#ifndef RFL_GENERIC_HPP_ #define RFL_GENERIC_HPP_ #include #include #include #include #include #include #include "Object.hpp" #include "Result.hpp" #include "Variant.hpp" #include "common.hpp" namespace rfl { class RFL_API Generic { public: constexpr static std::nullopt_t Null = std::nullopt; using Array = std::vector; using Object = rfl::Object; using VariantType = std::variant; using ReflectionType = std::optional< std::variant>; Generic(); Generic(Generic&& _other) noexcept; Generic(const Generic& _other); Generic(const VariantType& _value); Generic(VariantType&& _value) noexcept; Generic(const ReflectionType& _value); template , bool>::type = true> Generic(const T& _value) { value_ = _value; } template , bool>::type = true> Generic(T&& _value) noexcept : value_(std::forward(_value)) {} ~Generic(); /// Returns the underlying object. const VariantType& get() const { return value_; } /// Whether the object contains the null value. bool is_null() const noexcept; /// Assigns the underlying object. Generic& operator=(const VariantType& _value); /// Assigns the underlying object. Generic& operator=(VariantType&& _value) noexcept; /// Assigns the underlying object. template , bool>::type = true> auto& operator=(const T& _value) { using Type = std::remove_cvref_t; if constexpr (std::is_same_v) { value_.emplace<0>(_value); } else if constexpr (std::is_integral_v) { value_.emplace<1>(static_cast(_value)); } else if constexpr (std::is_floating_point_v) { value_.emplace<2>(static_cast(_value)); } else { value_ = _value; } return *this; } /// Assigns the underlying object. Generic& operator=(const Generic& _other); /// Assigns the underlying object. Generic& operator=(Generic&& _other); /// Returns the underlying object, necessary for the serialization to work. ReflectionType reflection() const noexcept; /// Casts the underlying value to an rfl::Generic::Array or returns an /// rfl::Error, if the underlying value is not an rfl::Generic::Array. Result to_array() const noexcept { return std::visit( [](auto _v) -> Result { using V = std::remove_cvref_t; if constexpr (std::is_same_v) { return _v; } else { return error( "rfl::Generic: Could not cast the underlying value to an " "rfl::Generic::Array."); } }, value_); } /// Casts the underlying value to a boolean or returns an rfl::Error, if the /// underlying value is not a boolean. Result to_bool() const noexcept { return std::visit( [](auto _v) -> Result { using V = std::remove_cvref_t; if constexpr (std::is_same_v) { return _v; } else { return error( "rfl::Generic: Could not cast the underlying value to a " "boolean."); } }, value_); } /// Casts the underlying value to a double or returns an rfl::Error, if the /// underlying value is not a number or the conversion would result in loss of /// precision. Result to_double() const noexcept { return std::visit( [](auto _v) -> Result { using V = std::remove_cvref_t; if constexpr (std::is_same_v) { return _v; } else if constexpr (std::is_same_v) { auto _d = static_cast(_v); if (static_cast(_d) == _v) { return _d; } else { return error( "rfl::Generic: Could not cast the underlying value to a " "double without loss of precision."); } } else { return error( "rfl::Generic: Could not cast the underlying value to a " "double."); } }, value_); } /// Casts the underlying value to an integer or returns an rfl::Error, if the /// underlying value is not an integer. Result to_int() const noexcept { return std::visit( [](auto _v) -> Result { using V = std::remove_cvref_t; if constexpr (std::is_same_v) { return static_cast(_v); } else { return error( "rfl::Generic: Could not cast the underlying value to an " "integer."); } }, value_); } /// Casts the underlying value to an int64 or returns an rfl::Error, if the /// underlying value is not an integer. Result to_int64() const noexcept { return std::visit( [](auto _v) -> Result { using V = std::remove_cvref_t; if constexpr (std::is_same_v) { return _v; } else { return error( "rfl::Generic: Could not cast the underlying value to an " "int64."); } }, value_); } /// Casts the underlying value to an rfl::Generic::Object or returns an /// rfl::Error, if the underlying value is not an rfl::Generic::Object. Result to_object() const noexcept { return std::visit( [](auto _v) -> Result { using V = std::remove_cvref_t; if constexpr (std::is_same_v) { return _v; } else { return error( "rfl::Generic: Could not cast the underlying value to an " "rfl::Generic::Object."); } }, value_); } /// Casts the underlying value to rfl::Generic::Null or returns an /// rfl::Error, if the underlying value is not rfl::Generic::Null. Result to_null() const noexcept { return std::visit( [](auto _v) -> Result { using V = std::remove_cvref_t; if constexpr (std::is_same_v) { return _v; } else { return error( "rfl::Generic: Could not cast the underlying value to " "rfl::Generic::Null."); } }, value_); } /// Casts the underlying value to a string or returns an rfl::Error, if the /// underlying value is not a string. Result to_string() const noexcept { return std::visit( [](auto _v) -> Result { using V = std::remove_cvref_t; if constexpr (std::is_same_v) { return _v; } else { return error( "rfl::Generic: Could not cast the underlying value to a " "string."); } }, value_); } /// Returns the underlying variant. VariantType& variant() noexcept { return value_; }; /// Returns the underlying variant. const VariantType& variant() const noexcept { return value_; }; private: static VariantType from_reflection_type(const ReflectionType& _r) noexcept; private: VariantType value_; }; /// Casts the underlying value to an rfl::Generic::Array or returns an /// rfl::Error, if the underlying value is not an rfl::Generic::Array. inline Result to_array(const Generic& _g) noexcept { return _g.to_array(); } /// Casts the underlying value to a boolean or returns an rfl::Error, if the /// underlying value is not a boolean. inline Result to_bool(const Generic& _g) noexcept { return _g.to_bool(); } /// Casts the underlying value to a double or returns an rfl::Error, if the /// underlying value is not a double. inline Result to_double(const Generic& _g) noexcept { return _g.to_double(); } /// Casts the underlying value to an integer or returns an rfl::Error, if the /// underlying value is not an integer. inline Result to_int(const Generic& _g) noexcept { return _g.to_int(); } /// Casts the underlying value to an int64 or returns an rfl::Error, if the /// underlying value is not an integer. inline Result to_int64(const Generic& _g) noexcept { return _g.to_int64(); } /// Casts the underlying value to an rfl::Generic::Object or returns an /// rfl::Error, if the underlying value is not an rfl::Generic::Object. inline Result to_object(const Generic& _g) noexcept { return _g.to_object(); } /// Casts the underlying value to a double or returns an rfl::Error, if the /// underlying value is not a double. inline Result to_null(const Generic& _g) noexcept { return _g.to_null(); } /// Casts the underlying value to a string or returns an rfl::Error, if the /// underlying value is not a string. inline Result to_string(const Generic& _g) noexcept { return _g.to_string(); } } // namespace rfl #endif