Gaia-ECS v1.0.0
A simple and powerful entity component system
Loading...
Searching...
No Matches
ser_json.h
1#pragma once
2#include "gaia/config/config.h"
3
4#if GAIA_JSON_ENABLED
5
6 #include <cctype>
7 #include <cmath>
8 #include <cstdint>
9 #include <cstdio>
10 #include <cstdlib>
11 #include <cstring>
12 #include <limits>
13 #include <type_traits>
14
15 #include "gaia/cnt/darray.h"
16 #include "gaia/core/utility.h"
17 #include "gaia/ser/ser_buffer_binary.h"
18 #include "gaia/util/str.h"
19
20namespace gaia {
21 namespace ser {
23 using json_str_view = util::str_view;
25 using json_str = util::str;
26
28 enum JsonSaveFlags : uint32_t {
30 None = 0,
32 BinarySnapshot = 1u << 0,
34 RawFallback = 1u << 1,
36 Default = BinarySnapshot | RawFallback
37 };
38
41 struct RuntimeJsonPolicy final {
43 bool symbolicEnums = false;
45 bool symbolicBitmasks = false;
46 };
47
49 enum class JsonDiagSeverity : uint8_t {
51 Info,
53 Warning,
55 Error
56 };
58 enum class JsonDiagReason : uint8_t {
60 None,
62 UnknownField,
64 FieldOutOfBounds,
66 FieldValueAdjusted,
68 TagValueIgnored,
70 NullComponentPayload,
72 MissingRuntimeFieldsOrRawPayload,
74 SoaRawUnsupported,
76 UnknownComponent,
78 TagComponentUnsupported,
80 DuplicateEntityName,
82 MissingComponentStorage,
84 MissingArchetypesSection,
86 MissingFormatField,
88 UnsupportedFormatVersion,
90 InvalidJson,
92 UnknownRuntimeConstant,
94 InvalidRuntimeConstant,
96 InvalidPatchPath,
98 ReadOnlyField,
100 HiddenField,
102 UnsupportedPatchValue,
104 RangeViolation,
106 StaleSchema
107 };
108
110 struct JsonDiagnostic {
112 JsonDiagSeverity severity = JsonDiagSeverity::Warning;
114 JsonDiagReason reason = JsonDiagReason::None;
116 json_str path;
118 json_str message;
119 };
120
122 struct JsonDiagnostics {
124 static constexpr uint32_t MaxDiagPathLength = 1024;
126 static constexpr uint32_t MaxDiagMessageLength = 2048;
127
129 cnt::darray<JsonDiagnostic> items;
131 bool hasWarnings = false;
133 bool hasErrors = false;
134
140 void add(JsonDiagSeverity severity, JsonDiagReason reason, json_str_view path, json_str_view message) {
141 JsonDiagnostic diag;
142 diag.severity = severity;
143 diag.reason = reason;
144 diag.path.assign(path);
145 diag.message.assign(message);
146 items.push_back(diag);
147
148 if (severity == JsonDiagSeverity::Warning)
149 hasWarnings = true;
150 else if (severity == JsonDiagSeverity::Error)
151 hasErrors = true;
152 }
158 void add(JsonDiagSeverity severity, JsonDiagReason reason, json_str_view path, const char* message) {
159 add(severity, reason, path, json_str_view(message, (uint32_t)GAIA_STRLEN(message, MaxDiagMessageLength)));
160 }
166 void add(JsonDiagSeverity severity, JsonDiagReason reason, const char* path, const char* message) {
167 add(severity, reason, json_str_view(path, (uint32_t)GAIA_STRLEN(path, MaxDiagPathLength)),
168 json_str_view(message, (uint32_t)GAIA_STRLEN(message, MaxDiagMessageLength)));
169 }
170
173 GAIA_NODISCARD bool has_issues() const {
174 return hasWarnings || hasErrors;
175 }
176
177 void clear() {
178 items.clear();
179 hasWarnings = false;
180 hasErrors = false;
181 }
182 };
183
188 class ser_json {
189 static constexpr uint32_t MaxImplicitKeyLength = 384;
190 static constexpr uint32_t MaxImplicitStringLength = 16u * 1024u * 1024u;
191 static constexpr uint32_t MaxLiteralLength = 256u;
192
193 enum class CtxType : uint8_t { Object, Array };
194
195 struct Ctx {
196 CtxType type = CtxType::Object;
197 bool first = true;
198 bool needsValue = false;
199 };
200
201 json_str m_out;
202 json_str m_parseScratch;
203 cnt::darray<Ctx> m_ctx;
204 const char* m_it = nullptr;
205 const char* m_end = nullptr;
206
207 GAIA_NODISCARD static bool parse_hex_quad(const char* str, uint32_t& value) {
208 value = 0;
209 GAIA_FOR(4) {
210 const char ch = str[i];
211 uint32_t digit = 0;
212 if (ch >= '0' && ch <= '9')
213 digit = (uint32_t)(ch - '0');
214 else if (ch >= 'a' && ch <= 'f')
215 digit = (uint32_t)(ch - 'a') + 10;
216 else if (ch >= 'A' && ch <= 'F')
217 digit = (uint32_t)(ch - 'A') + 10;
218 else
219 return false;
220 value = (value << 4U) | digit;
221 }
222 return true;
223 }
224
225 static void append_utf8(json_str& out, uint32_t codePoint) {
226 if (codePoint <= 0x7fU) {
227 out.append((char)codePoint);
228 } else if (codePoint <= 0x7ffU) {
229 out.append((char)(0xc0U | (codePoint >> 6U)));
230 out.append((char)(0x80U | (codePoint & 0x3fU)));
231 } else if (codePoint <= 0xffffU) {
232 out.append((char)(0xe0U | (codePoint >> 12U)));
233 out.append((char)(0x80U | ((codePoint >> 6U) & 0x3fU)));
234 out.append((char)(0x80U | (codePoint & 0x3fU)));
235 } else {
236 out.append((char)(0xf0U | (codePoint >> 18U)));
237 out.append((char)(0x80U | ((codePoint >> 12U) & 0x3fU)));
238 out.append((char)(0x80U | ((codePoint >> 6U) & 0x3fU)));
239 out.append((char)(0x80U | (codePoint & 0x3fU)));
240 }
241 }
242
243 static void add_escaped(json_str& out, const char* str, uint32_t len) {
244 GAIA_FOR(len) {
245 const char ch = str[i];
246 switch (ch) {
247 case '"':
248 out.append("\\\"");
249 break;
250 case '\\':
251 out.append("\\\\");
252 break;
253 case '\n':
254 out.append("\\n");
255 break;
256 case '\r':
257 out.append("\\r");
258 break;
259 case '\t':
260 out.append("\\t");
261 break;
262 default:
263 out.append(ch);
264 break;
265 }
266 }
267 }
268
269 void before_value() {
270 if (m_ctx.empty())
271 return;
272
273 auto& ctx = m_ctx.back();
274 if (ctx.type == CtxType::Array) {
275 if (!ctx.first)
276 m_out.append(",");
277 ctx.first = false;
278 } else {
279 GAIA_ASSERT(ctx.needsValue);
280 ctx.needsValue = false;
281 }
282 }
283
284 public:
285 ser_json() = default;
286
289 ser_json(const char* json, uint32_t len) {
290 reset_input(json, len);
291 }
295 template <size_t N>
296 explicit ser_json(const char (&json)[N]) {
297 static_assert(N > 0);
298 reset_input(json, (uint32_t)(N - 1));
299 }
300
304 void reset_input(const char* json, uint32_t len) {
305 if (json == nullptr) {
306 m_it = nullptr;
307 m_end = nullptr;
308 return;
309 }
310
311 m_it = json;
312 m_end = json + len;
313 }
317 template <size_t N>
318 void reset_input(const char (&json)[N]) {
319 static_assert(N > 0);
320 reset_input(json, (uint32_t)(N - 1));
321 }
322
324 void clear() {
325 m_out.clear();
326 m_parseScratch.clear();
327 m_ctx.clear();
328 }
329
332 GAIA_NODISCARD const json_str& str() const {
333 return m_out;
334 }
335
338 GAIA_NODISCARD bool eof() const {
339 return m_it == nullptr || m_end == nullptr || m_it >= m_end;
340 }
341
344 GAIA_NODISCARD char peek() const {
345 GAIA_ASSERT(m_it != nullptr && m_it < m_end);
346 return *m_it;
347 }
348
350 void ws() {
351 if (m_it == nullptr || m_end == nullptr)
352 return;
353 while (m_it < m_end && std::isspace((unsigned char)*m_it))
354 ++m_it;
355 }
356
357 GAIA_NODISCARD const char* pos() const {
358 return m_it;
359 }
360
361 GAIA_NODISCARD const char* end() const {
362 return m_end;
363 }
364
365 void begin_object() {
366 before_value();
367 m_out.append("{");
368 m_ctx.push_back({CtxType::Object, true, false});
369 }
370
371 void end_object() {
372 GAIA_ASSERT(!m_ctx.empty() && m_ctx.back().type == CtxType::Object);
373 m_ctx.pop_back();
374 m_out.append("}");
375 }
376
377 void begin_array() {
378 before_value();
379 m_out.append("[");
380 m_ctx.push_back({CtxType::Array, true, false});
381 }
382
383 void end_array() {
384 GAIA_ASSERT(!m_ctx.empty() && m_ctx.back().type == CtxType::Array);
385 m_ctx.pop_back();
386 m_out.append("]");
387 }
388
389 void key(const char* name, uint32_t len = 0) {
390 GAIA_ASSERT(name != nullptr);
391 GAIA_ASSERT(!m_ctx.empty() && m_ctx.back().type == CtxType::Object);
392 auto& ctx = m_ctx.back();
393 GAIA_ASSERT(!ctx.needsValue);
394
395 if (!ctx.first)
396 m_out.append(",");
397 ctx.first = false;
398 ctx.needsValue = true;
399
400 const auto l = len == 0 ? (uint32_t)GAIA_STRLEN(name, MaxImplicitKeyLength) : len;
401 m_out.append("\"");
402 add_escaped(m_out, name, l);
403 m_out.append("\":");
404 }
405
406 void value_null() {
407 before_value();
408 m_out.append("null");
409 }
410
411 void value_bool(bool v) {
412 before_value();
413 if (v)
414 m_out.append("true");
415 else
416 m_out.append("false");
417 }
418
419 template <typename TInt, typename = std::enable_if_t<std::is_integral_v<TInt> && !std::is_same_v<TInt, bool>>>
420 void value_int(TInt v) {
421 before_value();
422
423 char buff[64];
424 if constexpr (std::is_signed_v<TInt>) {
425 (void)GAIA_STRFMT(buff, sizeof(buff), "%lld", (long long)v);
426 } else {
427 (void)GAIA_STRFMT(buff, sizeof(buff), "%llu", (unsigned long long)v);
428 }
429 m_out.append(buff, (uint32_t)GAIA_STRLEN(buff, (size_t)sizeof(buff)));
430 }
431
432 void value_float(float v) {
433 before_value();
434 char buff[64];
435 (void)GAIA_STRFMT(buff, sizeof(buff), "%.9g", (double)v);
436 m_out.append(buff, (uint32_t)GAIA_STRLEN(buff, (size_t)sizeof(buff)));
437 }
438
439 void value_float(double v) {
440 before_value();
441 char buff[64];
442 (void)GAIA_STRFMT(buff, sizeof(buff), "%.17g", v);
443 m_out.append(buff, (uint32_t)GAIA_STRLEN(buff, (size_t)sizeof(buff)));
444 }
445
446 void value_string(const char* str, uint32_t len = 0) {
447 GAIA_ASSERT(str != nullptr);
448 before_value();
449 const auto l = len == 0 ? (uint32_t)GAIA_STRLEN(str, MaxImplicitStringLength) : len;
450 m_out.append("\"");
451 add_escaped(m_out, str, l);
452 m_out.append("\"");
453 }
454
455 bool consume(char ch) {
456 ws();
457 if (m_it == nullptr || m_end == nullptr || m_it >= m_end || *m_it != ch)
458 return false;
459 ++m_it;
460 return true;
461 }
462
463 bool expect(char ch) {
464 return consume(ch);
465 }
466
467 bool parse_literal(const char* lit) {
468 ws();
469 if (m_it == nullptr || m_end == nullptr || lit == nullptr)
470 return false;
471
472 const auto litLen = (uint32_t)GAIA_STRLEN(lit, MaxLiteralLength);
473 if (litLen >= MaxLiteralLength)
474 return false;
475 if ((uint32_t)(m_end - m_it) < litLen)
476 return false;
477 if (memcmp(m_it, lit, litLen) != 0)
478 return false;
479 m_it += litLen;
480 return true;
481 }
482
483 bool parse_string_view(json_str_view& out, bool* fromScratch = nullptr) {
484 ws();
485 if (m_it == nullptr || m_end == nullptr || m_it >= m_end || *m_it != '"')
486 return false;
487
488 ++m_it;
489 const char* begin = m_it;
490 bool escaped = false;
491 m_parseScratch.clear();
492 while (m_it < m_end) {
493 const char ch = *m_it++;
494 if (ch == '"')
495 break;
496
497 if (ch == '\\') {
498 if (!escaped) {
499 escaped = true;
500 const auto prefixLen = (size_t)((m_it - 1) - begin);
501 if (prefixLen > 0)
502 m_parseScratch.append(begin, (uint32_t)prefixLen);
503 }
504
505 if (m_it >= m_end)
506 return false;
507 const char esc = *m_it++;
508 switch (esc) {
509 case '"':
510 case '\\':
511 case '/':
512 m_parseScratch.append(esc);
513 break;
514 case 'b':
515 m_parseScratch.append('\b');
516 break;
517 case 'f':
518 m_parseScratch.append('\f');
519 break;
520 case 'n':
521 m_parseScratch.append('\n');
522 break;
523 case 'r':
524 m_parseScratch.append('\r');
525 break;
526 case 't':
527 m_parseScratch.append('\t');
528 break;
529 case 'u': {
530 if ((uint32_t)(m_end - m_it) < 4)
531 return false;
532 uint32_t codePoint = 0;
533 if (!parse_hex_quad(m_it, codePoint))
534 return false;
535 m_it += 4;
536 if (codePoint >= 0xd800U && codePoint <= 0xdbffU) {
537 if ((uint32_t)(m_end - m_it) < 6 || m_it[0] != '\\' || m_it[1] != 'u')
538 return false;
539 uint32_t low = 0;
540 if (!parse_hex_quad(m_it + 2, low) || low < 0xdc00U || low > 0xdfffU)
541 return false;
542 m_it += 6;
543 codePoint = 0x10000U + ((codePoint - 0xd800U) << 10U) + (low - 0xdc00U);
544 } else if (codePoint >= 0xdc00U && codePoint <= 0xdfffU) {
545 return false;
546 }
547 append_utf8(m_parseScratch, codePoint);
548 break;
549 }
550 default:
551 return false;
552 }
553 } else if (escaped)
554 m_parseScratch.append(ch);
555 }
556
557 if (m_it <= begin || m_it > m_end || *(m_it - 1) != '"')
558 return false;
559
560 if (escaped) {
561 if (fromScratch != nullptr)
562 *fromScratch = true;
563 out = m_parseScratch.view();
564 } else {
565 if (fromScratch != nullptr)
566 *fromScratch = false;
567 out = json_str_view(begin, (uint32_t)((m_it - 1) - begin));
568 }
569 return true;
570 }
571
572 bool parse_string(json_str& out) {
573 json_str_view view;
574 if (!parse_string_view(view))
575 return false;
576 out.assign(view);
577 return true;
578 }
579
580 bool parse_string_eq(const char* literal) {
581 json_str_view view;
582 if (!parse_string_view(view))
583 return false;
584 const auto literalLen = (size_t)GAIA_STRLEN(literal, MaxLiteralLength);
585 if (literalLen >= MaxLiteralLength)
586 return false;
587 return view.size() == literalLen && memcmp(view.data(), literal, literalLen) == 0;
588 }
589
599 bool
600 parse_integer_token(bool& negative, uint64_t& magnitude, bool& overflow, bool& adjusted, bool& integerToken) {
601 ws();
602 negative = false;
603 magnitude = 0;
604 overflow = false;
605 adjusted = false;
606 integerToken = false;
607 if (m_it == nullptr || m_end == nullptr || m_it >= m_end)
608 return false;
609
610 const char* p = m_it;
611 if (*p == '-') {
612 negative = true;
613 ++p;
614 }
615 if (p >= m_end || *p < '0' || *p > '9')
616 return false;
617 const char* digitsBegin = p;
618 if (*p == '0' && p + 1 < m_end && p[1] >= '0' && p[1] <= '9')
619 return false;
620
621 constexpr uint64_t MaxValue = (std::numeric_limits<uint64_t>::max)();
622 while (p < m_end && *p >= '0' && *p <= '9') {
623 const auto digit = (uint64_t)(*p - '0');
624 if (magnitude > (MaxValue - digit) / 10)
625 overflow = true;
626 else if (!overflow)
627 magnitude = magnitude * 10 + digit;
628 ++p;
629 }
630 const char* digitsEnd = p;
631
632 if (p < m_end && *p == '.') {
633 const char* decimalIt = p + 1;
634 if (decimalIt >= m_end || *decimalIt < '0' || *decimalIt > '9')
635 return false;
636 while (decimalIt < m_end && *decimalIt >= '0' && *decimalIt <= '9')
637 ++decimalIt;
638 if (decimalIt < m_end && (*decimalIt == 'e' || *decimalIt == 'E')) {
639 ++decimalIt;
640 if (decimalIt < m_end && (*decimalIt == '+' || *decimalIt == '-'))
641 ++decimalIt;
642 if (decimalIt >= m_end || *decimalIt < '0' || *decimalIt > '9')
643 return false;
644 }
645 return true;
646 }
647 if (p < m_end && (*p == 'e' || *p == 'E')) {
648 const char* exponentIt = p + 1;
649 bool negativeExponent = false;
650 if (exponentIt < m_end && (*exponentIt == '+' || *exponentIt == '-')) {
651 negativeExponent = *exponentIt == '-';
652 ++exponentIt;
653 }
654 if (exponentIt >= m_end || *exponentIt < '0' || *exponentIt > '9')
655 return false;
656
657 uint32_t exponent = 0;
658 bool exponentOverflow = false;
659 while (exponentIt < m_end && *exponentIt >= '0' && *exponentIt <= '9') {
660 const auto digit = (uint32_t)(*exponentIt - '0');
661 if (exponent > (UINT32_MAX - digit) / 10)
662 exponentOverflow = true;
663 else if (!exponentOverflow)
664 exponent = exponent * 10 + digit;
665 ++exponentIt;
666 }
667
668 if (negativeExponent && (exponentOverflow || exponent != 0)) {
669 const auto digitCount = (uint32_t)(digitsEnd - digitsBegin);
670 const auto keptCount = exponentOverflow || exponent >= digitCount ? 0U : digitCount - exponent;
671 magnitude = 0;
672 overflow = false;
673 for (uint32_t i = 0; i < keptCount; ++i) {
674 const auto digit = (uint64_t)(digitsBegin[i] - '0');
675 if (magnitude > (MaxValue - digit) / 10)
676 overflow = true;
677 else if (!overflow)
678 magnitude = magnitude * 10 + digit;
679 }
680 for (uint32_t i = keptCount; i < digitCount; ++i)
681 adjusted = adjusted || digitsBegin[i] != '0';
682 } else if (exponentOverflow || exponent > 19) {
683 overflow = magnitude != 0;
684 } else {
685 while (exponent-- > 0) {
686 if (magnitude > MaxValue / 10) {
687 overflow = true;
688 break;
689 }
690 magnitude *= 10;
691 }
692 }
693 p = exponentIt;
694 }
695
696 if (overflow)
697 magnitude = MaxValue;
698
699 integerToken = true;
700 m_it = p;
701 return true;
702 }
703
704 bool parse_number(double& value) {
705 ws();
706 if (m_it == nullptr || m_end == nullptr || m_it >= m_end)
707 return false;
708
709 char* pEnd = nullptr;
710 value = std::strtod(m_it, &pEnd);
711 if (pEnd == m_it)
712 return false;
713 m_it = pEnd;
714 return true;
715 }
716
717 bool parse_bool(bool& value) {
718 if (parse_literal("true")) {
719 value = true;
720 return true;
721 }
722 if (parse_literal("false")) {
723 value = false;
724 return true;
725 }
726 return false;
727 }
728
729 bool parse_null() {
730 return parse_literal("null");
731 }
732
733 bool skip_value() {
734 ws();
735 if (m_it == nullptr || m_end == nullptr || m_it >= m_end)
736 return false;
737
738 if (*m_it == '{') {
739 ++m_it;
740 ws();
741 if (consume('}'))
742 return true;
743
744 while (true) {
745 json_str_view key;
746 if (!parse_string_view(key))
747 return false;
748 if (!expect(':'))
749 return false;
750 if (!skip_value())
751 return false;
752
753 ws();
754 if (consume(','))
755 continue;
756 if (consume('}'))
757 return true;
758 return false;
759 }
760 }
761
762 if (*m_it == '[') {
763 ++m_it;
764 ws();
765 if (consume(']'))
766 return true;
767
768 while (true) {
769 if (!skip_value())
770 return false;
771 ws();
772 if (consume(','))
773 continue;
774 if (consume(']'))
775 return true;
776 return false;
777 }
778 }
779
780 if (*m_it == '"') {
781 json_str_view tmp;
782 return parse_string_view(tmp);
783 }
784
785 if (*m_it == 't' || *m_it == 'f') {
786 bool v = false;
787 return parse_bool(v);
788 }
789
790 if (*m_it == 'n')
791 return parse_null();
792
793 double v = 0.0;
794 return parse_number(v);
795 }
796 };
797
798 namespace detail {
800 template <typename T>
801 inline void copy_field_bytes(uint8_t* pFieldData, uint32_t size, const T& v) {
802 memcpy(pFieldData, &v, size < sizeof(v) ? size : (uint32_t)sizeof(v));
803 }
804
805 template <typename TInt>
806 inline bool read_runtime_field_json_int(ser_json& reader, uint8_t* pFieldData, uint32_t size, bool& ok) {
807 bool negative = false;
808 uint64_t magnitude = 0;
809 bool overflow = false;
810 bool adjusted = false;
811 bool integerToken = false;
812 if (!reader.parse_integer_token(negative, magnitude, overflow, adjusted, integerToken))
813 return false;
814
815 if (integerToken) {
816 if (adjusted)
817 ok = false;
818 TInt value = 0;
819 if constexpr (std::is_signed_v<TInt>) {
820 constexpr auto MaxPositive = (uint64_t)(std::numeric_limits<TInt>::max)();
821 constexpr auto MaxNegative = MaxPositive + 1;
822 if (negative) {
823 if (overflow || magnitude > MaxNegative) {
824 value = (std::numeric_limits<TInt>::lowest)();
825 ok = false;
826 } else if (magnitude == MaxNegative) {
827 value = (std::numeric_limits<TInt>::lowest)();
828 } else {
829 value = (TInt) - (int64_t)magnitude;
830 }
831 } else if (overflow || magnitude > MaxPositive) {
832 value = (std::numeric_limits<TInt>::max)();
833 ok = false;
834 } else {
835 value = (TInt)magnitude;
836 }
837 } else {
838 constexpr auto MaxValue = (uint64_t)(std::numeric_limits<TInt>::max)();
839 if (negative) {
840 if (overflow || magnitude != 0)
841 ok = false;
842 } else if (overflow || magnitude > MaxValue) {
843 value = (std::numeric_limits<TInt>::max)();
844 ok = false;
845 } else {
846 value = (TInt)magnitude;
847 }
848 }
849
850 copy_field_bytes(pFieldData, size, value);
851 return true;
852 }
853
854 double d = 0.0;
855 if (!reader.parse_number(d))
856 return false;
857
858 if (!std::isfinite(d)) {
859 ok = false;
860 const TInt v = 0;
861 copy_field_bytes(pFieldData, size, v);
862 return true;
863 }
864
865 double clamped = std::trunc(d);
866 if (clamped != d)
867 ok = false;
868
869 constexpr auto minVal = (double)(std::numeric_limits<TInt>::lowest)();
870 constexpr auto maxVal = (double)(std::numeric_limits<TInt>::max)();
871 if (clamped < minVal) {
872 clamped = minVal;
873 ok = false;
874 } else if constexpr (sizeof(TInt) == sizeof(uint64_t)) {
875 if (clamped >= maxVal) {
876 const TInt v = (std::numeric_limits<TInt>::max)();
877 copy_field_bytes(pFieldData, size, v);
878 ok = false;
879 return true;
880 }
881 } else if (clamped > maxVal) {
882 clamped = maxVal;
883 ok = false;
884 }
885
886 const TInt v = (TInt)clamped;
887 copy_field_bytes(pFieldData, size, v);
888 return true;
889 }
890
891 template <typename TFloat>
892 inline bool read_runtime_field_json_float(ser_json& reader, uint8_t* pFieldData, uint32_t size, bool& ok) {
893 double d = 0.0;
894 if (!reader.parse_number(d))
895 return false;
896
897 if (!std::isfinite(d)) {
898 ok = false;
899 const TFloat v = (TFloat)0;
900 copy_field_bytes(pFieldData, size, v);
901 return true;
902 }
903
904 const TFloat v = (TFloat)d;
905 copy_field_bytes(pFieldData, size, v);
906 return true;
907 }
908
909 inline bool
910 write_runtime_field_json(ser_json& writer, const uint8_t* pFieldData, serialization_type_id type, uint32_t size) {
911 switch (type) {
912 case serialization_type_id::s8: {
913 int8_t v = 0;
914 memcpy(&v, pFieldData, sizeof(v));
915 writer.value_int(v);
916 return true;
917 }
918 case serialization_type_id::u8: {
919 uint8_t v = 0;
920 memcpy(&v, pFieldData, sizeof(v));
921 writer.value_int(v);
922 return true;
923 }
924 case serialization_type_id::s16: {
925 int16_t v = 0;
926 memcpy(&v, pFieldData, sizeof(v));
927 writer.value_int(v);
928 return true;
929 }
930 case serialization_type_id::u16: {
931 uint16_t v = 0;
932 memcpy(&v, pFieldData, sizeof(v));
933 writer.value_int(v);
934 return true;
935 }
936 case serialization_type_id::s32: {
937 int32_t v = 0;
938 memcpy(&v, pFieldData, sizeof(v));
939 writer.value_int(v);
940 return true;
941 }
942 case serialization_type_id::u32: {
943 uint32_t v = 0;
944 memcpy(&v, pFieldData, sizeof(v));
945 writer.value_int(v);
946 return true;
947 }
948 case serialization_type_id::s64: {
949 int64_t v = 0;
950 memcpy(&v, pFieldData, sizeof(v));
951 writer.value_int(v);
952 return true;
953 }
954 case serialization_type_id::u64: {
955 uint64_t v = 0;
956 memcpy(&v, pFieldData, sizeof(v));
957 writer.value_int(v);
958 return true;
959 }
960 case serialization_type_id::b: {
961 bool v = false;
962 memcpy(&v, pFieldData, sizeof(v));
963 writer.value_bool(v);
964 return true;
965 }
966 case serialization_type_id::f32: {
967 float v = 0.0f;
968 memcpy(&v, pFieldData, sizeof(v));
969 writer.value_float(v);
970 return true;
971 }
972 case serialization_type_id::f64: {
973 double v = 0.0;
974 memcpy(&v, pFieldData, sizeof(v));
975 writer.value_float(v);
976 return true;
977 }
978 case serialization_type_id::c8: {
979 const auto len = (uint32_t)GAIA_STRLEN((const char*)pFieldData, size);
980 writer.value_string((const char*)pFieldData, len);
981 return true;
982 }
983 default:
984 writer.value_null();
985 return false;
986 }
987 }
988
989 inline bool read_runtime_field_json(
990 ser_json& reader, uint8_t* pFieldData, serialization_type_id type, uint32_t size, bool& ok) {
991 if (reader.parse_null()) {
992 ok = false;
993 return true;
994 }
995
996 switch (type) {
997 case serialization_type_id::s8: {
998 return read_runtime_field_json_int<int8_t>(reader, pFieldData, size, ok);
999 }
1000 case serialization_type_id::u8: {
1001 return read_runtime_field_json_int<uint8_t>(reader, pFieldData, size, ok);
1002 }
1003 case serialization_type_id::s16: {
1004 return read_runtime_field_json_int<int16_t>(reader, pFieldData, size, ok);
1005 }
1006 case serialization_type_id::u16: {
1007 return read_runtime_field_json_int<uint16_t>(reader, pFieldData, size, ok);
1008 }
1009 case serialization_type_id::s32: {
1010 return read_runtime_field_json_int<int32_t>(reader, pFieldData, size, ok);
1011 }
1012 case serialization_type_id::u32: {
1013 return read_runtime_field_json_int<uint32_t>(reader, pFieldData, size, ok);
1014 }
1015 case serialization_type_id::s64: {
1016 return read_runtime_field_json_int<int64_t>(reader, pFieldData, size, ok);
1017 }
1018 case serialization_type_id::u64: {
1019 return read_runtime_field_json_int<uint64_t>(reader, pFieldData, size, ok);
1020 }
1021 case serialization_type_id::f32: {
1022 return read_runtime_field_json_float<float>(reader, pFieldData, size, ok);
1023 }
1024 case serialization_type_id::f64: {
1025 return read_runtime_field_json_float<double>(reader, pFieldData, size, ok);
1026 }
1027 case serialization_type_id::b: {
1028 bool v = false;
1029 if (!reader.parse_bool(v))
1030 return false;
1031 copy_field_bytes(pFieldData, size, v);
1032 return true;
1033 }
1034 case serialization_type_id::c8: {
1035 json_str_view str;
1036 if (!reader.parse_string_view(str))
1037 return false;
1038 if (size == 0) {
1039 ok = false;
1040 return true;
1041 }
1042
1043 memset(pFieldData, 0, size);
1044 const auto maxLen = size > 0 ? size - 1 : 0;
1045 const auto strLen = (uint32_t)str.size();
1046 const auto copyLen = strLen < maxLen ? strLen : maxLen;
1047 if (strLen > maxLen)
1048 ok = false;
1049 if (copyLen > 0)
1050 memcpy(pFieldData, str.data(), copyLen);
1051 return true;
1052 }
1053 default:
1054 ok = false;
1055 return reader.skip_value();
1056 }
1057 }
1058
1059 template <typename TByteSink>
1060 inline bool parse_json_byte_array(ser_json& reader, TByteSink& out) {
1061 if (!reader.expect('['))
1062 return false;
1063
1064 reader.ws();
1065 if (reader.consume(']'))
1066 return true;
1067
1068 while (true) {
1069 double d = 0.0;
1070 if (!reader.parse_number(d))
1071 return false;
1072 if (d < 0.0 || d > 255.0)
1073 return false;
1074
1075 const auto v = (uint32_t)d;
1076 if ((double)v != d)
1077 return false;
1078
1079 const uint8_t byte = (uint8_t)v;
1080 out.save_raw(&byte, 1, serialization_type_id::u8);
1081
1082 reader.ws();
1083 if (reader.consume(','))
1084 continue;
1085 if (reader.consume(']'))
1086 return true;
1087 return false;
1088 }
1089 }
1091 } // namespace detail
1092 } // namespace ser
1093} // namespace gaia
1094
1095#endif