#ifndef RFL_TAGGEDUNION_HPP_ #define RFL_TAGGEDUNION_HPP_ #include #include "define_literal.hpp" #include "internal/Getter.hpp" #include "internal/StringLiteral.hpp" #include "internal/tag_t.hpp" namespace rfl { // https://serde.rs/enum-representations.html template struct TaggedUnion { static constexpr internal::StringLiteral discrimininator_ = _discriminator; /// The type of the underlying variant. using VariantType = std::variant; /// A literal containing all the tags that are possible using PossibleTags = define_literal_t...>; TaggedUnion(const VariantType& _variant) : variant_(_variant) {} TaggedUnion(VariantType&& _variant) noexcept : variant_(std::move(_variant)) {} TaggedUnion(const TaggedUnion<_discriminator, Ts...>& _tagged_union) = default; TaggedUnion(TaggedUnion<_discriminator, Ts...>&& _tagged_union) noexcept = default; template , bool>::type = true> TaggedUnion(const T& _t) : variant_(_t) {} template , bool>::type = true> TaggedUnion(T&& _t) noexcept : variant_(std::forward(_t)) {} ~TaggedUnion() = default; /// Assigns the underlying object. TaggedUnion<_discriminator, Ts...>& operator=(const VariantType& _variant) { variant_ = _variant; return *this; } /// Assigns the underlying object. TaggedUnion<_discriminator, Ts...>& operator=(VariantType&& _variant) { variant_ = std::move(_variant); return *this; } /// Assigns the underlying object. template , bool>::type = true> TaggedUnion<_discriminator, Ts...>& operator=(T&& _variant) { variant_ = std::forward(_variant); return *this; } /// Assigns the underlying object. template , bool>::type = true> TaggedUnion<_discriminator, Ts...>& operator=(const T& _variant) { variant_ = _variant; return *this; } /// Assigns the underlying object. TaggedUnion<_discriminator, Ts...>& operator=( const TaggedUnion<_discriminator, Ts...>& _other) = default; /// Assigns the underlying object. TaggedUnion<_discriminator, Ts...>& operator=( TaggedUnion<_discriminator, Ts...>&& _other) = default; /// Returns the underlying variant. VariantType& variant() { return variant_; } /// Returns the underlying variant. const VariantType& variant() const { return variant_; } static_assert(!PossibleTags::has_duplicates(), "Duplicate tags are not allowed inside tagged unions."); /// The underlying variant - a TaggedUnion is a thin wrapper /// around a variant that is mainly used for parsing. VariantType variant_; }; namespace internal { template struct Getter> { public: /// Retrieves the indicated value from the tuple. template static inline auto& get( TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) { return Getter>::template get<_index>( _tu.variant_); } /// Gets a field by name. template static inline auto& get( TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) { return Getter>::template get<_field_name>( _tu.variant_); } /// Gets a field by the field type. template static inline auto& get( TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) { return Getter>::template get( _tu.variant_); } /// Retrieves the indicated value from the tuple. template static inline const auto& get_const( const TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) { return Getter>::template get_const<_index>( _tu.variant_); } /// Gets a field by name. template static inline const auto& get_const( const TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) { return Getter>::template get_const< _field_name>(_tu.variant_); } /// Gets a field by the field type. template static inline const auto& get_const( const TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) { return Getter>::template get_const( _tu.variant_); } }; } // namespace internal } // namespace rfl #endif // RFL_TAGGEDUNION_HPP_