parcel 0.2.4
Wrappable, wire-transferable C++23 value system with JSON serialization
Loading...
Searching...
No Matches
reason.h
Go to the documentation of this file.
1#pragma once
2
9#include <parcel/cell.h>
10#include <parcel/defaults.h>
11#include <parcel/descriptor.h>
12#include <parcel/json.h>
13
14#include <commons/json/reason.hpp>
15#include <commons/reason.hpp>
16
17#include <compare>
18#include <memory>
19#include <optional>
20#include <string>
21#include <string_view>
22#include <utility>
23
24namespace parcel {
25
36class ReasonCell : public ICell {
37public:
38 using storage_t = comms::ReasonPtr;
39
40 static constexpr std::string_view kind_id = "reason";
41
43 comms::ReasonPtr value;
44
45 ReasonCell() = default;
46 explicit ReasonCell(comms::ReasonPtr v) : value(std::move(v)) {}
47
49 static cell_t of(comms::ReasonPtr v) {
50 return std::make_shared<ReasonCell>(std::move(v));
51 }
52
53 [[nodiscard]] std::string_view kind() const override {
54 return kind_id;
55 }
56
57 [[nodiscard]] std::optional<DisplayInfo> const& overridden_display_info() const override {
58 return display_info_;
59 }
60
61 [[nodiscard]] std::string to_string() const override {
62 return value ? std::string{value->kind()} : std::string{"null"};
63 }
64
65 [[nodiscard]] json_t to_json() const override {
66 json_t j{{KEY_KIND, kind_id}, {KEY_VALUE, value}};
67 if (display_info_) {
68 j[KEY_DESCRIPTION] = *display_info_;
69 }
70 return j;
71 }
72
73 [[nodiscard]] cell_t clone() const override {
74 auto c = std::make_shared<ReasonCell>(value ? value->clone() : comms::ReasonPtr{});
75 c->display_info_ = display_info_;
76 return c;
77 }
78
79 [[nodiscard]] std::partial_ordering compare(ICell const& other) const override {
80 if (const auto k_cmp = this->kind() <=> other.kind(); k_cmp != 0) {
81 return k_cmp;
82 }
83 const auto* o = dynamic_cast<ReasonCell const*>(&other);
84 if (o == nullptr) {
85 return std::partial_ordering::unordered;
86 }
87 return json_t(value) == json_t(o->value) ? std::partial_ordering::equivalent
88 : std::partial_ordering::unordered;
89 }
90
91 static cell_t from_json(json_t const& j, ParcelRegistry const&) {
92 if (!j.is_object()) {
93 throw InvalidJsonException("Expected JSON object for ICell", std::string(kind_id));
94 }
95 const auto it_kind = j.find(KEY_KIND);
96 if (it_kind == j.end() || !it_kind->is_string()) {
97 throw InvalidJsonException("Missing or invalid 'k' field in ICell JSON",
98 std::string(kind_id));
99 }
100 if (const auto k = it_kind->get<std::string_view>(); k != kind_id) {
101 throw KindMismatchException("Unexpected kind in ICell JSON: expected '" +
102 std::string(kind_id) + "', got '" + std::string(k) +
103 "'",
104 std::string(kind_id));
105 }
106 const auto it_value = j.find(KEY_VALUE);
107 if (it_value == j.end()) {
108 throw InvalidJsonException("Missing 'v' field in ICell JSON", std::string(kind_id));
109 }
110 // Resolves "kind" against comms::GlobalReasonRegistry; unknown kind throws.
111 auto cell = std::make_shared<ReasonCell>(it_value->get<comms::ReasonPtr>());
112 if (const auto it_d = j.find(KEY_DESCRIPTION); it_d != j.end()) {
113 cell->set_display_info(it_d->get<DisplayInfo>());
114 }
115 return cell;
116 }
117
118 static cell_type_descriptor_t descriptor() {
119 static const auto d = std::make_shared<SimpleCellTypeDescriptor<ReasonCell>>(DisplayInfo{
120 .name = "Reason",
121 .description = "Polymorphic \"why\" envelope ({\"kind\", …fields} on the wire)"});
122 return d;
123 }
124
125protected:
126 void set_display_info(std::optional<DisplayInfo> m) override {
127 display_info_ = std::move(m);
128 }
129
130private:
131 std::optional<DisplayInfo> display_info_;
132};
133
143class FailureReasonCell : public ICell {
144public:
145 using storage_t = comms::FailureReasonPtr;
146
147 static constexpr std::string_view kind_id = "failure_reason";
148
150 comms::FailureReasonPtr value;
151
152 FailureReasonCell() = default;
153 explicit FailureReasonCell(comms::FailureReasonPtr v) : value(std::move(v)) {}
154
156 static cell_t of(comms::FailureReasonPtr v) {
157 return std::make_shared<FailureReasonCell>(std::move(v));
158 }
159
160 [[nodiscard]] std::string_view kind() const override {
161 return kind_id;
162 }
163
164 [[nodiscard]] std::optional<DisplayInfo> const& overridden_display_info() const override {
165 return display_info_;
166 }
167
168 [[nodiscard]] std::string to_string() const override {
169 return value ? std::string{value->kind()} : std::string{"null"};
170 }
171
172 [[nodiscard]] json_t to_json() const override {
173 json_t j{{KEY_KIND, kind_id}, {KEY_VALUE, value}};
174 if (display_info_) {
175 j[KEY_DESCRIPTION] = *display_info_;
176 }
177 return j;
178 }
179
180 [[nodiscard]] cell_t clone() const override {
181 // IFailureReason::clone() returns a ReasonPtr whose dynamic type is the
182 // failure subclass; recover the typed pointer (provably safe downcast).
183 comms::FailureReasonPtr copy;
184 if (value) {
185 comms::IReason* raw = value->clone().release();
186 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
187 copy = comms::FailureReasonPtr{static_cast<comms::IFailureReason*>(raw)};
188 }
189 auto c = std::make_shared<FailureReasonCell>(std::move(copy));
190 c->display_info_ = display_info_;
191 return c;
192 }
193
194 [[nodiscard]] std::partial_ordering compare(ICell const& other) const override {
195 if (const auto k_cmp = this->kind() <=> other.kind(); k_cmp != 0) {
196 return k_cmp;
197 }
198 const auto* o = dynamic_cast<FailureReasonCell const*>(&other);
199 if (o == nullptr) {
200 return std::partial_ordering::unordered;
201 }
202 return json_t(value) == json_t(o->value) ? std::partial_ordering::equivalent
203 : std::partial_ordering::unordered;
204 }
205
206 static cell_t from_json(json_t const& j, ParcelRegistry const&) {
207 if (!j.is_object()) {
208 throw InvalidJsonException("Expected JSON object for ICell", std::string(kind_id));
209 }
210 const auto it_kind = j.find(KEY_KIND);
211 if (it_kind == j.end() || !it_kind->is_string()) {
212 throw InvalidJsonException("Missing or invalid 'k' field in ICell JSON",
213 std::string(kind_id));
214 }
215 if (const auto k = it_kind->get<std::string_view>(); k != kind_id) {
216 throw KindMismatchException("Unexpected kind in ICell JSON: expected '" +
217 std::string(kind_id) + "', got '" + std::string(k) +
218 "'",
219 std::string(kind_id));
220 }
221 const auto it_value = j.find(KEY_VALUE);
222 if (it_value == j.end()) {
223 throw InvalidJsonException("Missing 'v' field in ICell JSON", std::string(kind_id));
224 }
225 // Resolves "kind" against comms::GlobalReasonRegistry and verifies the
226 // kind is an IFailureReason; unknown / non-failure kind throws.
227 auto cell = std::make_shared<FailureReasonCell>(it_value->get<comms::FailureReasonPtr>());
228 if (const auto it_d = j.find(KEY_DESCRIPTION); it_d != j.end()) {
229 cell->set_display_info(it_d->get<DisplayInfo>());
230 }
231 return cell;
232 }
233
234 static cell_type_descriptor_t descriptor() {
235 static const auto d =
236 std::make_shared<SimpleCellTypeDescriptor<FailureReasonCell>>(DisplayInfo{
237 .name = "FailureReason",
238 .description =
239 "Polymorphic developer-controlled failure ({\"kind\", …fields} on the wire)"});
240 return d;
241 }
242
243protected:
244 void set_display_info(std::optional<DisplayInfo> m) override {
245 display_info_ = std::move(m);
246 }
247
248private:
249 std::optional<DisplayInfo> display_info_;
250};
251
252} // namespace parcel
253
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::FailureReasonPtr (a std::unique_ptr<comms::IFailureReason>).
Definition reason.h:143
std::partial_ordering compare(ICell const &other) const override
Three-way compare against another cell.
Definition reason.h:194
std::optional< DisplayInfo > const & overridden_display_info() const override
Read-only access to this cell's optional display info.
Definition reason.h:164
std::string_view kind() const override
Wire-stable kind identifier for this cell.
Definition reason.h:160
std::string to_string() const override
Render the cell's value as a compact human-readable string.
Definition reason.h:168
cell_t clone() const override
Deep-copy this cell.
Definition reason.h:180
comms::FailureReasonPtr value
Held failure reason (may be null).
Definition reason.h:150
json_t to_json() const override
Serialize this cell to its canonical JSON representation.
Definition reason.h:172
static cell_t of(comms::FailureReasonPtr v)
Construct a shared_ptr<FailureReasonCell> owning v.
Definition reason.h:156
void set_display_info(std::optional< DisplayInfo > m) override
Replace this cell's display info in place.
Definition reason.h:244
JSON shape was wrong (missing/non-string k, missing v, etc.).
Definition error.h:158
Runtime catalog of cell-type descriptors, keyed by wire kind id.
Definition registry.h:115
Cell wrapping comms::ReasonPtr (a std::unique_ptr<comms::IReason>).
Definition reason.h:36
std::string to_string() const override
Render the cell's value as a compact human-readable string.
Definition reason.h:61
std::optional< DisplayInfo > const & overridden_display_info() const override
Read-only access to this cell's optional display info.
Definition reason.h:57
json_t to_json() const override
Serialize this cell to its canonical JSON representation.
Definition reason.h:65
void set_display_info(std::optional< DisplayInfo > m) override
Replace this cell's display info in place.
Definition reason.h:126
std::string_view kind() const override
Wire-stable kind identifier for this cell.
Definition reason.h:53
cell_t clone() const override
Deep-copy this cell.
Definition reason.h:73
std::partial_ordering compare(ICell const &other) const override
Three-way compare against another cell.
Definition reason.h:79
comms::ReasonPtr value
Held reason (may be null).
Definition reason.h:43
static cell_t of(comms::ReasonPtr v)
Construct a shared_ptr<ReasonCell> owning v.
Definition reason.h:49
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
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