tagval 0.2.0
Modern C++23 header-only library of tagged values (open/closed enumerations with metadata)
Loading...
Searching...
No Matches
base.hpp
Go to the documentation of this file.
1#pragma once
2
10
11#include <tagval/descriptor.hpp>
12#include <tagval/entry.hpp>
13#include <tagval/error.hpp>
14
15#include <commons/color.hpp>
16#include <commons/fixed_string.hpp>
17#include <commons/icon.hpp>
18
19#include <compare>
20#include <concepts>
21#include <expected>
22#include <optional>
23#include <span>
24#include <string_view>
25
26namespace tagval::detail {
27
31
32template <typename T>
33concept HasMakeDescriptor = requires {
34 { T::make_descriptor() } -> std::same_as<TagValDescriptor>;
35};
36
37template <comms::FixedString Id, typename Derived>
38[[nodiscard]] constexpr TagValDescriptor compute_descriptor() noexcept {
39 if constexpr (HasMakeDescriptor<Derived>) {
40 return Derived::make_descriptor();
41 } else {
42 return TagValDescriptor{.id = Id.view()};
43 }
44}
45
48template <comms::FixedString Id, typename Derived>
49class HandleBase : public TagValBaseTag {
50public:
53 constexpr HandleBase() noexcept = default;
54
55 [[nodiscard]] std::string_view code() const noexcept {
56 return meta_ != nullptr ? meta_->code : std::string_view{};
57 }
58
59 [[nodiscard]] std::string_view label() const noexcept {
60 return meta_ != nullptr ? meta_->label : std::string_view{};
61 }
62
63 [[nodiscard]] std::optional<comms::Icon> icon() const noexcept {
64 return meta_ != nullptr ? meta_->icon : std::nullopt;
65 }
66
67 [[nodiscard]] std::optional<comms::Color> color() const noexcept {
68 return meta_ != nullptr ? meta_->color : std::nullopt;
69 }
70
71 [[nodiscard]] bool empty() const noexcept {
72 return meta_ == nullptr;
73 }
74
75 [[nodiscard]] explicit operator bool() const noexcept {
76 return meta_ != nullptr;
77 }
78
79 [[nodiscard]] static constexpr std::string_view kind_id() noexcept {
80 return Id.view();
81 }
82
83 [[nodiscard]] static constexpr TagValDescriptor descriptor() noexcept {
85 }
86
87 [[nodiscard]] friend constexpr bool operator==(const HandleBase& a,
88 const HandleBase& b) noexcept {
89 return a.meta_ == b.meta_;
90 }
91
92 [[nodiscard]] friend constexpr std::strong_ordering operator<=>(const HandleBase& a,
93 const HandleBase& b) noexcept {
94 // Null handles sort before populated ones; among populated handles
95 // ordering is lexicographic on code().
96 const bool ae = a.meta_ == nullptr;
97 if (const bool be = b.meta_ == nullptr; ae || be) {
98 return static_cast<int>(be) <=> static_cast<int>(ae);
99 }
100 return a.meta_->code.compare(b.meta_->code) <=> 0;
101 }
102
103protected:
104 explicit constexpr HandleBase(const TagValMetadata* m) noexcept : meta_(m) {}
105
106 const TagValMetadata* meta_ = nullptr;
107
109 [[nodiscard]] static Derived make_handle(const TagValMetadata* m) noexcept {
110 Derived d;
111 d.HandleBase::meta_ = m;
112 return d;
113 }
114
116 [[nodiscard]] static const TagValMetadata* find_in(const std::span<const TagValMetadata> values,
117 const std::string_view code) noexcept {
118 for (const auto& m : values) {
119 if (m.code == code) {
120 return &m;
121 }
122 }
123 return nullptr;
124 }
125
126 [[nodiscard]] static Derived of_impl(const std::span<const TagValMetadata> values,
127 const std::string_view code) {
128 const TagValMetadata* m = find_in(values, code);
129 if (m == nullptr) {
130 std::string msg = "tagval: unknown code '";
131 msg.append(code);
132 msg += "' for kind '";
133 msg.append(Id.view());
134 msg += "'";
135 throw UnknownCodeError{msg};
136 }
137 return make_handle(m);
138 }
139
140 [[nodiscard]] static std::expected<Derived, ParseError>
141 try_of_impl(const std::span<const TagValMetadata> values,
142 const std::string_view code) noexcept {
143 const TagValMetadata* m = find_in(values, code);
144 if (m == nullptr) {
145 return std::unexpected(ParseError{.code = std::string{code}, .kind_id = Id.view()});
146 }
147 return make_handle(m);
148 }
149};
150
151} // namespace tagval::detail
Thrown by of() when a code is not present.
Definition error.hpp:19
CRTP handle.
Definition base.hpp:49
static Derived of_impl(const std::span< const TagValMetadata > values, const std::string_view code)
Definition base.hpp:126
std::string_view label() const noexcept
Definition base.hpp:59
std::optional< comms::Color > color() const noexcept
Definition base.hpp:67
static const TagValMetadata * find_in(const std::span< const TagValMetadata > values, const std::string_view code) noexcept
Linear search a metadata range by code.
Definition base.hpp:116
static std::expected< Derived, ParseError > try_of_impl(const std::span< const TagValMetadata > values, const std::string_view code) noexcept
Definition base.hpp:141
constexpr HandleBase() noexcept=default
Default-constructed handle: empty(), bool() == false.
static constexpr TagValDescriptor descriptor() noexcept
Definition base.hpp:83
std::optional< comms::Icon > icon() const noexcept
Definition base.hpp:63
constexpr HandleBase(const TagValMetadata *m) noexcept
Definition base.hpp:104
friend constexpr bool operator==(const HandleBase &a, const HandleBase &b) noexcept
Definition base.hpp:87
static Derived make_handle(const TagValMetadata *m) noexcept
Build a Derived handle from a stable metadata pointer.
Definition base.hpp:109
std::string_view code() const noexcept
Definition base.hpp:55
const TagValMetadata * meta_
Definition base.hpp:106
static constexpr std::string_view kind_id() noexcept
Definition base.hpp:79
friend constexpr std::strong_ordering operator<=>(const HandleBase &a, const HandleBase &b) noexcept
Definition base.hpp:92
bool empty() const noexcept
Definition base.hpp:71
Empty marker base — used by std::hash / std::formatter / operator<< specializations to recognize all ...
Definition base.hpp:30
Definition base.hpp:33
Public kind-level metadata struct.
Compile-time Entry NTTP and the runtime-view TagValMetadata struct.
tagval exception types and ParseError record used by try_of().
Definition base.hpp:26
constexpr TagValDescriptor compute_descriptor() noexcept
Definition base.hpp:38
Returned via std::expected from try_of() when a code is not present.
Definition error.hpp:25
std::string code
The attempted code.
Definition error.hpp:26
Runtime metadata describing a tag-value kind (e.g.
Definition descriptor.hpp:19
std::string_view id
Stable identifier (e.g. "device_kind"). Required.
Definition descriptor.hpp:21
Runtime view of an entry's metadata.
Definition entry.hpp:46
std::string_view code
Definition entry.hpp:47
std::string_view label
Definition entry.hpp:48
std::optional< comms::Icon > icon
Definition entry.hpp:49
std::optional< comms::Color > color
Definition entry.hpp:50