parcel 0.2.2
Wrappable, wire-transferable C++23 value system with JSON serialization
Loading...
Searching...
No Matches
commons.h
Go to the documentation of this file.
1#pragma once
2
28#include <parcel/cell.h>
29#include <parcel/defaults.h>
30#include <parcel/descriptor.h>
31#include <parcel/json.h>
32
33#include <commons/color.hpp>
34#include <commons/display_info.hpp>
35#include <commons/flag.hpp>
36#include <commons/icon.hpp>
37#include <commons/json.hpp>
38#include <commons/origin.hpp>
39#include <commons/semver.hpp>
40#include <commons/version_constraint.hpp>
41
42#include <compare>
43#include <memory>
44#include <optional>
45#include <string>
46#include <string_view>
47
48namespace parcel {
49
53class ColorCell : public BaseCell<ColorCell, comms::Color> {
55
56public:
57 using base_t::base_t;
58 using base_t::operator=;
59
60 static constexpr std::string_view kind_id = "color";
61
62 [[nodiscard]] std::string to_string() const override {
63 return this->value.to_hex_string();
64 }
65
66 static cell_t from_json(json_t const& j, ParcelRegistry const&) {
67 auto v = base_t::cell_from_json<comms::Color>(j, kind_id);
68 auto cell = std::make_shared<ColorCell>(v);
70 return cell;
71 }
72
73 static cell_type_descriptor_t descriptor() {
74 static const auto d = std::make_shared<SimpleCellTypeDescriptor<ColorCell>>(
75 DisplayInfo{.name = "Color", .description = "RGBA color (hex string on the wire)"});
76 return d;
77 }
78};
79
83class IconCell : public BaseCell<IconCell, comms::Icon> {
85
86public:
87 using base_t::base_t;
88 using base_t::operator=;
89
90 static constexpr std::string_view kind_id = "icon";
91
92 [[nodiscard]] std::string to_string() const override {
93 return this->value.to_string();
94 }
95
96 static cell_t from_json(json_t const& j, ParcelRegistry const&) {
97 auto v = base_t::cell_from_json<comms::Icon>(j, kind_id);
98 auto cell = std::make_shared<IconCell>(v);
100 return cell;
101 }
102
103 static cell_type_descriptor_t descriptor() {
104 static const auto d = std::make_shared<SimpleCellTypeDescriptor<IconCell>>(DisplayInfo{
105 .name = "Icon", .description = "Iconify icon identifier (set:name string)"});
106 return d;
107 }
108};
109
113class DisplayInfoCell : public BaseCell<DisplayInfoCell, comms::DisplayInfo> {
115
116public:
117 using base_t::base_t;
118 using base_t::operator=;
119
120 static constexpr std::string_view kind_id = "display_info";
121
122 [[nodiscard]] std::string to_string() const override {
123 return json_t(this->value).dump();
124 }
125
126 static cell_t from_json(json_t const& j, ParcelRegistry const&) {
127 auto v = base_t::cell_from_json<comms::DisplayInfo>(j, kind_id);
128 auto cell = std::make_shared<DisplayInfoCell>(std::move(v));
130 return cell;
131 }
132
133 static cell_type_descriptor_t descriptor() {
134 static const auto d = std::make_shared<SimpleCellTypeDescriptor<DisplayInfoCell>>(
135 DisplayInfo{.name = "DisplayInfo",
136 .description = "Presentation display info (name/description/icon/color)"});
137 return d;
138 }
139};
140
147class FlagCell : public BaseCell<FlagCell, comms::FlagRef> {
149
150public:
151 using base_t::base_t;
152 using base_t::operator=;
153
154 static constexpr std::string_view kind_id = "flag";
155
156 [[nodiscard]] std::string to_string() const override {
157 return std::string{this->value.name};
158 }
159
160 static cell_t from_json(json_t const& j, ParcelRegistry const&) {
161 auto v = base_t::cell_from_json<comms::FlagRef>(j, kind_id);
162 auto cell = std::make_shared<FlagCell>(v);
164 return cell;
165 }
166
167 static cell_type_descriptor_t descriptor() {
168 static const auto d = std::make_shared<SimpleCellTypeDescriptor<FlagCell>>(DisplayInfo{
169 .name = "Flag", .description = "Reference to a registered flag (name on the wire)"});
170 return d;
171 }
172};
173
180class FlagSetCell : public BaseCell<FlagSetCell, comms::FlagSet> {
182
183public:
184 using base_t::base_t;
185 using base_t::operator=;
186
187 static constexpr std::string_view kind_id = "flag_set";
188
189 [[nodiscard]] std::string to_string() const override {
190 std::string out = "[";
191 bool first = true;
192 for (auto const& f : this->value) {
193 if (!first) {
194 out += ", ";
195 }
196 out += std::string{f.name};
197 first = false;
198 }
199 out += "]";
200 return out;
201 }
202
203 static cell_t from_json(json_t const& j, ParcelRegistry const&) {
204 auto v = base_t::cell_from_json<comms::FlagSet>(j, kind_id);
205 auto cell = std::make_shared<FlagSetCell>(std::move(v));
207 return cell;
208 }
209
210 static cell_type_descriptor_t descriptor() {
211 static const auto d = std::make_shared<SimpleCellTypeDescriptor<FlagSetCell>>(
212 DisplayInfo{.name = "FlagSet",
213 .description = "Insertion-ordered set of flags (names on the wire)"});
214 return d;
215 }
216};
217
222class SemVerCell : public BaseCell<SemVerCell, comms::SemVer> {
224
225public:
226 using base_t::base_t;
227 using base_t::operator=;
228
229 static constexpr std::string_view kind_id = "semver";
230
231 [[nodiscard]] std::string to_string() const override {
232 return this->value.to_string();
233 }
234
235 static cell_t from_json(json_t const& j, ParcelRegistry const&) {
236 auto v = base_t::cell_from_json<comms::SemVer>(j, kind_id);
237 auto cell = std::make_shared<SemVerCell>(v);
239 return cell;
240 }
241
242 static cell_type_descriptor_t descriptor() {
243 static const auto d = std::make_shared<SimpleCellTypeDescriptor<SemVerCell>>(DisplayInfo{
244 .name = "SemVer", .description = "Semantic version (canonical string on the wire)"});
245 return d;
246 }
247};
248
256class VersionConstraintCell : public BaseCell<VersionConstraintCell, comms::VersionConstraint> {
258
259public:
260 using base_t::base_t;
261 using base_t::operator=;
262
263 static constexpr std::string_view kind_id = "version_constraint";
264
265 [[nodiscard]] std::string to_string() const override {
266 return this->value.to_string();
267 }
268
269 static cell_t from_json(json_t const& j, ParcelRegistry const&) {
270 auto v = base_t::cell_from_json<comms::VersionConstraint>(j, kind_id);
271 auto cell = std::make_shared<VersionConstraintCell>(std::move(v));
273 return cell;
274 }
275
276 static cell_type_descriptor_t descriptor() {
277 static const auto d = std::make_shared<SimpleCellTypeDescriptor<VersionConstraintCell>>(
278 DisplayInfo{.name = "VersionConstraint",
279 .description = "Semver range constraint (range string on the wire)"});
280 return d;
281 }
282};
283
294class OriginCell : public ICell {
295public:
296 using storage_t = comms::OriginPtr;
297
298 static constexpr std::string_view kind_id = "origin";
299
301 comms::OriginPtr value;
302
303 OriginCell() = default;
304 explicit OriginCell(comms::OriginPtr v) : value(std::move(v)) {}
305
307 static cell_t of(comms::OriginPtr v) {
308 return std::make_shared<OriginCell>(std::move(v));
309 }
310
311 [[nodiscard]] std::string_view kind() const override {
312 return kind_id;
313 }
314
315 [[nodiscard]] std::optional<DisplayInfo> const& overridden_display_info() const override {
316 return display_info_;
317 }
318
319 [[nodiscard]] std::string to_string() const override {
320 return value ? std::string{value->kind()} : std::string{"null"};
321 }
322
323 [[nodiscard]] json_t to_json() const override {
324 json_t j{{KEY_KIND, kind_id}, {KEY_VALUE, value}};
325 if (display_info_) {
326 j[KEY_DESCRIPTION] = *display_info_;
327 }
328 return j;
329 }
330
331 [[nodiscard]] cell_t clone() const override {
332 auto c = std::make_shared<OriginCell>(value ? value->clone() : comms::OriginPtr{});
333 c->display_info_ = display_info_;
334 return c;
335 }
336
337 [[nodiscard]] std::partial_ordering compare(ICell const& other) const override {
338 if (const auto k_cmp = this->kind() <=> other.kind(); k_cmp != 0) {
339 return k_cmp;
340 }
341 const auto* o = dynamic_cast<OriginCell const*>(&other);
342 if (o == nullptr) {
343 return std::partial_ordering::unordered;
344 }
345 return json_t(value) == json_t(o->value) ? std::partial_ordering::equivalent
346 : std::partial_ordering::unordered;
347 }
348
349 static cell_t from_json(json_t const& j, ParcelRegistry const&) {
350 // Mirror BaseCell::cell_from_json's {"k","v"} validation; OriginPtr is
351 // move-only so we cannot route through the BaseCell helper.
352 if (!j.is_object()) {
353 throw InvalidJsonException("Expected JSON object for ICell", std::string(kind_id));
354 }
355 const auto it_kind = j.find(KEY_KIND);
356 if (it_kind == j.end() || !it_kind->is_string()) {
357 throw InvalidJsonException("Missing or invalid 'k' field in ICell JSON",
358 std::string(kind_id));
359 }
360 if (const auto k = it_kind->get<std::string_view>(); k != kind_id) {
361 throw KindMismatchException("Unexpected kind in ICell JSON: expected '" +
362 std::string(kind_id) + "', got '" + std::string(k) +
363 "'",
364 std::string(kind_id));
365 }
366 const auto it_value = j.find(KEY_VALUE);
367 if (it_value == j.end()) {
368 throw InvalidJsonException("Missing 'v' field in ICell JSON", std::string(kind_id));
369 }
370 // Resolves "kind" against comms::GlobalOriginRegistry; unknown kind throws.
371 auto cell = std::make_shared<OriginCell>(it_value->get<comms::OriginPtr>());
372 if (const auto it_d = j.find(KEY_DESCRIPTION); it_d != j.end()) {
373 cell->set_display_info(it_d->get<DisplayInfo>());
374 }
375 return cell;
376 }
377
378 static cell_type_descriptor_t descriptor() {
379 static const auto d = std::make_shared<SimpleCellTypeDescriptor<OriginCell>>(DisplayInfo{
380 .name = "Origin",
381 .description = "Polymorphic provenance envelope ({\"kind\", …fields} on the wire)"});
382 return d;
383 }
384
385protected:
386 void set_display_info(std::optional<DisplayInfo> m) override {
387 display_info_ = std::move(m);
388 }
389
390private:
391 std::optional<DisplayInfo> display_info_;
392};
393
394} // namespace parcel
395
Core ICell interface, cell_t handle, BaseCell CRTP base, and CellLike concept.
std::shared_ptr< ICellTypeDescriptor > cell_type_descriptor_t
Shared handle to a runtime cell-type descriptor.
Definition cell.h:63
std::shared_ptr< ICell > cell_t
Shared handle to any ICell-derived value — the canonical cell pointer.
Definition cell.h:68
Cell wrapping comms::Color.
Definition commons.h:53
std::string to_string() const override
Render the cell's value as a compact human-readable string.
Definition commons.h:62
Cell wrapping comms::DisplayInfo.
Definition commons.h:113
std::string to_string() const override
Render the cell's value as a compact human-readable string.
Definition commons.h:122
Cell wrapping comms::FlagRef.
Definition commons.h:147
std::string to_string() const override
Render the cell's value as a compact human-readable string.
Definition commons.h:156
Cell wrapping comms::FlagSet.
Definition commons.h:180
std::string to_string() const override
Render the cell's value as a compact human-readable string.
Definition commons.h:189
Cell wrapping comms::Icon.
Definition commons.h:83
std::string to_string() const override
Render the cell's value as a compact human-readable string.
Definition commons.h:92
JSON shape was wrong (missing/non-string k, missing v, etc.).
Definition error.h:158
Cell wrapping comms::OriginPtr (a std::unique_ptr<comms::IOrigin>).
Definition commons.h:294
static cell_t of(comms::OriginPtr v)
Construct a shared_ptr<OriginCell> owning v.
Definition commons.h:307
std::optional< DisplayInfo > const & overridden_display_info() const override
Read-only access to this cell's optional display info.
Definition commons.h:315
json_t to_json() const override
Serialize this cell to its canonical JSON representation.
Definition commons.h:323
comms::OriginPtr value
Held origin (may be null).
Definition commons.h:301
std::string to_string() const override
Render the cell's value as a compact human-readable string.
Definition commons.h:319
void set_display_info(std::optional< DisplayInfo > m) override
Replace this cell's display info in place.
Definition commons.h:386
std::string_view kind() const override
Wire-stable kind identifier for this cell.
Definition commons.h:311
std::partial_ordering compare(ICell const &other) const override
Three-way compare against another cell.
Definition commons.h:337
cell_t clone() const override
Deep-copy this cell.
Definition commons.h:331
Runtime catalog of cell-type descriptors, keyed by wire kind id.
Definition registry.h:115
Cell wrapping comms::SemVer.
Definition commons.h:222
std::string to_string() const override
Render the cell's value as a compact human-readable string.
Definition commons.h:231
Cell wrapping comms::VersionConstraint.
Definition commons.h:256
std::string to_string() const override
Render the cell's value as a compact human-readable string.
Definition commons.h:265
comms::DisplayInfo DisplayInfo
Display info attached to a cell or descriptor — re-exported from comms::DisplayInfo.
Definition common.h:75
The default_cell_for<T> trait that drives FieldsBuilder field-type inference.
#define PARCEL_DEFAULT_CELL(CellT)
Register a cell type as the default wrapper for its payload type.
Definition defaults.h:269
auto cell(T &&v)
Wrap a raw value into its default cell, returning a shared_ptr to the cell.
Definition defaults.h:192
Runtime cell-type descriptors and the schema-graph mix-ins (IHasFields, ISubTypes).
nlohmann::json typedef shared across cell types.
nlohmann::json json_t
Project-wide alias for nlohmann::json.
Definition json.h:19
CRTP base providing default to_json / clone / kind plumbing on top of a storage type.
Definition cell.h:343
static void absorb_display_info(json_t const &j, Out &out)
Read "d" (if present) from a JSON object and assign it onto a cell.
Definition cell.h:499
comms::Color value
Held value of the cell.
Definition cell.h:348
Polymorphic root of every parcel cell.
Definition cell.h:84
static constexpr std::string_view KEY_DESCRIPTION
JSON key for the optional display info block ("d").
Definition cell.h:90
static constexpr std::string_view KEY_VALUE
JSON key for the value payload ("v").
Definition cell.h:88
virtual std::string_view kind() const =0
Wire-stable kind identifier for this cell.
static constexpr std::string_view KEY_KIND
JSON key for the kind id ("k").
Definition cell.h:86