parcel 0.2.2
Wrappable, wire-transferable C++23 value system with JSON serialization
Loading...
Searching...
No Matches
error.h
Go to the documentation of this file.
1#pragma once
2
13#include <stdexcept>
14#include <string>
15#include <utility>
16
17// `<expected>` ships in libstdc++ 14 / libc++ 17, but only enables the
18// `std::expected` templates when the compiler meets internal concept /
19// constexpr gates. Include the header first (`__has_include` only checks
20// for file existence) and then check `__cpp_lib_expected` — that macro is
21// defined by `<expected>` itself iff the templates were actually exposed,
22// so it stays consistent across g++ and clang-tidy parse paths.
23#if __has_include(<expected>)
24#include <expected>
25#endif
26
27#if defined(__cpp_lib_expected) && __cpp_lib_expected >= 202202L
28#define PARCEL_HAS_EXPECTED 1
29#else
30#define PARCEL_HAS_EXPECTED 0
31#endif
32
33namespace parcel {
34
43 enum class Code {
54 };
55
59 std::string message;
61 std::string kind;
63 std::string field;
64
69 [[nodiscard]] std::string to_string() const {
70 std::string out;
71 switch (code) {
73 out = "InvalidJson";
74 break;
76 out = "KindMismatch";
77 break;
79 out = "UnknownKind";
80 break;
82 out = "MissingField";
83 break;
84 case Code::TypeError:
85 out = "TypeError";
86 break;
87 }
88 out += ": ";
89 out += message;
90 if (!kind.empty()) {
91 out += " [kind=";
92 out += kind;
93 out += "]";
94 }
95 if (!field.empty()) {
96 out += " [field=";
97 out += field;
98 out += "]";
99 }
100 return out;
101 }
102
106 static ParcelError
107 make(const Code c, std::string msg, std::string kind_id = {}, std::string fld = {}) {
108 return ParcelError{c, std::move(msg), std::move(kind_id), std::move(fld)};
109 }
110};
111
121class ParcelException : public std::runtime_error {
122public:
123 // std::runtime_error only takes a const-ref string, so msg is necessarily
124 // copied into the base sub-object — pass-by-value-then-move would buy us
125 // nothing here. Adjacent string params are intentional and used by every
126 // derived class.
127 // NOLINTBEGIN(bugprone-easily-swappable-parameters,performance-unnecessary-value-param)
129 const std::string& msg,
130 std::string kind_id = {},
131 std::string field_name = {})
132 : std::runtime_error(msg), code_(c), kind_(std::move(kind_id)),
133 field_(std::move(field_name)) {}
134 // NOLINTEND(bugprone-easily-swappable-parameters,performance-unnecessary-value-param)
135
136 [[nodiscard]] ParcelError::Code code() const noexcept {
137 return code_;
138 }
139 [[nodiscard]] std::string_view kind_id() const noexcept {
140 return kind_;
141 }
142 [[nodiscard]] std::string_view field_name() const noexcept {
143 return field_;
144 }
145
147 [[nodiscard]] ParcelError to_error() const {
148 return ParcelError::make(code_, what(), kind_, field_);
149 }
150
151private:
152 ParcelError::Code code_;
153 std::string kind_;
154 std::string field_;
155};
156
159public:
160 explicit InvalidJsonException(const std::string& msg,
161 std::string kind_id = {},
162 std::string field_name = {})
164 ParcelError::Code::InvalidJson, msg, std::move(kind_id), std::move(field_name)) {}
165};
166
169public:
170 explicit KindMismatchException(const std::string& msg, std::string kind_id = {})
171 : ParcelException(ParcelError::Code::KindMismatch, msg, std::move(kind_id)) {}
172};
173
176public:
177 explicit UnknownKindException(const std::string& msg, std::string kind_id = {})
178 : ParcelException(ParcelError::Code::UnknownKind, msg, std::move(kind_id)) {}
179};
180
183public:
184 MissingFieldException(const std::string& msg, std::string kind_id, std::string field_name)
186 ParcelError::Code::MissingField, msg, std::move(kind_id), std::move(field_name)) {}
187};
188
190class TypeException final : public ParcelException {
191public:
192 explicit TypeException(const std::string& msg,
193 std::string kind_id = {},
194 std::string field_name = {})
196 ParcelError::Code::TypeError, msg, std::move(kind_id), std::move(field_name)) {}
197};
198
199} // namespace parcel
JSON shape was wrong (missing/non-string k, missing v, etc.).
Definition error.h:158
k field was present but did not match the expected kind.
Definition error.h:168
Required struct field absent from the JSON payload.
Definition error.h:182
Base class for parcel deserialization exceptions.
Definition error.h:121
ParcelError to_error() const
Project to a ParcelError value (used by try_* adapters).
Definition error.h:147
Typed value (cast, struct field, etc.) failed conversion.
Definition error.h:190
Registry was asked to dispatch a kind it does not know.
Definition error.h:175
Structured error returned by the non-throwing try_* parsing surface.
Definition error.h:41
std::string kind
Kind id involved in the error (may be empty).
Definition error.h:61
std::string message
Human-readable message — never empty.
Definition error.h:59
std::string field
Struct field name involved in the error (may be empty).
Definition error.h:63
std::string to_string() const
Render the error as code: message [kind=…] [field=…].
Definition error.h:69
static ParcelError make(const Code c, std::string msg, std::string kind_id={}, std::string fld={})
Construct from code, message, and optional kind/field tags.
Definition error.h:107
Code code
Coarse error code.
Definition error.h:57
Code
Coarse error categories.
Definition error.h:43
@ TypeError
A typed value (e.g.
@ KindMismatch
JSON "k" did not match the expected kind.
@ InvalidJson
Input was not parseable JSON or had wrong shape.
@ MissingField
A required struct field was missing.
@ UnknownKind
JSON "k" referenced a kind not registered.