Loading [MathJax]/extensions/tex2jax.js
Iros
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
Loading...
Searching...
No Matches
json_deserializer.h
Go to the documentation of this file.
1#pragma once
2
9#include "di/io/prelude.h"
10#include "di/io/string_reader.h"
11#include "di/meta/core.h"
12#include "di/meta/operations.h"
14#include "di/platform/prelude.h"
20#include "di/types/prelude.h"
21#include "di/util/exchange.h"
28
29namespace di::serialization {
35template<concepts::Impl<io::Reader> Reader>
36class JsonDeserializer {
37private:
38 template<typename T>
39 using Result = meta::ReaderResult<T, Reader>;
40
41public:
43
44 template<typename T>
46 constexpr explicit JsonDeserializer(T&& reader) : m_reader(util::forward<T>(reader)) {}
47
48 constexpr auto deserialize(InPlaceType<json::Value>) -> Result<json::Value> {
49 auto result = DI_TRY(deserialize_value());
50 DI_TRY(skip_whitespace());
51 return result;
52 }
53
54 template<typename T, concepts::InstanceOf<reflection::Fields> M>
55 constexpr auto deserialize(InPlaceType<T>, M fields) -> Result<T> {
56 // NOTE: for now, this requires T be default constructible.
57 auto result = T {};
58
59 DI_TRY(skip_whitespace());
60 DI_TRY(expect('{'));
61
62 auto first = true;
63 for (;;) {
64 DI_TRY(skip_whitespace());
65 auto code_point = DI_TRY(peek_next_code_point());
66 if (!code_point) {
67 return vocab::Unexpected(BasicError::InvalidArgument);
68 }
69 if (*code_point == U'}') {
70 break;
71 }
72 if (!util::exchange(first, false)) {
73 DI_TRY(expect(U','));
74 }
75 auto key = DI_TRY(deserialize_string());
76 DI_TRY(skip_whitespace());
77 DI_TRY(expect(U':'));
78 DI_TRY(skip_whitespace());
79
80 auto found = false;
81 DI_TRY(vocab::tuple_sequence<Result<void>>(
82 [&](auto field) -> Result<void> {
84 using Value = meta::Type<decltype(field)>;
85 if constexpr (concepts::Optional<Value>) {
87 } else {
89 }
90 found = true;
91 }
92 return {};
93 },
94 fields));
95 if (!found) {
96 return vocab::Unexpected(BasicError::InvalidArgument);
97 }
98 }
99
100 DI_TRY(expect('}'));
101 DI_TRY(skip_whitespace());
102 return result;
103 }
104
105 template<typename T, concepts::InstanceOf<reflection::Enumerators> M>
106 constexpr auto deserialize(InPlaceType<T>, M enumerators) -> Result<T> {
107 DI_TRY(skip_whitespace());
108 auto string = DI_TRY(deserialize_string());
109 DI_TRY(skip_whitespace());
110 auto result = T(0);
111 auto found = false;
112
114 [&](auto enumerator) {
116 result = T(enumerator.value);
117 found = true;
118 }
119 },
120 enumerators);
121
122 if (!found) {
123 return vocab::Unexpected(BasicError::InvalidArgument);
124 }
125 return result;
126 }
127
128 template<typename T, concepts::InstanceOf<reflection::Atom> M>
129 requires(M::is_bool() || M::is_integer() || M::is_string())
130 constexpr auto deserialize(InPlaceType<T>, M) -> Result<T> {
131 if constexpr (M::is_bool()) {
132 auto result = DI_TRY(deserialize_bool());
133 DI_TRY(skip_whitespace());
134 return result;
135 } else if constexpr (M::is_integer()) {
136 auto result = DI_TRY(deserialize_number(in_place_type<T>));
137 DI_TRY(skip_whitespace());
138 return result;
139 } else if constexpr (M::is_string()) {
140 auto result = DI_TRY(deserialize_string());
141 DI_TRY(skip_whitespace());
142 return result;
143 }
144 }
145
146 template<typename T, concepts::InstanceOf<reflection::Atom> M>
148 constexpr auto deserialize(InPlaceType<T>, M) -> Result<T> {
149 auto result = T {};
150
151 DI_TRY(skip_whitespace());
152 DI_TRY(expect('['));
153
154 for (;;) {
155 DI_TRY(skip_whitespace());
156 auto code_point = DI_TRY(peek_next_code_point());
157 if (!code_point) {
158 return vocab::Unexpected(BasicError::InvalidArgument);
159 }
160 if (*code_point == U']') {
161 break;
162 }
163 if (!result.empty()) {
164 DI_TRY(expect(U','));
165 }
167 }
168
169 DI_TRY(expect(']'));
170 DI_TRY(skip_whitespace());
171 return result;
172 }
173
174 template<typename T, concepts::InstanceOf<reflection::Atom> M>
177 constexpr auto deserialize(InPlaceType<T>, M) -> Result<T> {
178 auto result = T {};
179
180 DI_TRY(skip_whitespace());
181 DI_TRY(expect('{'));
182
183 for (;;) {
184 DI_TRY(skip_whitespace());
185 auto code_point = DI_TRY(peek_next_code_point());
186 if (!code_point) {
187 return vocab::Unexpected(BasicError::InvalidArgument);
188 }
189 if (*code_point == U'}') {
190 break;
191 }
192 if (!result.empty()) {
193 DI_TRY(expect(U','));
194 }
195 auto key = DI_TRY(deserialize_string());
196 DI_TRY(skip_whitespace());
197 DI_TRY(expect(U':'));
198 DI_TRY(skip_whitespace());
200 result.insert_or_assign(util::move(key), util::move(value));
201 }
202
203 DI_TRY(expect('}'));
204 DI_TRY(skip_whitespace());
205 return result;
206 }
207
208 constexpr auto deserialize(InPlaceType<json::Null>) -> Result<json::Null> {
209 auto result = DI_TRY(deserialize_null());
210 DI_TRY(skip_whitespace());
211 return result;
212 }
213
214 constexpr auto reader() & -> Reader& { return m_reader; }
215 constexpr auto reader() const& -> Reader const& { return m_reader; }
216 constexpr auto reader() && -> Reader&& { return util::move(*this).m_reader; }
217
218private:
219 constexpr static auto is_whitespace(c32 code_point) -> bool {
220 return code_point == ' ' || code_point == '\t' || code_point == '\n' || code_point == '\r';
221 }
222
223 constexpr auto expect(c32 expected) -> Result<void> {
224 auto code_point = DI_TRY(next_code_point());
225 if (!code_point || *code_point != expected) {
226 return vocab::Unexpected(BasicError::InvalidArgument);
227 }
228 return {};
229 }
230
231 constexpr auto fill_next_code_point() -> Result<void> {
232 // FIXME: handle UTF-8.
233 auto byte = vocab::Array<types::byte, 1> {};
234 auto nread = DI_TRY(io::read_some(m_reader, byte));
235 if (nread == 0) {
236 m_at_end = true;
237 }
238 m_next_code_point = c32(byte[0]);
239 return {};
240 }
241
242 constexpr auto peek_next_code_point() -> Result<vocab::Optional<c32>> {
243 if (m_at_end) {
244 return vocab::nullopt;
245 }
246 if (!m_next_code_point) {
247 DI_TRY(fill_next_code_point());
248 if (m_at_end) {
249 return vocab::nullopt;
250 }
251 }
252 return *m_next_code_point;
253 }
254
255 constexpr void consume() { m_next_code_point = vocab::nullopt; }
256
257 constexpr auto next_code_point() -> Result<vocab::Optional<c32>> {
258 if (m_at_end) {
259 return vocab::nullopt;
260 }
261 if (!m_next_code_point) {
262 DI_TRY(fill_next_code_point());
263 if (m_at_end) {
264 return vocab::nullopt;
265 }
266 }
267 return *util::exchange(m_next_code_point, vocab::nullopt);
268 }
269
270 constexpr auto require_next_code_point() -> Result<c32> {
271 auto code_point = DI_TRY(next_code_point());
272 if (!code_point) {
273 return vocab::Unexpected(BasicError::InvalidArgument);
274 }
275 return *code_point;
276 }
277
278 constexpr auto skip_whitespace() -> Result<void> {
279 for (;;) {
280 auto code_point = DI_TRY(peek_next_code_point());
281 if (!code_point || !is_whitespace(*code_point)) {
282 return {};
283 }
284 consume();
285 }
286 }
287
288 constexpr auto deserialize_value() -> Result<json::Value> {
289 DI_TRY(skip_whitespace());
290
291 auto code_point = DI_TRY(peek_next_code_point());
292 if (!code_point) {
293 return vocab::Unexpected(BasicError::InvalidArgument);
294 }
295
296 switch (*code_point) {
297 case U'n':
298 return deserialize_null();
299 case U't':
300 return deserialize_true();
301 case U'f':
302 return deserialize_false();
303 case U'"':
304 return deserialize_string();
305 case U'-':
306 case U'0':
307 case U'1':
308 case U'2':
309 case U'3':
310 case U'4':
311 case U'5':
312 case U'6':
313 case U'7':
314 case U'8':
315 case U'9':
316 return deserialize_number(in_place_type<json::Number>);
317 case U'{':
318 return deserialize_object();
319 case U'[':
320 return deserialize_array();
321 default:
322 return vocab::Unexpected(BasicError::InvalidArgument);
323 }
324 }
325
326 constexpr auto deserialize_null() -> Result<json::Null> {
327 DI_TRY(skip_whitespace());
328
329 DI_TRY(expect(U'n'));
330 DI_TRY(expect(U'u'));
331 DI_TRY(expect(U'l'));
332 DI_TRY(expect(U'l'));
333 return json::null;
334 }
335
336 constexpr auto deserialize_bool() -> Result<json::Bool> {
337 DI_TRY(skip_whitespace());
338
339 auto code_point = DI_TRY(require_next_code_point());
340 switch (code_point) {
341 case U't':
342 DI_TRY(expect(U'r'));
343 DI_TRY(expect(U'u'));
344 DI_TRY(expect(U'e'));
345 return true;
346 case U'f':
347 DI_TRY(expect(U'a'));
348 DI_TRY(expect(U'l'));
349 DI_TRY(expect(U's'));
350 DI_TRY(expect(U'e'));
351 return false;
352 default:
353 return vocab::Unexpected(BasicError::InvalidArgument);
354 }
355 }
356
357 constexpr auto deserialize_true() -> Result<json::Bool> {
358 DI_TRY(skip_whitespace());
359 DI_TRY(expect(U't'));
360 DI_TRY(expect(U'r'));
361 DI_TRY(expect(U'u'));
362 DI_TRY(expect(U'e'));
363 return true;
364 }
365
366 constexpr auto deserialize_false() -> Result<json::Bool> {
367 DI_TRY(skip_whitespace());
368 DI_TRY(expect(U'f'));
369 DI_TRY(expect(U'a'));
370 DI_TRY(expect(U'l'));
371 DI_TRY(expect(U's'));
372 DI_TRY(expect(U'e'));
373 return false;
374 }
375
376 constexpr auto deserialize_string() -> Result<json::String> {
377 DI_TRY(skip_whitespace());
378 DI_TRY(expect(U'"'));
379
380 auto string = json::String {};
381 for (;;) {
382 auto code_point = DI_TRY(next_code_point());
383 if (!code_point || *code_point < 0x20) {
384 return vocab::Unexpected(BasicError::InvalidArgument);
385 }
386 if (*code_point == U'"') {
387 break;
388 }
389 // FIXME: handle escape sequences.
390 string.push_back(*code_point);
391 }
392 return string;
393 }
394
395 template<concepts::Integer T>
396 constexpr auto deserialize_number(InPlaceType<T>) -> Result<json::Number> {
397 DI_TRY(skip_whitespace());
398 auto first_code_point = DI_TRY(require_next_code_point());
399
400 auto string = json::String {};
401 if (first_code_point == U'-') {
402 string.push_back(first_code_point);
403 first_code_point = DI_TRY(require_next_code_point());
404 if (first_code_point < U'0' || first_code_point > U'9') {
405 return vocab::Unexpected(BasicError::InvalidArgument);
406 }
407 }
408 if (first_code_point == U'0') {
409 return 0;
410 }
411
412 string.push_back(first_code_point);
413
414 for (;;) {
415 auto code_point = DI_TRY(peek_next_code_point());
416 if (!code_point) {
417 break;
418 }
419
420 if (*code_point < U'0' || *code_point > U'9') {
421 break;
422 }
423
424 string.push_back(*code_point);
425 consume();
426 }
427
428 // FIXME: handle decimal point and exponent for floating point numbers.
429 auto result = parser::parse<T>(string);
430 if (!result) {
431 return vocab::Unexpected(BasicError::InvalidArgument);
432 }
433 return *result;
434 }
435
436 constexpr auto deserialize_array() -> Result<json::Array> {
437 DI_TRY(skip_whitespace());
438 DI_TRY(expect(U'['));
439
440 auto array = json::Array {};
441 for (;;) {
442 DI_TRY(skip_whitespace());
443 auto code_point = DI_TRY(peek_next_code_point());
444 if (!code_point) {
445 return vocab::Unexpected(BasicError::InvalidArgument);
446 }
447 if (*code_point == U']') {
448 break;
449 }
450 if (!array.empty()) {
451 DI_TRY(expect(U','));
452 }
453 array.push_back(DI_TRY(deserialize_value()));
454 }
455
456 DI_TRY(expect(U']'));
457 return array;
458 }
459
460 constexpr auto deserialize_object() -> Result<json::Object> {
461 DI_TRY(skip_whitespace());
462 DI_TRY(expect(U'{'));
463
464 auto object = json::Object {};
465 for (;;) {
466 DI_TRY(skip_whitespace());
467 auto code_point = DI_TRY(peek_next_code_point());
468 if (!code_point) {
469 return vocab::Unexpected(BasicError::InvalidArgument);
470 }
471 if (*code_point == U'}') {
472 break;
473 }
474 if (!object.empty()) {
475 DI_TRY(expect(U','));
476 DI_TRY(skip_whitespace());
477 }
478 auto key = DI_TRY(deserialize_string());
479 DI_TRY(skip_whitespace());
480 DI_TRY(expect(U':'));
481 auto value = DI_TRY(deserialize_value());
482 object.insert_or_assign(util::move(key), util::move(value));
483 }
484
485 DI_TRY(expect(U'}'));
486 return object;
487 }
488
489 Reader m_reader;
490 vocab::Optional<c32> m_next_code_point;
491 bool m_at_end { false };
492};
493
494template<typename T>
496
497namespace detail {
498 template<typename T>
500 template<typename... Args>
503 constexpr auto operator()(container::StringView view, Args&&... args) const {
504 return serialization::deserialize_string<T>(json_format, view, util::forward<Args>(args)...);
505 }
506 };
507}
508
509template<concepts::Deserializable<JsonDeserializer<StringReader<container::StringView>>> T = json::Value>
511
512namespace detail {
513 template<typename T>
515 template<concepts::Impl<io::Reader> Reader, typename... Args>
517 Args...> &&
519 constexpr auto operator()(Reader&& reader, Args&&... args) const {
520 return serialization::deserialize<T>(json_format, ref(reader), util::forward<Args>(args)...);
521 }
522 };
523}
524
525template<typename T = json::Value>
527}
528
529namespace di {
530inline namespace literals {
531 inline namespace json_literals {
532 namespace detail {
533 template<container::FixedString string>
534 consteval auto valid_json_literal() -> bool {
535 // NOTE: GCC does not think that the following is a constant expression, but clang does.
536#ifdef DI_CLANG
538 return serialization::from_json_string<>(string_view).has_value();
539#endif
540 return true;
541 }
542 }
543
544 template<container::FixedString string>
546 constexpr auto operator""_json() {
548 return *serialization::from_json_string<>(string_view);
549 }
550 }
551}
552}
553
554#if !defined(DI_NO_GLOBALS) && !defined(DI_NO_GLOBAL_JSON_LITERALS)
555using namespace di::literals::json_literals;
556#endif
557
558namespace di {
560
563}
Definition string_reader.h:18
A deserializer for the JSON format.
Definition json_serializer.h:355
constexpr auto reader() &-> Reader &
Definition json_deserializer.h:214
constexpr auto deserialize(InPlaceType< T >, M) -> Result< T >
Definition json_deserializer.h:130
constexpr auto deserialize(InPlaceType< T >, M fields) -> Result< T >
Definition json_deserializer.h:55
constexpr auto deserialize(InPlaceType< T >, M) -> Result< T >
Definition json_deserializer.h:148
constexpr auto deserialize(InPlaceType< T >, M enumerators) -> Result< T >
Definition json_deserializer.h:106
constexpr JsonDeserializer(T &&reader)
Definition json_deserializer.h:46
JsonFormat DeserializationFormat
Definition json_deserializer.h:42
constexpr auto reader() &&-> Reader &&
Definition json_deserializer.h:216
constexpr auto reader() const &-> Reader const &
Definition json_deserializer.h:215
constexpr auto deserialize(InPlaceType< json::Null >) -> Result< json::Null >
Definition json_deserializer.h:208
constexpr auto deserialize(InPlaceType< T >, M) -> Result< T >
Definition json_deserializer.h:177
constexpr auto deserialize(InPlaceType< json::Value >) -> Result< json::Value >
Definition json_deserializer.h:48
Definition operations.h:11
Definition deserialize.h:153
Definition vocab.h:77
Definition core.h:114
#define DI_TRY(...)
Definition monad_try.h:13
string::StringViewImpl< string::Utf8Encoding > StringView
Definition string_view.h:12
constexpr auto fixed_string_to_utf8_string_view
Definition fixed_string_to_utf8_string_view.h:32
constexpr auto value
Definition value.h:34
constexpr auto read_some
Definition reader.h:32
meta::List< ReadSome > Reader
Definition reader.h:34
Definition json_deserializer.h:532
consteval auto valid_json_literal() -> bool
Definition json_deserializer.h:534
Definition json_deserializer.h:531
T::Type Type
Definition core.h:26
meta::RemoveCVRef< T >::Value OptionalValue
Definition vocab.h:82
meta::LikeExpected< decltype(io::read_some(util::declval< Reader & >(), util::declval< Span< Byte > >())), T > ReaderResult
Definition reader.h:39
decltype(vocab::tuple_element(types::in_place_type< meta::RemoveReference< T > >, c_< index >))::Type TupleElement
Definition tuple_element.h:21
IteratorValue< ContainerIterator< T > > ContainerValue
Definition container_value.h:8
constexpr auto code_point
Definition code_point_parser.h:35
constexpr auto parse
Definition parse.h:23
Definition binary_deserializer.h:137
constexpr auto null
Definition json_value.h:51
container::String String
Definition json_value.h:58
container::TreeMap< container::String, Value > Object
Definition json_value.h:60
container::Vector< Value > Array
Definition json_value.h:59
Definition binary_deserializer.h:33
constexpr auto from_json_string
Definition json_deserializer.h:510
JsonDeserializer(T &&) -> JsonDeserializer< T >
constexpr auto deserialize_json
Definition json_deserializer.h:526
constexpr auto json_format
Definition json_serializer.h:371
constexpr auto deserialize_string
Definition deserialize_string.h:27
constexpr auto deserialize
Definition deserialize.h:178
char32_t c32
Definition char.h:6
constexpr auto exchange(T &object, U &&new_value) -> T
Definition exchange.h:8
Array(T, U...) -> Array< T, 1+sizeof...(U)>
Expected< T, Error > Result
Definition result.h:8
constexpr auto nullopt
Definition nullopt.h:15
constexpr auto tuple_sequence
Definition tuple_sequence.h:36
constexpr void tuple_for_each(F &&function, Tup &&tuple)
Definition tuple_for_each.h:22
Unexpected(E &&) -> Unexpected< meta::UnwrapRefDecay< E > >
Definition zstring_parser.h:9
constexpr auto empty
Definition empty.h:45
constexpr auto ref
Definition reference_wrapper.h:98
constexpr auto enumerator
Definition enumerator.h:36
constexpr auto field
Definition field.h:42
constexpr auto in_place_type
Definition in_place_type.h:12
@ U
Definition key.h:30
Definition json_serializer.h:357
Definition json_deserializer.h:514
Definition json_deserializer.h:499
Definition in_place_type.h:5