Browse Source

LibGUI: Make GUI::Variant an actual Variant

Previously this had its own massive tagged union implementation with
some POD types to represent non-POD types that could be put in the
variant; implement it via a Variant and get rid of the manual
pointer/ref handling.

This commit does not change any semantics on the type, just the
underlying implementation (and removes an unused ::clear() method).
Ali Mohammad Pur 3 years ago
parent
commit
7a02d33cd5
2 changed files with 195 additions and 769 deletions
  1. 57 499
      Userland/Libraries/LibGUI/Variant.cpp
  2. 138 270
      Userland/Libraries/LibGUI/Variant.h

+ 57 - 499
Userland/Libraries/LibGUI/Variant.cpp

@@ -1,544 +1,102 @@
 /*
  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  * Copyright (c) 2022, Filiph Sandström <filiph.sandstrom@filfatstudios.com>
+ * Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
-#include <AK/FlyString.h>
-#include <AK/JsonValue.h>
-#include <AK/RefPtr.h>
+#include <AK/NonnullRefPtr.h>
+#include <LibGUI/Icon.h>
 #include <LibGUI/Variant.h>
 
 namespace GUI {
 
-char const* to_string(Variant::Type type)
-{
-    switch (type) {
-    case Variant::Type::Invalid:
-        return "Invalid";
-    case Variant::Type::Bool:
-        return "Bool";
-    case Variant::Type::Int32:
-        return "Int32";
-    case Variant::Type::Int64:
-        return "Int64";
-    case Variant::Type::UnsignedInt32:
-        return "UnsignedInt32";
-    case Variant::Type::UnsignedInt64:
-        return "UnsignedInt64";
-    case Variant::Type::Float:
-        return "Float";
-    case Variant::Type::String:
-        return "String";
-    case Variant::Type::Bitmap:
-        return "Bitmap";
-    case Variant::Type::Color:
-        return "Color";
-    case Variant::Type::Icon:
-        return "Icon";
-    case Variant::Type::Point:
-        return "Point";
-    case Variant::Type::Size:
-        return "Size";
-    case Variant::Type::Rect:
-        return "Rect";
-    case Variant::Type::Font:
-        return "Font";
-    case Variant::Type::TextAlignment:
-        return "TextAlignment";
-    case Variant::Type::ColorRole:
-        return "ColorRole";
-    case Variant::Type::AlignmentRole:
-        return "AlignmentRole";
-    case Variant::Type::FlagRole:
-        return "FlagRole";
-    case Variant::Type::MetricRole:
-        return "MetricRole";
-    case Variant::Type::PathRole:
-        return "PathRole";
-    }
-    VERIFY_NOT_REACHED();
-}
-
-Variant::Variant()
-{
-    m_value.as_string = nullptr;
-}
-
-Variant::~Variant()
-{
-    clear();
-}
-
-void Variant::clear()
-{
-    switch (m_type) {
-    case Type::String:
-        AK::unref_if_not_null(m_value.as_string);
-        break;
-    case Type::Bitmap:
-        AK::unref_if_not_null(m_value.as_bitmap);
-        break;
-    case Type::Icon:
-        AK::unref_if_not_null(m_value.as_icon);
-        break;
-    default:
-        break;
-    }
-    m_type = Type::Invalid;
-    m_value.as_string = nullptr;
-}
-
-Variant::Variant(Gfx::TextAlignment value)
-    : m_type(Type::TextAlignment)
-{
-    m_value.as_text_alignment = value;
-}
-
-Variant::Variant(Gfx::ColorRole value)
-    : m_type(Type::ColorRole)
-{
-    m_value.as_color_role = value;
-}
-
-Variant::Variant(Gfx::AlignmentRole value)
-    : m_type(Type::AlignmentRole)
-{
-    m_value.as_alignment_role = value;
-}
-
-Variant::Variant(Gfx::FlagRole value)
-    : m_type(Type::FlagRole)
-{
-    m_value.as_flag_role = value;
-}
-
-Variant::Variant(Gfx::MetricRole value)
-    : m_type(Type::MetricRole)
-{
-    m_value.as_metric_role = value;
-}
-
-Variant::Variant(Gfx::PathRole value)
-    : m_type(Type::PathRole)
-{
-    m_value.as_path_role = value;
-}
-
-Variant::Variant(i32 value)
-    : m_type(Type::Int32)
-{
-    m_value.as_i32 = value;
-}
-
-Variant::Variant(i64 value)
-    : m_type(Type::Int64)
-{
-    m_value.as_i64 = value;
-}
-
-Variant::Variant(u32 value)
-    : m_type(Type::UnsignedInt32)
-{
-    m_value.as_u32 = value;
-}
-
-Variant::Variant(u64 value)
-    : m_type(Type::UnsignedInt64)
-{
-    m_value.as_u64 = value;
-}
-
-Variant::Variant(float value)
-    : m_type(Type::Float)
-{
-    m_value.as_float = value;
-}
-
-Variant::Variant(bool value)
-    : m_type(Type::Bool)
-{
-    m_value.as_bool = value;
-}
-
-Variant::Variant(char const* cstring)
-    : Variant(String(cstring))
-{
-}
-
-Variant::Variant(FlyString const& value)
-    : Variant(String(value.impl()))
-{
-}
-
-Variant::Variant(StringView value)
-    : Variant(value.to_string())
-{
-}
-
-Variant::Variant(String const& value)
-    : m_type(Type::String)
+Variant::Variant(JsonValue const& value)
 {
-    m_value.as_string = const_cast<StringImpl*>(value.impl());
-    AK::ref_if_not_null(m_value.as_string);
+    *this = value;
 }
 
-Variant::Variant(JsonValue const& value)
+Variant& Variant::operator=(JsonValue const& value)
 {
-    if (value.is_null()) {
-        m_value.as_string = nullptr;
-        return;
-    }
+    if (value.is_null())
+        return *this;
 
     if (value.is_i32()) {
-        m_type = Type::Int32;
-        m_value.as_i32 = value.as_i32();
-        return;
+        set(value.as_i32());
+        return *this;
     }
 
     if (value.is_u32()) {
-        m_type = Type::UnsignedInt32;
-        m_value.as_u32 = value.as_u32();
-        return;
+        set(value.as_u32());
+        return *this;
     }
 
     if (value.is_i64()) {
-        m_type = Type::Int64;
-        m_value.as_i64 = value.as_i64();
-        return;
+        set(value.as_i64());
+        return *this;
     }
 
     if (value.is_u64()) {
-        m_type = Type::UnsignedInt64;
-        m_value.as_u64 = value.to_u64();
-        return;
+        set(value.as_u64());
+        return *this;
     }
 
     if (value.is_string()) {
-        m_type = Type::String;
-        m_value.as_string = value.as_string().impl();
-        m_value.as_string->ref();
-        return;
+        set(value.as_string());
+        return *this;
     }
 
     if (value.is_bool()) {
-        m_type = Type::Bool;
-        m_value.as_bool = value.as_bool();
-        return;
+        set(Detail::Boolean { value.as_bool() });
+        return *this;
     }
 
     VERIFY_NOT_REACHED();
 }
 
-Variant::Variant(Gfx::Bitmap const& value)
-    : m_type(Type::Bitmap)
-{
-    m_value.as_bitmap = const_cast<Gfx::Bitmap*>(&value);
-    AK::ref_if_not_null(m_value.as_bitmap);
-}
-
-Variant::Variant(const GUI::Icon& value)
-    : m_type(Type::Icon)
-{
-    m_value.as_icon = &const_cast<GUI::IconImpl&>(value.impl());
-    AK::ref_if_not_null(m_value.as_icon);
-}
-
-Variant::Variant(Gfx::Font const& value)
-    : m_type(Type::Font)
-{
-    m_value.as_font = &const_cast<Gfx::Font&>(value);
-    AK::ref_if_not_null(m_value.as_font);
-}
-
-Variant::Variant(Color color)
-    : m_type(Type::Color)
-{
-    m_value.as_color = color.value();
-}
-
-Variant::Variant(Gfx::IntPoint const& point)
-    : m_type(Type::Point)
-{
-    m_value.as_point = { point.x(), point.y() };
-}
-
-Variant::Variant(Gfx::IntSize const& size)
-    : m_type(Type::Size)
-{
-    m_value.as_size = { size.width(), size.height() };
-}
-
-Variant::Variant(Gfx::IntRect const& rect)
-    : m_type(Type::Rect)
-{
-    m_value.as_rect = (RawRect const&)rect;
-}
-
-Variant& Variant::operator=(Variant const& other)
-{
-    if (&other == this)
-        return *this;
-    clear();
-    copy_from(other);
-    return *this;
-}
-
-Variant& Variant::operator=(Variant&& other)
-{
-    if (&other == this)
-        return *this;
-    clear();
-    move_from(move(other));
-    return *this;
-}
-
-Variant::Variant(Variant const& other)
-{
-    copy_from(other);
-}
-
-void Variant::move_from(Variant&& other)
-{
-    m_type = other.m_type;
-    m_value = other.m_value;
-    other.m_type = Type::Invalid;
-    other.m_value.as_string = nullptr;
-}
-
-void Variant::copy_from(Variant const& other)
-{
-    VERIFY(!is_valid());
-    m_type = other.m_type;
-    switch (m_type) {
-    case Type::Bool:
-        m_value.as_bool = other.m_value.as_bool;
-        break;
-    case Type::Int32:
-        m_value.as_i32 = other.m_value.as_i32;
-        break;
-    case Type::Int64:
-        m_value.as_i64 = other.m_value.as_i64;
-        break;
-    case Type::UnsignedInt32:
-        m_value.as_u32 = other.m_value.as_u32;
-        break;
-    case Type::UnsignedInt64:
-        m_value.as_u64 = other.m_value.as_u64;
-        break;
-    case Type::Float:
-        m_value.as_float = other.m_value.as_float;
-        break;
-    case Type::String:
-        m_value.as_string = other.m_value.as_string;
-        AK::ref_if_not_null(m_value.as_bitmap);
-        break;
-    case Type::Bitmap:
-        m_value.as_bitmap = other.m_value.as_bitmap;
-        AK::ref_if_not_null(m_value.as_bitmap);
-        break;
-    case Type::Icon:
-        m_value.as_icon = other.m_value.as_icon;
-        AK::ref_if_not_null(m_value.as_icon);
-        break;
-    case Type::Font:
-        m_value.as_font = other.m_value.as_font;
-        AK::ref_if_not_null(m_value.as_font);
-        break;
-    case Type::Color:
-        m_value.as_color = other.m_value.as_color;
-        break;
-    case Type::Point:
-        m_value.as_point = other.m_value.as_point;
-        break;
-    case Type::Size:
-        m_value.as_size = other.m_value.as_size;
-        break;
-    case Type::Rect:
-        m_value.as_rect = other.m_value.as_rect;
-        break;
-    case Type::TextAlignment:
-        m_value.as_text_alignment = other.m_value.as_text_alignment;
-        break;
-    case Type::ColorRole:
-        m_value.as_color_role = other.m_value.as_color_role;
-        break;
-    case Type::AlignmentRole:
-        m_value.as_alignment_role = other.m_value.as_alignment_role;
-        break;
-    case Type::FlagRole:
-        m_value.as_flag_role = other.m_value.as_flag_role;
-        break;
-    case Type::MetricRole:
-        m_value.as_metric_role = other.m_value.as_metric_role;
-        break;
-    case Type::PathRole:
-        m_value.as_path_role = other.m_value.as_path_role;
-        break;
-    case Type::Invalid:
-        break;
-    }
-}
-
 bool Variant::operator==(Variant const& other) const
 {
-    if (m_type != other.m_type)
-        return to_string() == other.to_string();
-    switch (m_type) {
-    case Type::Bool:
-        return as_bool() == other.as_bool();
-    case Type::Int32:
-        return as_i32() == other.as_i32();
-    case Type::Int64:
-        return as_i64() == other.as_i64();
-    case Type::UnsignedInt32:
-        return as_u32() == other.as_u32();
-    case Type::UnsignedInt64:
-        return as_u64() == other.as_u64();
-    case Type::Float:
-        return as_float() == other.as_float();
-    case Type::String:
-        return as_string() == other.as_string();
-    case Type::Bitmap:
-        return m_value.as_bitmap == other.m_value.as_bitmap;
-    case Type::Icon:
-        return m_value.as_icon == other.m_value.as_icon;
-    case Type::Color:
-        return m_value.as_color == other.m_value.as_color;
-    case Type::Point:
-        return as_point() == other.as_point();
-    case Type::Size:
-        return as_size() == other.as_size();
-    case Type::Rect:
-        return as_rect() == other.as_rect();
-    case Type::Font:
-        return &as_font() == &other.as_font();
-    case Type::TextAlignment:
-        return m_value.as_text_alignment == other.m_value.as_text_alignment;
-    case Type::ColorRole:
-        return m_value.as_color_role == other.m_value.as_color_role;
-    case Type::AlignmentRole:
-        return m_value.as_alignment_role == other.m_value.as_alignment_role;
-    case Type::FlagRole:
-        return m_value.as_flag_role == other.m_value.as_flag_role;
-    case Type::MetricRole:
-        return m_value.as_metric_role == other.m_value.as_metric_role;
-    case Type::PathRole:
-        return m_value.as_path_role == other.m_value.as_path_role;
-    case Type::Invalid:
-        return true;
-    }
-    VERIFY_NOT_REACHED();
+    return visit([&]<typename T>(T const& own_value) {
+        return other.visit(
+            [&](T const& other_value) -> bool {
+                if constexpr (requires { own_value == other_value; })
+                    return own_value == other_value;
+                else if constexpr (IsSame<T, GUI::Icon>)
+                    return &own_value.impl() == &other_value.impl();
+                // FIXME: Figure out if this silly behaviour is actually used anywhere, then get rid of it.
+                else
+                    return to_string() == other.to_string();
+            },
+            [&](auto const&) {
+                // FIXME: Figure out if this silly behaviour is actually used anywhere, then get rid of it.
+                return to_string() == other.to_string();
+            });
+    });
 }
 
 bool Variant::operator<(Variant const& other) const
 {
-    if (m_type != other.m_type)
-        return to_string() < other.to_string();
-    switch (m_type) {
-    case Type::Bool:
-        return as_bool() < other.as_bool();
-    case Type::Int32:
-        return as_i32() < other.as_i32();
-    case Type::Int64:
-        return as_i64() < other.as_i64();
-    case Type::UnsignedInt32:
-        return as_u32() < other.as_u32();
-    case Type::UnsignedInt64:
-        return as_u64() < other.as_u64();
-    case Type::Float:
-        return as_float() < other.as_float();
-    case Type::String:
-        return as_string() < other.as_string();
-    case Type::Bitmap:
-        // FIXME: Maybe compare bitmaps somehow differently?
-        return m_value.as_bitmap < other.m_value.as_bitmap;
-    case Type::Icon:
-        // FIXME: Maybe compare icons somehow differently?
-        return m_value.as_icon < other.m_value.as_icon;
-    case Type::Color:
-        return m_value.as_color < other.m_value.as_color;
-    case Type::Point:
-    case Type::Size:
-    case Type::Rect:
-    case Type::Font:
-    case Type::TextAlignment:
-    case Type::ColorRole:
-    case Type::AlignmentRole:
-    case Type::FlagRole:
-    case Type::MetricRole:
-    case Type::PathRole:
-        // FIXME: Figure out how to compare these.
-        VERIFY_NOT_REACHED();
-    case Type::Invalid:
-        break;
-    }
-    VERIFY_NOT_REACHED();
+    return visit([&]<typename T>(T const& own_value) {
+        return other.visit(
+            [&](T const& other_value) -> bool {
+                // FIXME: Maybe compare icons somehow differently?
+                if constexpr (IsSame<T, GUI::Icon>)
+                    return &own_value.impl() < &other_value.impl();
+                // FIXME: Maybe compare bitmaps somehow differently?
+                else if constexpr (IsSame<T, NonnullRefPtr<Gfx::Bitmap>>)
+                    return own_value.ptr() < other_value.ptr();
+                else if constexpr (IsSame<T, NonnullRefPtr<Gfx::Font>>)
+                    return own_value->name() < other_value->name();
+                else if constexpr (requires { own_value < other_value; })
+                    return own_value < other_value;
+                // FIXME: Figure out if this silly behaviour is actually used anywhere, then get rid of it.
+                else
+                    return to_string() < other.to_string();
+            },
+            [&](auto const&) -> bool {
+                return to_string() < other.to_string(); // FIXME: Figure out if this silly behaviour is actually used anywhere, then get rid of it.
+            });
+    });
 }
-
-String Variant::to_string() const
-{
-    switch (m_type) {
-    case Type::Bool:
-        return as_bool() ? "true" : "false";
-    case Type::Int32:
-        return String::number(as_i32());
-    case Type::Int64:
-        return String::number(as_i64());
-    case Type::UnsignedInt32:
-        return String::number(as_u32());
-    case Type::UnsignedInt64:
-        return String::number(as_u64());
-    case Type::Float:
-        return String::formatted("{:.2}", as_float());
-    case Type::String:
-        return as_string();
-    case Type::Bitmap:
-        return "[Gfx::Bitmap]";
-    case Type::Icon:
-        return "[GUI::Icon]";
-    case Type::Color:
-        return as_color().to_string();
-    case Type::Point:
-        return as_point().to_string();
-    case Type::Size:
-        return as_size().to_string();
-    case Type::Rect:
-        return as_rect().to_string();
-    case Type::Font:
-        return String::formatted("[Font: {}]", as_font().name());
-    case Type::TextAlignment: {
-        switch (m_value.as_text_alignment) {
-        case Gfx::TextAlignment::Center:
-            return "Gfx::TextAlignment::Center";
-        case Gfx::TextAlignment::CenterLeft:
-            return "Gfx::TextAlignment::CenterLeft";
-        case Gfx::TextAlignment::CenterRight:
-            return "Gfx::TextAlignment::CenterRight";
-        case Gfx::TextAlignment::TopLeft:
-            return "Gfx::TextAlignment::TopLeft";
-        case Gfx::TextAlignment::TopRight:
-            return "Gfx::TextAlignment::TopRight";
-        default:
-            VERIFY_NOT_REACHED();
-        }
-        return "";
-    }
-    case Type::ColorRole:
-        return String::formatted("Gfx::ColorRole::{}", Gfx::to_string(m_value.as_color_role));
-    case Type::AlignmentRole:
-        return String::formatted("Gfx::AlignmentRole::{}", Gfx::to_string(m_value.as_alignment_role));
-    case Type::FlagRole:
-        return String::formatted("Gfx::FlagRole::{}", Gfx::to_string(m_value.as_flag_role));
-    case Type::MetricRole:
-        return String::formatted("Gfx::MetricRole::{}", Gfx::to_string(m_value.as_metric_role));
-    case Type::PathRole:
-        return String::formatted("Gfx::PathRole::{}", Gfx::to_string(m_value.as_path_role));
-    case Type::Invalid:
-        return "[null]";
-    }
-    VERIFY_NOT_REACHED();
-}
-
 }

+ 138 - 270
Userland/Libraries/LibGUI/Variant.h

@@ -1,12 +1,14 @@
 /*
  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  * Copyright (c) 2022, Filiph Sandström <filiph.sandstrom@filfatstudios.com>
+ * Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
 #pragma once
 
+#include <AK/Concepts.h>
 #include <AK/String.h>
 #include <LibGUI/Icon.h>
 #include <LibGfx/Bitmap.h>
@@ -15,339 +17,205 @@
 
 namespace GUI {
 
-class Variant {
-public:
-    Variant();
-    Variant(bool);
-    Variant(float);
-    Variant(i32);
-    Variant(i64);
-    Variant(u32);
-    Variant(u64);
-    Variant(char const*);
-    Variant(StringView);
-    Variant(String const&);
-    Variant(FlyString const&);
-    Variant(Gfx::Bitmap const&);
-    Variant(const GUI::Icon&);
-    Variant(Gfx::IntPoint const&);
-    Variant(Gfx::IntSize const&);
-    Variant(Gfx::IntRect const&);
-    Variant(Gfx::Font const&);
-    Variant(const Gfx::TextAlignment);
-    Variant(const Gfx::ColorRole);
-    Variant(const Gfx::AlignmentRole);
-    Variant(const Gfx::FlagRole);
-    Variant(const Gfx::MetricRole);
-    Variant(const Gfx::PathRole);
-    Variant(JsonValue const&);
-    Variant(Color);
-
-    Variant(Variant const&);
-    Variant& operator=(Variant const&);
-
-    Variant(Variant&&) = delete;
-    Variant& operator=(Variant&&);
-
-    void clear();
-    ~Variant();
-
-    enum class Type {
-        Invalid,
-        Bool,
-        Int32,
-        Int64,
-        UnsignedInt32,
-        UnsignedInt64,
-        Float,
-        String,
-        Bitmap,
-        Color,
-        Icon,
-        Point,
-        Size,
-        Rect,
-        Font,
-        TextAlignment,
-        ColorRole,
-        AlignmentRole,
-        FlagRole,
-        MetricRole,
-        PathRole,
-    };
-
-    bool is_valid() const { return m_type != Type::Invalid; }
-    bool is_bool() const { return m_type == Type::Bool; }
-    bool is_i32() const { return m_type == Type::Int32; }
-    bool is_i64() const { return m_type == Type::Int64; }
-    bool is_u32() const { return m_type == Type::UnsignedInt32; }
-    bool is_u64() const { return m_type == Type::UnsignedInt64; }
-    bool is_float() const { return m_type == Type::Float; }
-    bool is_string() const { return m_type == Type::String; }
-    bool is_bitmap() const { return m_type == Type::Bitmap; }
-    bool is_color() const { return m_type == Type::Color; }
-    bool is_icon() const { return m_type == Type::Icon; }
-    bool is_point() const { return m_type == Type::Point; }
-    bool is_size() const { return m_type == Type::Size; }
-    bool is_rect() const { return m_type == Type::Rect; }
-    bool is_font() const { return m_type == Type::Font; }
-    bool is_text_alignment() const { return m_type == Type::TextAlignment; }
-    bool is_color_role() const { return m_type == Type::ColorRole; }
-    bool is_alignment_role() const { return m_type == Type::AlignmentRole; }
-    bool is_flag_role() const { return m_type == Type::FlagRole; }
-    bool is_metric_role() const { return m_type == Type::MetricRole; }
-    bool is_path_role() const { return m_type == Type::PathRole; }
-    Type type() const { return m_type; }
-
-    bool as_bool() const
-    {
-        VERIFY(type() == Type::Bool);
-        return m_value.as_bool;
-    }
-
-    bool to_bool() const
-    {
-        if (type() == Type::Bool)
-            return as_bool();
-        if (type() == Type::String)
-            return !!m_value.as_string;
-        if (type() == Type::Int32)
-            return m_value.as_i32 != 0;
-        if (type() == Type::Int64)
-            return m_value.as_i64 != 0;
-        if (type() == Type::UnsignedInt32)
-            return m_value.as_u32 != 0;
-        if (type() == Type::UnsignedInt64)
-            return m_value.as_u64 != 0;
-        if (type() == Type::Rect)
-            return !as_rect().is_null();
-        if (type() == Type::Size)
-            return !as_size().is_null();
-        if (type() == Type::Point)
-            return !as_point().is_null();
-        return is_valid();
-    }
-
-    int as_i32() const
-    {
-        VERIFY(type() == Type::Int32);
-        return m_value.as_i32;
-    }
+namespace Detail {
+struct Boolean {
+    bool value;
+};
+using VariantUnderlyingType = AK::Variant<Empty, Boolean, float, i32, i64, u32, u64, String, Color, Gfx::IntPoint, Gfx::IntSize, Gfx::IntRect, Gfx::TextAlignment, Gfx::ColorRole, Gfx::AlignmentRole, Gfx::FlagRole, Gfx::MetricRole, Gfx::PathRole, NonnullRefPtr<Gfx::Bitmap>, NonnullRefPtr<Gfx::Font>, GUI::Icon>;
+}
 
-    int as_i64() const
-    {
-        VERIFY(type() == Type::Int64);
-        return m_value.as_i64;
-    }
+class Variant : public Detail::VariantUnderlyingType {
+public:
+    using Detail::VariantUnderlyingType::Variant;
+    using Detail::VariantUnderlyingType::operator=;
 
-    u32 as_u32() const
+    Variant(JsonValue const&);
+    Variant& operator=(JsonValue const&);
+    Variant(bool v)
+        : Variant(Detail::Boolean { v })
     {
-        VERIFY(type() == Type::UnsignedInt32);
-        return m_value.as_u32;
     }
-
-    u64 as_u64() const
+    Variant& operator=(bool v)
     {
-        VERIFY(type() == Type::UnsignedInt64);
-        return m_value.as_u64;
+        set(Detail::Boolean { v });
+        return *this;
     }
 
     template<typename T>
-    T to_integer() const
+    Variant(T&& value) requires(IsConstructible<String, T>)
+        : Variant(String(forward<T>(value)))
     {
-        if (is_i32())
-            return as_i32();
-        if (is_i64())
-            return as_i64();
-        if (is_bool())
-            return as_bool() ? 1 : 0;
-        if (is_float())
-            return (int)as_float();
-        if (is_u32()) {
-            VERIFY(as_u32() <= INT32_MAX);
-            return static_cast<i32>(as_u32());
-        }
-        if (is_u64()) {
-            VERIFY(as_u64() <= INT64_MAX);
-            return static_cast<i64>(as_u64());
-        }
-        if (is_string())
-            return as_string().to_int().value_or(0);
-        return 0;
     }
-
-    i32 to_i32() const
-    {
-        return to_integer<i32>();
-    }
-
-    i64 to_i64() const
+    template<typename T>
+    Variant& operator=(T&& v) requires(IsConstructible<String, T>)
     {
-        return to_integer<i64>();
+        set(String(v));
+        return *this;
     }
 
-    float as_float() const
+    template<OneOfIgnoringCV<Gfx::Bitmap, Gfx::Font> T>
+    Variant(T const& value)
+        : Variant(NonnullRefPtr<RemoveCV<T>>(value))
     {
-        VERIFY(type() == Type::Float);
-        return m_value.as_float;
     }
-
-    float as_float_or(float fallback) const
+    template<OneOfIgnoringCV<Gfx::Bitmap, Gfx::Font> T>
+    Variant& operator=(T&& value)
     {
-        if (is_float())
-            return as_float();
-        return fallback;
+        set(NonnullRefPtr<RemoveCV<T>>(forward<T>(value)));
+        return *this;
     }
 
-    Gfx::IntPoint as_point() const
-    {
-        return { m_value.as_point.x, m_value.as_point.y };
-    }
+    ~Variant() = default;
 
-    Gfx::IntSize as_size() const
-    {
-        return { m_value.as_size.width, m_value.as_size.height };
-    }
+    bool is_valid() const { return !has<Empty>(); }
+    bool is_bool() const { return has<Detail::Boolean>(); }
+    bool is_i32() const { return has<i32>(); }
+    bool is_i64() const { return has<i64>(); }
+    bool is_u32() const { return has<u32>(); }
+    bool is_u64() const { return has<u64>(); }
+    bool is_float() const { return has<float>(); }
+    bool is_string() const { return has<String>(); }
+    bool is_bitmap() const { return has<NonnullRefPtr<Gfx::Bitmap>>(); }
+    bool is_color() const { return has<Color>(); }
+    bool is_icon() const { return has<GUI::Icon>(); }
+    bool is_point() const { return has<Gfx::IntPoint>(); }
+    bool is_size() const { return has<Gfx::IntSize>(); }
+    bool is_rect() const { return has<Gfx::IntRect>(); }
+    bool is_font() const { return has<NonnullRefPtr<Gfx::Font>>(); }
+    bool is_text_alignment() const { return has<Gfx::TextAlignment>(); }
+    bool is_color_role() const { return has<Gfx::ColorRole>(); }
+    bool is_alignment_role() const { return has<Gfx::AlignmentRole>(); }
+    bool is_flag_role() const { return has<Gfx::FlagRole>(); }
+    bool is_metric_role() const { return has<Gfx::MetricRole>(); }
+    bool is_path_role() const { return has<Gfx::PathRole>(); }
 
-    Gfx::IntRect as_rect() const
-    {
-        return { as_point(), as_size() };
-    }
+    bool as_bool() const { return get<Detail::Boolean>().value; }
 
-    String as_string() const
+    bool to_bool() const
     {
-        VERIFY(type() == Type::String);
-        return m_value.as_string;
+        return visit(
+            [](Empty) { return false; },
+            [](Detail::Boolean v) { return v.value; },
+            [](String const& v) { return !v.is_null(); },
+            [](Integral auto v) { return v != 0; },
+            [](OneOf<Gfx::IntRect, Gfx::IntPoint, Gfx::IntSize> auto const& v) { return !v.is_null(); },
+            [](Enum auto const&) { return true; },
+            [](OneOf<float, String, Color, NonnullRefPtr<Gfx::Font>, NonnullRefPtr<Gfx::Bitmap>, GUI::Icon> auto const&) { return true; });
     }
 
-    Gfx::Bitmap const& as_bitmap() const
-    {
-        VERIFY(type() == Type::Bitmap);
-        return *m_value.as_bitmap;
-    }
+    i32 as_i32() const { return get<i32>(); }
+    i64 as_i64() const { return get<i64>(); }
+    u32 as_u32() const { return get<u32>(); }
+    u64 as_u64() const { return get<u64>(); }
 
-    GUI::Icon as_icon() const
+    template<Integral T>
+    T to_integer() const
     {
-        VERIFY(type() == Type::Icon);
-        return GUI::Icon(*m_value.as_icon);
-    }
+        return visit(
+            [](Empty) -> T { return 0; },
+            [](Integral auto v) { return static_cast<T>(v); },
+            [](FloatingPoint auto v) { return (T)v; },
+            [](Detail::Boolean v) -> T { return v.value ? 1 : 0; },
+            [](String const& v) {
+                if constexpr (IsUnsigned<T>)
+                    return v.to_uint<T>().value_or(0u);
+                else
+                    return v.to_int<T>().value_or(0);
+            },
+            [](Enum auto const&) -> T { return 0; },
+            [](OneOf<Gfx::IntPoint, Gfx::IntRect, Gfx::IntSize, Color, NonnullRefPtr<Gfx::Font>, NonnullRefPtr<Gfx::Bitmap>, GUI::Icon> auto const&) -> T { return 0; });
+    }
+
+    i32 to_i32() const { return to_integer<i32>(); }
+    i64 to_i64() const { return to_integer<i64>(); }
+    float as_float() const { return get<float>(); }
 
-    Color as_color() const
+    float as_float_or(float fallback) const
     {
-        VERIFY(type() == Type::Color);
-        return Color::from_argb(m_value.as_color);
+        if (auto const* p = get_pointer<float>())
+            return *p;
+        return fallback;
     }
 
-    Gfx::Font const& as_font() const
-    {
-        VERIFY(type() == Type::Font);
-        return *m_value.as_font;
-    }
+    Gfx::IntPoint as_point() const { return get<Gfx::IntPoint>(); }
+    Gfx::IntSize as_size() const { return get<Gfx::IntSize>(); }
+    Gfx::IntRect as_rect() const { return get<Gfx::IntRect>(); }
+    String as_string() const { return get<String>(); }
+    Gfx::Bitmap const& as_bitmap() const { return *get<NonnullRefPtr<Gfx::Bitmap>>(); }
+    GUI::Icon as_icon() const { return get<GUI::Icon>(); }
+    Color as_color() const { return get<Color>(); }
+    Gfx::Font const& as_font() const { return *get<NonnullRefPtr<Gfx::Font>>(); }
 
     Gfx::TextAlignment to_text_alignment(Gfx::TextAlignment default_value) const
     {
-        if (type() != Type::TextAlignment)
-            return default_value;
-        return m_value.as_text_alignment;
+        if (auto const* p = get_pointer<Gfx::TextAlignment>())
+            return *p;
+        return default_value;
     }
 
     Gfx::ColorRole to_color_role() const
     {
-        if (type() != Type::ColorRole)
-            return Gfx::ColorRole::NoRole;
-        return m_value.as_color_role;
+        if (auto const* p = get_pointer<Gfx::ColorRole>())
+            return *p;
+        return Gfx::ColorRole::NoRole;
     }
 
     Gfx::AlignmentRole to_alignment_role() const
     {
-        if (type() != Type::AlignmentRole)
-            return Gfx::AlignmentRole::NoRole;
-        return m_value.as_alignment_role;
+        if (auto const* p = get_pointer<Gfx::AlignmentRole>())
+            return *p;
+        return Gfx::AlignmentRole::NoRole;
     }
 
     Gfx::FlagRole to_flag_role() const
     {
-        if (type() != Type::FlagRole)
-            return Gfx::FlagRole::NoRole;
-        return m_value.as_flag_role;
+        if (auto const* p = get_pointer<Gfx::FlagRole>())
+            return *p;
+        return Gfx::FlagRole::NoRole;
     }
 
     Gfx::MetricRole to_metric_role() const
     {
-        if (type() != Type::MetricRole)
-            return Gfx::MetricRole::NoRole;
-        return m_value.as_metric_role;
+        if (auto const* p = get_pointer<Gfx::MetricRole>())
+            return *p;
+        return Gfx::MetricRole::NoRole;
     }
 
     Gfx::PathRole to_path_role() const
     {
-        if (type() != Type::PathRole)
-            return Gfx::PathRole::NoRole;
-        return m_value.as_path_role;
+        if (auto const* p = get_pointer<Gfx::PathRole>())
+            return *p;
+        return Gfx::PathRole::NoRole;
     }
 
     Color to_color(Color default_value = {}) const
     {
-        if (type() == Type::Color)
-            return as_color();
-        if (type() == Type::String) {
-            auto color = Color::from_string(as_string());
-            if (color.has_value())
-                return color.value();
-        }
+        if (auto const* p = get_pointer<Color>())
+            return *p;
+        if (auto const* p = get_pointer<String>())
+            return Color::from_string(*p).value_or(default_value);
         return default_value;
     }
 
-    String to_string() const;
+    String to_string() const
+    {
+        return visit(
+            [](Empty) -> String { return "[null]"; },
+            [](Gfx::TextAlignment v) { return String::formatted("Gfx::TextAlignment::{}", Gfx::to_string(v)); },
+            [](Gfx::ColorRole v) { return String::formatted("Gfx::ColorRole::{}", Gfx::to_string(v)); },
+            [](Gfx::AlignmentRole v) { return String::formatted("Gfx::AlignmentRole::{}", Gfx::to_string(v)); },
+            [](Gfx::FlagRole v) { return String::formatted("Gfx::FlagRole::{}", Gfx::to_string(v)); },
+            [](Gfx::MetricRole v) { return String::formatted("Gfx::MetricRole::{}", Gfx::to_string(v)); },
+            [](Gfx::PathRole v) { return String::formatted("Gfx::PathRole::{}", Gfx::to_string(v)); },
+            [](NonnullRefPtr<Gfx::Font> const& font) { return String::formatted("[Font: {}]", font->name()); },
+            [](NonnullRefPtr<Gfx::Bitmap> const&) -> String { return "[Gfx::Bitmap]"; },
+            [](GUI::Icon const&) -> String { return "[GUI::Icon]"; },
+            [](Detail::Boolean v) { return String::formatted("{}", v.value); },
+            [](auto const& v) { return String::formatted("{}", v); });
+    }
 
     bool operator==(Variant const&) const;
     bool operator<(Variant const&) const;
-
-private:
-    void copy_from(Variant const&);
-    void move_from(Variant&&);
-
-    struct RawPoint {
-        int x;
-        int y;
-    };
-
-    struct RawSize {
-        int width;
-        int height;
-    };
-
-    struct RawRect {
-        RawPoint location;
-        RawSize size;
-    };
-
-    union {
-        StringImpl* as_string;
-        Gfx::Bitmap* as_bitmap;
-        GUI::IconImpl* as_icon;
-        Gfx::Font* as_font;
-        bool as_bool;
-        i32 as_i32;
-        i64 as_i64;
-        u32 as_u32;
-        u64 as_u64;
-        float as_float;
-        Gfx::ARGB32 as_color;
-        Gfx::TextAlignment as_text_alignment;
-        Gfx::ColorRole as_color_role;
-        Gfx::AlignmentRole as_alignment_role;
-        Gfx::FlagRole as_flag_role;
-        Gfx::MetricRole as_metric_role;
-        Gfx::PathRole as_path_role;
-        RawPoint as_point;
-        RawSize as_size;
-        RawRect as_rect;
-    } m_value;
-
-    Type m_type { Type::Invalid };
 };
 
-char const* to_string(Variant::Type);
-
 }