draconisplusplus/include/rfl/TaggedUnion.hpp

150 lines
5 KiB
C++
Raw Normal View History

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