FastLED 3.9.15
Loading...
Searching...
No Matches
types.h
Go to the documentation of this file.
1#pragma once
2
3// JSON implementation types and helpers
4// Internal header - do not include directly, use fl/stl/json.h instead
5
6#include "fl/stl/int.h"
7#include "fl/stl/string.h"
8#include "fl/stl/vector.h"
9#include "fl/stl/flat_map.h"
10#include "fl/stl/variant.h"
11#include "fl/stl/optional.h"
12#include "fl/stl/shared_ptr.h"
13#include "fl/stl/cctype.h"
14#include "fl/stl/charconv.h"
15#include "fl/stl/limits.h"
16#include "fl/stl/cstddef.h"
17#include "fl/stl/move.h"
18#include "fl/stl/strstream.h"
19#include "fl/stl/span.h"
20#include "fl/stl/type_traits.h"
21#include "fl/log/log.h"
22#include "fl/task/promise.h" // For fl::task::Error type
23#include "fl/stl/string_view.h"
24
25#include "fl/stl/noexcept.h"
26
27namespace fl {
28
29struct json_value;
30
31// Define Array and Object as pointers to avoid incomplete type issues
32// We'll use heap-allocated containers for these to avoid alignment issues
35
36// parse_result struct to replace variant<T, task::Error>
37template<typename T>
41
42 parse_result(const T& val) FL_NOEXCEPT : value(val), error() {}
44
45 bool has_error() const FL_NOEXCEPT { return !error.is_empty(); }
46 const T& get_value() const FL_NOEXCEPT { return value; }
47 const task::Error& get_error() const FL_NOEXCEPT { return error; }
48
49 // Implicit conversion operator to allow using parse_result as T directly
50 operator const T&() const FL_NOEXCEPT {
51 if (has_error()) {
52 // This should ideally trigger some kind of error handling
53 // For now, we'll just return the value (which might be default-initialized)
54 }
55 return value;
56 }
57};
58
59// Function to get a reference to a static null json_value
61
62// Function to get a reference to a static empty json_object
64
65// AI - pay attention to this - implementing visitor pattern
66template<typename T>
68 const T& fallback;
69 const T* result = nullptr;
70 T storage; // Use instance storage instead of static
71
73
74 // This is the method that fl::variant expects
75 template<typename U>
76 void accept(const U& value) FL_NOEXCEPT {
77 // Dispatch to the correct operator() overload
78 (*this)(value);
79 }
80
81 // Specific overload for the type T
82 void operator()(const T& value) FL_NOEXCEPT {
83 result = &value;
84 }
85
86 // Special handling for integer conversions
87 template<typename U>
90 // Convert between integer types
91 storage = static_cast<T>(value);
92 result = &storage;
93 }
94
95 // Special handling for floating point to integer conversion
96 template<typename U>
99 // Convert float to integer
100 storage = static_cast<T>(value);
101 result = &storage;
102 }
103
104 // Special handling for integer to floating point conversion
105 template<typename U>
108 // Convert integer to float
109 storage = static_cast<T>(value);
110 result = &storage;
111 }
112
113 // Special handling for floating point to floating point conversion
114 template<typename U>
117 // Convert between floating point types (e.g., double to float)
118 storage = static_cast<T>(value);
119 result = &storage;
120 }
121
122 // Generic overload for all other types
123 template<typename U>
124 typename fl::enable_if<
129 void>::type
130 operator()(const U&) {
131 // Do nothing for other types
132 }
133
134 // Special handling for nullptr_t
136 // Do nothing - will return fallback
137 }
138};
139
140// Visitor for converting values to int
141template<typename IntType = i64>
144
145 template<typename U>
146 void accept(const U& value) FL_NOEXCEPT {
147 // Dispatch to the correct operator() overload
148 (*this)(value);
149 }
150
151 // Special handling to avoid conflict when IntType is i64
152 template<typename T = IntType>
154 operator()(const IntType& value) FL_NOEXCEPT {
155 result = value;
156 }
157
158 // Special handling for i64 case
159 template<typename T = IntType>
162 result = value;
163 }
164
165 // Special handling for double case (when IntType is double)
166 template<typename T = IntType>
168 operator()(const double& value) FL_NOEXCEPT {
169 result = value;
170 }
171
172 // Special handling to avoid conflict when IntType is i64
173 // With overflow detection and logging
174 template<typename T = IntType>
177 // Check for overflow before casting
178 // For signed types: check if value is within [min, max] range
179 // For unsigned types: check if value is non-negative and within [0, max] range
180 // Use parentheses around min/max to protect against Arduino min/max macros
181 const i64 min_val = static_cast<i64>((fl::numeric_limits<IntType>::min)());
182 const i64 max_val = static_cast<i64>((fl::numeric_limits<IntType>::max)());
183
184 if (value < min_val || value > max_val) {
185 // Log overflow error but still perform conversion (value will be truncated)
186 FL_ERROR("JSON integer overflow: value " << value << " does not fit in target type (range: "
187 << min_val << " to " << max_val << "), truncating");
188 }
189
190 // Always perform conversion, even if overflow detected
191 result = static_cast<IntType>(value);
192 }
193
194 void operator()(const bool& value) FL_NOEXCEPT {
195 result = static_cast<IntType>(value ? 1 : 0);
196 }
197
198 // Special handling for float to int conversion
199 void operator()(const float& value) FL_NOEXCEPT {
200 // NEW INSTRUCTIONS: AUTO CONVERT FLOAT TO INT
201 result = static_cast<IntType>(value);
202 }
203
204 // Special handling for double to int conversion
205 template<typename T = IntType>
207 operator()(const double& value) FL_NOEXCEPT {
208 // NEW INSTRUCTIONS: AUTO CONVERT FLOAT TO INT
209 result = static_cast<IntType>(value);
210 }
211
213 // NEW INSTRUCTIONS: AUTO CONVERT STRING TO INT
214 // Try to parse the string as an integer using FastLED's StringFormatter
215 // Validate by checking if string contains only digits (and optional +/- sign)
216 bool isValidInt = true;
217 fl::size startPos = 0;
218
219 // Check for sign
220 if (str.length() > 0 && (str[0] == '+' || str[0] == '-')) {
221 startPos = 1;
222 }
223
224 // Check that all remaining characters are digits
225 for (fl::size i = startPos; i < str.length(); i++) {
226 if (!fl::isdigit(str[i])) {
227 isValidInt = false;
228 break;
229 }
230 }
231
232 // If it looks like a valid integer, try to parse it
233 if (isValidInt && str.length() > 0) {
234 int parsed = fl::parseInt(str.c_str(), str.length());
235 result = static_cast<IntType>(parsed);
236 }
237 }
238
239 template<typename T>
240 void operator()(const T&) FL_NOEXCEPT {
241 // Do nothing for other types
242 }
243};
244
245// Specialization for i64 to avoid template conflicts
246template<>
249
250 template<typename U>
251 void accept(const U& value) FL_NOEXCEPT {
252 // Dispatch to the correct operator() overload
253 (*this)(value);
254 }
255
257 result = value;
258 }
259
260 void operator()(const bool& value) FL_NOEXCEPT {
261 result = value ? 1 : 0;
262 }
263
264 void operator()(const float& value) FL_NOEXCEPT {
265 // AUTO CONVERT FLOAT TO INT. Route through int32 first to avoid the
266 // direct (i64)float cast — libgcc's `__aeabi_f2lz` helper internally
267 // chains through `_fixunssfdi.o` which anchors `__aeabi_dmul/dsub`
268 // (soft-double helpers, ~6 KB on no-FPU targets). See FastLED #3002.
269 // The variant only ever holds float (not double — see line 652), so
270 // JSON numbers fitting in int32 cover every value the parser
271 // currently emits; larger magnitudes saturate.
272 if (value > static_cast<float>(2147483647)) {
273 result = static_cast<i64>(2147483647);
274 } else if (value < static_cast<float>(-2147483648.0f)) {
275 result = static_cast<i64>(-2147483648LL);
276 } else {
277 result = static_cast<i64>(static_cast<fl::i32>(value));
278 }
279 }
280
281 void operator()(const double& value) FL_NOEXCEPT {
282 // Same #3002 reasoning — but the variant never holds `double`, so
283 // this overload is dead code in practice. Keep the direct cast for
284 // semantic completeness; LTO will remove it.
285 result = static_cast<i64>(value);
286 }
287
289 // NEW INSTRUCTIONS: AUTO CONVERT STRING TO INT
290 // Try to parse the string as an integer using FastLED's StringFormatter
291 // Validate by checking if string contains only digits (and optional +/- sign)
292 bool isValidInt = true;
293 fl::size startPos = 0;
294
295 // Check for sign
296 if (str.length() > 0 && (str[0] == '+' || str[0] == '-')) {
297 startPos = 1;
298 }
299
300 // Check that all remaining characters are digits
301 for (fl::size i = startPos; i < str.length(); i++) {
302 if (!fl::isdigit(str[i])) {
303 isValidInt = false;
304 break;
305 }
306 }
307
308 // If it looks like a valid integer, try to parse it
309 if (isValidInt && str.length() > 0) {
310 int parsed = fl::parseInt(str.c_str(), str.length());
311 result = static_cast<i64>(parsed);
312 }
313 }
314
315 template<typename T>
316 void operator()(const T&) FL_NOEXCEPT {
317 // Do nothing for other types
318 }
319};
320
321// Visitor for converting values to bool
324
325 template<typename U>
326 void accept(const U& value) FL_NOEXCEPT {
327 // Dispatch to the correct operator() overload
328 (*this)(value);
329 }
330
331 void operator()(const bool& value) FL_NOEXCEPT {
332 result = value;
333 }
334
336 // NEW INSTRUCTIONS: AUTO CONVERT INT TO BOOL
337 // 0 → false, non-zero → true
338 result = (value != 0);
339 }
340
341 void operator()(const float& value) FL_NOEXCEPT {
342 // NEW INSTRUCTIONS: AUTO CONVERT FLOAT TO BOOL
343 // 0.0 → false, non-zero → true
344 result = (value != 0.0f);
345 }
346
347 void operator()(const double& value) FL_NOEXCEPT {
348 // NEW INSTRUCTIONS: AUTO CONVERT DOUBLE TO BOOL
349 // 0.0 → false, non-zero → true
350 result = (value != 0.0);
351 }
352
354 // NEW INSTRUCTIONS: AUTO CONVERT STRING TO BOOL
355 // "true", "1", "yes", "on" (case insensitive) → true
356 // "false", "0", "no", "off" (case insensitive) → false
357 // Empty string → false
358 // Invalid string → nullopt
359
360 if (str.empty()) {
361 result = false;
362 return;
363 }
364
365 // Convert to lowercase for case-insensitive comparison
366 fl::string lower = str;
367 for (fl::size i = 0; i < lower.length(); i++) {
368 lower[i] = fl::tolower(lower[i]);
369 }
370
371 // Check for true values
372 if (lower == "true" || lower == "1" || lower == "yes" || lower == "on") {
373 result = true;
374 return;
375 }
376
377 // Check for false values
378 if (lower == "false" || lower == "0" || lower == "no" || lower == "off") {
379 result = false;
380 return;
381 }
382
383 // Invalid string - don't set result (leave as nullopt)
384 }
385
386 template<typename T>
387 void operator()(const T&) FL_NOEXCEPT {
388 // Do nothing for other types (arrays, objects, null)
389 }
390};
391
392// Visitor for converting values to float
393template<typename FloatType = double>
396
397 template<typename U>
398 void accept(const U& value) FL_NOEXCEPT {
399 // Dispatch to the correct operator() overload
400 (*this)(value);
401 }
402
403 void operator()(const FloatType& value) FL_NOEXCEPT {
404 result = value;
405 }
406
407 // Special handling to avoid conflict when FloatType is double
408 template<typename T = FloatType>
410 operator()(const double& value) FL_NOEXCEPT {
411 result = static_cast<FloatType>(value);
412 }
413
414 // Special handling to avoid conflict when FloatType is float
415 template<typename T = FloatType>
418 result = static_cast<FloatType>(value);
419 }
420
422 // AUTO CONVERT INT TO FLOAT. Route through int32 first to avoid the
423 // direct (FloatType)i64 cast — libgcc-nofp's `__aeabi_l2f` helper lives
424 // in `_floatdisf.o` which anchors `__aeabi_dadd / dmul / i2d / ui2d / d2f`
425 // (soft-double helpers, ~5 KB on no-FPU targets). Values fitting in
426 // int32 cover every value the integer-only LowMemory JSON-RPC contract
427 // emits; larger magnitudes saturate at INT32_MIN/MAX. See FastLED #3076.
428 if (value > 2147483647LL) {
429 result = static_cast<FloatType>(2147483647);
430 } else if (value < -2147483648LL) {
431 result = static_cast<FloatType>(-2147483648);
432 } else {
433 result = static_cast<FloatType>(static_cast<fl::i32>(value));
434 }
435 }
436
437 void operator()(const bool& value) FL_NOEXCEPT {
438 // Use float literals (1.0f / 0.0f), not double (1.0 / 0.0), to avoid
439 // pulling the soft-double helpers. See FastLED #3076.
440 result = static_cast<FloatType>(value ? 1.0f : 0.0f);
441 }
442
444 // NEW INSTRUCTIONS: AUTO CONVERT STRING TO FLOAT
445 // Try to parse the string as a float using FastLED's StringFormatter
446 // Validate by checking if string contains valid float characters
447 bool isValidFloat = true;
448 bool hasDecimal = false;
449 fl::size startPos = 0;
450
451 // Check for sign
452 if (str.length() > 0 && (str[0] == '+' || str[0] == '-')) {
453 startPos = 1;
454 }
455
456 // Check that all remaining characters are valid for a float
457 for (fl::size i = startPos; i < str.length(); i++) {
458 char c = str[i];
459 if (c == '.') {
460 if (hasDecimal) {
461 // Multiple decimal points
462 isValidFloat = false;
463 break;
464 }
465 hasDecimal = true;
466 } else if (!fl::isdigit(c) && c != 'e' && c != 'E') {
467 isValidFloat = false;
468 break;
469 }
470 }
471
472 // If it looks like a valid float, try to parse it
473 if (isValidFloat && str.length() > 0) {
474 // For simple cases, we can use a more precise approach
475 // Check if it's a simple decimal number
476 bool isSimpleDecimal = true;
477 for (fl::size i = startPos; i < str.length(); i++) {
478 char c = str[i];
479 if (c != '.' && !fl::isdigit(c)) {
480 isSimpleDecimal = false;
481 break;
482 }
483 }
484
485 if (isSimpleDecimal) {
486 // For simple decimals, we can do a more direct conversion
487 float parsed = fl::parseFloat(str.c_str(), str.length());
488 result = static_cast<FloatType>(parsed);
489 } else {
490 // For complex floats (with exponents), use the standard approach
491 float parsed = fl::parseFloat(str.c_str(), str.length());
492 result = static_cast<FloatType>(parsed);
493 }
494 }
495 }
496
497 template<typename T>
498 void operator()(const T&) FL_NOEXCEPT {
499 // Do nothing for other types
500 }
501};
502
503// Specialization for double to avoid template conflicts
504template<>
507
508 template<typename U>
509 void accept(const U& value) FL_NOEXCEPT {
510 // Dispatch to the correct operator() overload
511 (*this)(value);
512 }
513
514 void operator()(const double& value) FL_NOEXCEPT {
515 result = value;
516 }
517
518 void operator()(const float& value) FL_NOEXCEPT {
519 result = static_cast<double>(value);
520 }
521
523 // AUTO CONVERT INT TO FLOAT. Route through int32 to avoid pulling
524 // libgcc-nofp's `_floatdisf.o` soft-double cascade on no-FPU targets.
525 // The double path (`as_double()`) is DCE'd from LowMemory builds today,
526 // but keep the int32-route here as defense-in-depth. See FastLED #3076.
527 if (value > 2147483647LL) {
528 result = static_cast<double>(2147483647);
529 } else if (value < -2147483648LL) {
530 result = static_cast<double>(-2147483648);
531 } else {
532 result = static_cast<double>(static_cast<fl::i32>(value));
533 }
534 }
535
536 void operator()(const bool& value) FL_NOEXCEPT {
537 result = value ? 1.0 : 0.0;
538 }
539
541 // NEW INSTRUCTIONS: AUTO CONVERT STRING TO FLOAT
542 // Try to parse the string as a float using FastLED's StringFormatter
543 // Validate by checking if string contains valid float characters
544 bool isValidFloat = true;
545 bool hasDecimal = false;
546 fl::size startPos = 0;
547
548 // Check for sign
549 if (str.length() > 0 && (str[0] == '+' || str[0] == '-')) {
550 startPos = 1;
551 }
552
553 // Check that all remaining characters are valid for a float
554 for (fl::size i = startPos; i < str.length(); i++) {
555 char c = str[i];
556 if (c == '.') {
557 if (hasDecimal) {
558 // Multiple decimal points
559 isValidFloat = false;
560 break;
561 }
562 hasDecimal = true;
563 } else if (!fl::isdigit(c) && c != 'e' && c != 'E') {
564 isValidFloat = false;
565 break;
566 }
567 }
568
569 // If it looks like a valid float, try to parse it
570 if (isValidFloat && str.length() > 0) {
571 // For simple cases, we can use a more precise approach
572 // Check if it's a simple decimal number
573 bool isSimpleDecimal = true;
574 for (fl::size i = startPos; i < str.length(); i++) {
575 char c = str[i];
576 if (c != '.' && !fl::isdigit(c)) {
577 isSimpleDecimal = false;
578 break;
579 }
580 }
581
582 if (isSimpleDecimal) {
583 // For simple decimals, we can do a more direct conversion
584 float parsed = fl::parseFloat(str.c_str(), str.length());
585 result = static_cast<double>(parsed);
586 } else {
587 // For complex floats (with exponents), use the standard approach
588 float parsed = fl::parseFloat(str.c_str(), str.length());
589 result = static_cast<double>(parsed);
590 }
591 }
592 }
593
594 template<typename T>
595 void operator()(const T&) FL_NOEXCEPT {
596 // Do nothing for other types
597 }
598};
599
600// Visitor for converting values to string
603
604 template<typename U>
605 void accept(const U& value) FL_NOEXCEPT {
606 // Dispatch to the correct operator() overload
607 (*this)(value);
608 }
609
611 result = value;
612 }
613
615 // Convert integer to string
617 }
618
619 void operator()(const double& value) FL_NOEXCEPT {
620 // Convert double to string with higher precision for JSON representation
621 result = fl::to_string(static_cast<float>(value), 6);
622 }
623
624 void operator()(const float& value) FL_NOEXCEPT {
625 // Convert float to string with higher precision for JSON representation
627 }
628
629 void operator()(const bool& value) FL_NOEXCEPT {
630 // Convert bool to string
631 result = value ? "true" : "false";
632 }
633
635 // Convert null to string
636 result = "null";
637 }
638
639 template<typename T>
640 void operator()(const T&) FL_NOEXCEPT {
641 // Do nothing for other types (arrays, objects)
642 }
643};
644
645// Visitor for getting size of arrays and objects
647 size_t result = 0;
648
649 template<typename U>
650 void accept(const U& value) FL_NOEXCEPT {
651 // Dispatch to the correct operator() overload
652 (*this)(value);
653 }
654
655 void operator()(const json_array& arr) FL_NOEXCEPT { result = arr.size(); }
656 void operator()(const json_object& obj) FL_NOEXCEPT { result = obj.size(); }
657 void operator()(const fl::vector<i16>& vec) FL_NOEXCEPT { result = vec.size(); }
658 void operator()(const fl::vector<u8>& vec) FL_NOEXCEPT { result = vec.size(); }
659 void operator()(const fl::vector<float>& vec) FL_NOEXCEPT { result = vec.size(); }
660
661 // Generic fallback for other types (primitives, null)
663 void operator()(const bool&) FL_NOEXCEPT { result = 0; }
664 void operator()(const i64&) FL_NOEXCEPT { result = 0; }
665 void operator()(const float&) FL_NOEXCEPT { result = 0; }
667};
668
669// Forward declarations for visitors (defined after json_value)
670template<typename T> struct NumericExtractVisitor;
671template<typename T> struct CopyToVisitor;
672template<typename T, typename OutputIt> struct CopyToOutputIteratorVisitor;
673
674// The JSON node
676 // Forward declarations for nested iterator classes
677 class iterator;
678 class const_iterator;
679
680 // Friend declarations
681 friend class json;
682
683 // The variant holds exactly one of these alternatives
684 using variant_t = fl::variant<
685 fl::nullptr_t, // null
686 bool, // true/false
687 i64, // integer
688 float, // floating-point (changed from double to float)
689 fl::string, // string
690 json_array, // array
691 json_object, // object
692 fl::vector<i16>, // audio data (specialized array of int16_t)
693 fl::vector<u8>, // byte data (specialized array of uint8_t)
694 fl::vector<float> // float data (specialized array of float)
695 >;
696
699
701
702 // Constructors
707 // Explicit int/unsigned constructors to prevent ambiguity on platforms where
708 // int != i64 (e.g., 32-bit ARM with GCC). Without these, int is equally
709 // convertible to bool, i64, and float.
710 json_value(int i) FL_NOEXCEPT : data(static_cast<i64>(i)) {}
711 json_value(unsigned int i) FL_NOEXCEPT : data(static_cast<i64>(i)) {}
712 json_value(float f) FL_NOEXCEPT : data(f) {} // Changed from double to float
714 }
716 //FL_WARN("Created json_value with array");
717 }
719 //FL_WARN("Created json_value with object");
720 }
722 //FL_WARN("Created json_value with audio data");
723 }
724
726 //FL_WARN("Created json_value with moved audio data");
727 }
728
729 json_value(const fl::vector<u8>& bytes) FL_NOEXCEPT : data(bytes) {
730 //FL_WARN("Created json_value with byte data");
731 }
732
734 //FL_WARN("Created json_value with moved byte data");
735 }
736
737 json_value(const fl::vector<float>& floats) FL_NOEXCEPT : data(floats) {
738 //FL_WARN("Created json_value with float data");
739 }
740
742 //FL_WARN("Created json_value with moved float data");
743 }
744
745 // Copy constructor
746 json_value(const json_value& other) FL_NOEXCEPT : data(other.data) {}
747
749 data = other.data;
750 return *this;
751 }
752
754 data = fl::move(other.data);
755 return *this;
756 }
757
758 template<typename T>
762 return *this;
763 }
764
766 data = nullptr;
767 return *this;
768 }
769
771 data = b;
772 return *this;
773 }
774
776 data = i;
777 return *this;
778 }
779
781 data = static_cast<float>(d);
782 return *this;
783 }
784
786 data = f;
787 return *this;
788 }
789
791 data = fl::move(s);
792 return *this;
793 }
794
796 data = fl::move(a);
797 return *this;
798 }
799
804
806 data = fl::move(bytes);
807 return *this;
808 }
809
811 data = fl::move(floats);
812 return *this;
813 }
814
815 // Special constructor for char values
819
820 // Visitor pattern implementation
821 template<typename Visitor>
822 auto visit(Visitor&& visitor) FL_NOEXCEPT -> decltype(visitor(fl::nullptr_t{})) {
823 return data.visit(fl::forward<Visitor>(visitor));
824 }
825
826 template<typename Visitor>
827 auto visit(Visitor&& visitor) const FL_NOEXCEPT -> decltype(visitor(fl::nullptr_t{})) {
828 return data.visit(fl::forward<Visitor>(visitor));
829 }
830
831 // Type queries - using is<T>() instead of index() for fl::variant
832 bool is_null() const FL_NOEXCEPT {
833 //FL_WARN("is_null called, tag=" << data.tag());
834 return data.is<fl::nullptr_t>();
835 }
836 bool is_bool() const FL_NOEXCEPT {
837 //FL_WARN("is_bool called, tag=" << data.tag());
838 return data.is<bool>();
839 }
840 bool is_int() const FL_NOEXCEPT {
841 //FL_WARN("is_int called, tag=" << data.tag());
842 return data.is<i64>();
843 }
844 bool is_double() const FL_NOEXCEPT {
845 //FL_WARN("is_double called, tag=" << data.tag());
846 return data.is<float>();
847 }
848 bool is_float() const FL_NOEXCEPT {
849 return data.is<float>();
850 }
851 // is_number() returns true if the value is any numeric type (int or float)
852 bool is_number() const FL_NOEXCEPT {
853 return is_int() || is_float();
854 }
855 bool is_string() const FL_NOEXCEPT {
856 //FL_WARN("is_string called, tag=" << data.tag());
857 return data.is<fl::string>();
858 }
859 // Visitor for array type checking
861 bool result = false;
862
863 template<typename T>
864 void accept(const T& value) FL_NOEXCEPT {
865 // Dispatch to the correct operator() overload
866 (*this)(value);
867 }
868
869 // json_array is an array
871 result = true;
872 }
873
874 // Specialized array types ARE arrays
876 result = true; // Audio data is still an array
877 }
878
880 result = true; // Byte data is still an array
881 }
882
884 result = true; // Float data is still an array
885 }
886
887 // Generic handler for all other types
888 template<typename T>
889 void operator()(const T&) FL_NOEXCEPT {
890 result = false;
891 }
892 };
893
894 bool is_array() const FL_NOEXCEPT {
895 //FL_WARN("is_array called, tag=" << data.tag());
896 IsArrayVisitor visitor;
897 data.visit(visitor);
898 return visitor.result;
899 }
900
901 // Returns true only for json_array (not specialized array types)
903 return data.is<json_array>();
904 }
905
906 bool is_object() const FL_NOEXCEPT {
907 //FL_WARN("is_object called, tag=" << data.tag());
908 return data.is<json_object>();
909 }
910 bool is_audio() const FL_NOEXCEPT {
911 //FL_WARN("is_audio called, tag=" << data.tag());
912 return data.is<fl::vector<i16>>();
913 }
914 bool is_bytes() const FL_NOEXCEPT {
915 //FL_WARN("is_bytes called, tag=" << data.tag());
916 return data.is<fl::vector<u8>>();
917 }
918 bool is_floats() const FL_NOEXCEPT {
919 //FL_WARN("is_floats called, tag=" << data.tag());
920 return data.is<fl::vector<float>>();
921 }
922
923 // Safe extractors (return optional values, not references)
925 // Check if we have a valid value first
926 if (data.empty()) {
927 return fl::nullopt;
928 }
929
930 BoolConversionVisitor visitor;
931 data.visit(visitor);
932 return visitor.result;
933 }
934
936 // Check if we have a valid value first
937 if (data.empty()) {
938 return fl::nullopt;
939 }
940
942 data.visit(visitor);
943 return visitor.result;
944 }
945
946 template<typename IntType>
948 // Check if we have a valid value first
949 if (data.empty()) {
950 return fl::nullopt;
951 }
952
954 data.visit(visitor);
955 return visitor.result;
956 }
957
959 // Check if we have a valid value first
960 if (data.empty()) {
961 return fl::nullopt;
962 }
963
965 data.visit(visitor);
966 return visitor.result;
967 }
968
972
973 template<typename FloatType>
975 // Check if we have a valid value first
976 if (data.empty()) {
977 return fl::nullopt;
978 }
979
981 data.visit(visitor);
982 return visitor.result;
983 }
984
986 // Check if we have a valid value first
987 if (data.empty()) {
988 return fl::nullopt;
989 }
990
992 data.visit(visitor);
993 return visitor.result;
994 }
995
996 // Zero-copy pointer accessors (non-const)
999
1000 // Const overloads
1002 // Check if we have a valid value first
1003 if (data.empty()) {
1004 return fl::nullopt;
1005 }
1006
1007 BoolConversionVisitor visitor;
1008 data.visit(visitor);
1009 return visitor.result;
1010 }
1011
1013 // Check if we have a valid value first
1014 if (data.empty()) {
1015 return fl::nullopt;
1016 }
1017
1019 data.visit(visitor);
1020 return visitor.result;
1021 }
1022
1023 template<typename IntType>
1025 // Check if we have a valid value first
1026 if (data.empty()) {
1027 return fl::nullopt;
1028 }
1029
1031 data.visit(visitor);
1032 return visitor.result;
1033 }
1034
1038
1039 template<typename FloatType>
1041 // Check if we have a valid value first
1042 if (data.empty()) {
1043 return fl::nullopt;
1044 }
1045
1047 data.visit(visitor);
1048 return visitor.result;
1049 }
1050
1052 // Check if we have a valid value first
1053 if (data.empty()) {
1054 return fl::nullopt;
1055 }
1056
1058 data.visit(visitor);
1059 return visitor.result;
1060 }
1061
1062 // Zero-copy pointer accessors (const)
1063 const json_array* as_array() const FL_NOEXCEPT { return data.ptr<json_array>(); }
1064 const json_object* as_object() const FL_NOEXCEPT { return data.ptr<json_object>(); }
1065
1066 // Explicit copy methods - use when you need an owned copy or packed-array conversion
1068 auto ptr = data.ptr<json_array>();
1069 if (ptr) return fl::optional<json_array>(*ptr);
1070 // Handle specialized array types by converting them to regular json_array
1071 if (data.is<fl::vector<i16>>()) {
1072 auto audioPtr = data.ptr<fl::vector<i16>>();
1074 for (const auto& item : *audioPtr) {
1075 result.push_back(fl::make_shared<json_value>(static_cast<i64>(item)));
1076 }
1078 }
1079 if (data.is<fl::vector<u8>>()) {
1080 auto bytePtr = data.ptr<fl::vector<u8>>();
1082 for (const auto& item : *bytePtr) {
1083 result.push_back(fl::make_shared<json_value>(static_cast<i64>(item)));
1084 }
1086 }
1087 if (data.is<fl::vector<float>>()) {
1088 auto floatPtr = data.ptr<fl::vector<float>>();
1090 for (const auto& item : *floatPtr) {
1091 result.push_back(fl::make_shared<json_value>(item));
1092 }
1094 }
1095 return fl::nullopt;
1096 }
1098 auto ptr = data.ptr<json_object>();
1099 return ptr ? fl::optional<json_object>(*ptr) : fl::nullopt;
1100 }
1101
1102 // Copy packed-array elements into a caller-owned span with type conversion.
1103 // Returns number of elements copied (min of array size and span size).
1104 // Returns 0 if this value is not a numeric array.
1105 template<typename T>
1106 size_t copy_to(fl::span<T> out) const FL_NOEXCEPT {
1107 CopyToVisitor<T> visitor(out);
1108 data.visit(visitor);
1109 return visitor.result;
1110 }
1111
1112 // Stream packed-array elements into an output iterator with type conversion.
1113 // Use with fl::back_inserter(container) to append to any container.
1114 // Returns number of elements written. Returns 0 if not a numeric array.
1115 template<typename T, typename OutputIt>
1116 size_t copy_to_output_iterator(OutputIt out) const FL_NOEXCEPT {
1118 data.visit(visitor);
1119 return visitor.result;
1120 }
1121
1122 // Overload for back_insert_iterator: T deduced from container's value_type
1123 template<typename Container>
1125 using T = typename Container::value_type;
1127 data.visit(visitor);
1128 return visitor.result;
1129 }
1130
1131 // Generic getter template method
1132 template<typename T>
1134 auto ptr = data.ptr<T>();
1135 return ptr ? fl::optional<T>(*ptr) : fl::nullopt;
1136 }
1137
1138 template<typename T>
1140 auto ptr = data.ptr<T>();
1141 return ptr ? fl::optional<T>(*ptr) : fl::nullopt;
1142 }
1143
1144 // Iterator support for objects and arrays
1146 if (is_object()) {
1147 auto ptr = data.ptr<json_object>();
1148 return iterator(ptr->begin());
1149 }
1150 // Use temporary empty object to avoid static initialization conflicts with Teensy
1151 return iterator(json_object().begin());
1152 }
1153
1155 if (is_object()) {
1156 auto ptr = data.ptr<json_object>();
1157 return iterator(ptr->end());
1158 }
1159 // Use temporary empty object to avoid static initialization conflicts with Teensy
1160 return iterator(json_object().end());
1161 }
1162
1164 if (is_object()) {
1165 auto ptr = data.ptr<const json_object>();
1166 if (!ptr) return const_iterator::from_iterator(json_object().begin());
1167 return const_iterator::from_iterator(ptr->begin());
1168 }
1169 // Use temporary empty object to avoid static initialization conflicts with Teensy
1171 }
1172
1174 if (is_object()) {
1175 auto ptr = data.ptr<const json_object>();
1176 if (!ptr) return const_iterator::from_iterator(json_object().end());
1177 return const_iterator::from_iterator(ptr->end());
1178 }
1179 // Use temporary empty object to avoid static initialization conflicts with Teensy
1181 }
1182
1183 // Iterator support for packed arrays
1184 template<typename T>
1186 private:
1189 size_t mIndex;
1190
1191 // Helper to get the size of the array regardless of its type
1192 size_t get_size() const FL_NOEXCEPT {
1193 if (!mVariant) return 0;
1194
1195 if (mVariant->is<json_array>()) {
1196 auto ptr = mVariant->ptr<json_array>();
1197 return ptr ? ptr->size() : 0;
1198 }
1199
1200 if (mVariant->is<fl::vector<i16>>()) {
1201 auto ptr = mVariant->ptr<fl::vector<i16>>();
1202 return ptr ? ptr->size() : 0;
1203 }
1204
1205 if (mVariant->is<fl::vector<u8>>()) {
1206 auto ptr = mVariant->ptr<fl::vector<u8>>();
1207 return ptr ? ptr->size() : 0;
1208 }
1209
1210 if (mVariant->is<fl::vector<float>>()) {
1211 auto ptr = mVariant->ptr<fl::vector<float>>();
1212 return ptr ? ptr->size() : 0;
1213 }
1214
1215 return 0;
1216 }
1217
1218 // Helper to convert current element to target type T
1220 if (!mVariant || mIndex >= get_size()) {
1221 return parse_result<T>(task::Error("Index out of bounds"));
1222 }
1223
1224 if (mVariant->is<json_array>()) {
1225 auto ptr = mVariant->ptr<json_array>();
1226 if (ptr && mIndex < ptr->size() && (*ptr)[mIndex]) {
1227 auto& val = *((*ptr)[mIndex]);
1228
1229 // Try to convert to T using the json_value conversion methods
1230 // Using FastLED type traits instead of std:: ones
1232 auto opt = val.as_bool();
1233 if (opt) {
1234 return parse_result<T>(*opt);
1235 } else {
1236 return parse_result<T>(task::Error("Cannot convert to bool"));
1237 }
1239 auto opt = val.template as_int<T>();
1240 if (opt) {
1241 return parse_result<T>(*opt);
1242 } else {
1243 return parse_result<T>(task::Error("Cannot convert to signed integer"));
1244 }
1246 // For unsigned types, we check that it's integral but not signed
1247 auto opt = val.template as_int<T>();
1248 if (opt) {
1249 return parse_result<T>(*opt);
1250 } else {
1251 return parse_result<T>(task::Error("Cannot convert to unsigned integer"));
1252 }
1254 auto opt = val.template as_float<T>();
1255 if (opt) {
1256 return parse_result<T>(*opt);
1257 } else {
1258 return parse_result<T>(task::Error("Cannot convert to floating point"));
1259 }
1260 }
1261 } else {
1262 return parse_result<T>(task::Error("Invalid array access"));
1263 }
1264 }
1265
1266 if (mVariant->is<fl::vector<i16>>()) {
1267 auto ptr = mVariant->ptr<fl::vector<i16>>();
1268 if (ptr && mIndex < ptr->size()) {
1269 return parse_result<T>(static_cast<T>((*ptr)[mIndex]));
1270 } else {
1271 return parse_result<T>(task::Error("Index out of bounds in i16 array"));
1272 }
1273 }
1274
1275 if (mVariant->is<fl::vector<u8>>()) {
1276 auto ptr = mVariant->ptr<fl::vector<u8>>();
1277 if (ptr && mIndex < ptr->size()) {
1278 return parse_result<T>(static_cast<T>((*ptr)[mIndex]));
1279 } else {
1280 return parse_result<T>(task::Error("Index out of bounds in u8 array"));
1281 }
1282 }
1283
1284 if (mVariant->is<fl::vector<float>>()) {
1285 auto ptr = mVariant->ptr<fl::vector<float>>();
1286 if (ptr && mIndex < ptr->size()) {
1287 return parse_result<T>(static_cast<T>((*ptr)[mIndex]));
1288 } else {
1289 return parse_result<T>(task::Error("Index out of bounds in float array"));
1290 }
1291 }
1292
1293 return parse_result<T>(task::Error("Unknown array type"));
1294 }
1295
1296 public:
1298 array_iterator(variant_t* variant, size_t index) FL_NOEXCEPT : mVariant(variant), mIndex(index) {}
1299
1301 return get_value();
1302 }
1303
1305 ++mIndex;
1306 return *this;
1307 }
1308
1310 array_iterator tmp(*this);
1311 ++(*this);
1312 return tmp;
1313 }
1314
1315 bool operator!=(const array_iterator& other) const FL_NOEXCEPT {
1316 return mIndex != other.mIndex || mVariant != other.mVariant;
1317 }
1318
1319 bool operator==(const array_iterator& other) const FL_NOEXCEPT {
1320 return mIndex == other.mIndex && mVariant == other.mVariant;
1321 }
1322 };
1323
1324 // Begin/end methods for array iteration
1325 template<typename T>
1327 if (is_array()) {
1328 return array_iterator<T>(&data, 0);
1329 }
1330 return array_iterator<T>();
1331 }
1332
1333 template<typename T>
1335 if (is_array()) {
1336 return array_iterator<T>(&data, size());
1337 }
1338 return array_iterator<T>();
1339 }
1340
1341 template<typename T>
1343 if (is_array()) {
1344 return array_iterator<T>(const_cast<variant_t*>(&data), 0);
1345 }
1346 return array_iterator<T>();
1347 }
1348
1349 template<typename T>
1351 if (is_array()) {
1352 return array_iterator<T>(const_cast<variant_t*>(&data), size());
1353 }
1354 return array_iterator<T>();
1355 }
1356
1357 // Free functions for range-based for loops
1358 friend iterator begin(json_value& v) FL_NOEXCEPT { return v.begin(); }
1359 friend iterator end(json_value& v) FL_NOEXCEPT { return v.end(); }
1360 friend const_iterator begin(const json_value& v) FL_NOEXCEPT { return v.begin(); }
1361 friend const_iterator end(const json_value& v) FL_NOEXCEPT { return v.end(); }
1362
1363 // Indexing for fluid chaining
1365 if (!is_array()) data = json_array{};
1366 // Handle regular json_array
1367 if (data.is<json_array>()) {
1368 auto ptr = data.ptr<json_array>();
1369 if (!ptr) return get_null_json_value(); // Handle error case
1370 auto &arr = *ptr;
1371 if (idx >= arr.size()) {
1372 // Resize array and fill with null values
1373 for (size_t i = arr.size(); i <= idx; i++) {
1374 arr.push_back(fl::make_shared<json_value>());
1375 }
1376 }
1377 if (idx >= arr.size()) return get_null_json_value(); // Handle error case
1378 return *arr[idx];
1379 }
1380 // For packed arrays, we need to convert them to regular arrays first
1381 // This is needed for compatibility with existing code that expects json_array
1382 if (data.is<fl::vector<i16>>() ||
1383 data.is<fl::vector<u8>>() ||
1384 data.is<fl::vector<float>>()) {
1385 // Convert to regular json_array (needs a copy/conversion)
1386 auto arr = clone_array();
1387 if (arr) {
1388 data = fl::move(*arr);
1389 auto ptr = data.ptr<json_array>();
1390 if (!ptr) return get_null_json_value();
1391 auto &jsonArr = *ptr;
1392 if (idx >= jsonArr.size()) {
1393 // Resize array and fill with null values
1394 for (size_t i = jsonArr.size(); i <= idx; i++) {
1395 jsonArr.push_back(fl::make_shared<json_value>());
1396 }
1397 }
1398 if (idx >= jsonArr.size()) return get_null_json_value();
1399 return *jsonArr[idx];
1400 }
1401 }
1402 return get_null_json_value();
1403 }
1404
1406 if (!is_object()) data = json_object{};
1407 auto ptr = data.ptr<json_object>();
1408 if (!ptr) return get_null_json_value(); // Handle error case
1409 auto &obj = *ptr;
1410 if (obj.find(key) == obj.end()) {
1411 // Create a new entry if key doesn't exist
1412 obj[key] = fl::make_shared<json_value>();
1413 }
1414 return *obj[key];
1415 }
1416
1417 // Default-value operator (pipe)
1418 template<typename T>
1419 T operator|(const T& fallback) const FL_NOEXCEPT {
1420 default_value_visitor<T> visitor(fallback);
1421 data.visit(visitor);
1422 return visitor.result ? *visitor.result : fallback;
1423 }
1424
1425 // Explicit method for default values (alternative to operator|)
1426 template<typename T>
1427 T as_or(const T& fallback) const FL_NOEXCEPT {
1428 default_value_visitor<T> visitor(fallback);
1429 data.visit(visitor);
1430 return visitor.result ? *visitor.result : fallback;
1431 }
1432
1433 // Contains methods for checking existence
1434 bool contains(size_t idx) const FL_NOEXCEPT {
1435 // Handle regular json_array first
1436 if (data.is<json_array>()) {
1437 auto ptr = data.ptr<json_array>();
1438 return ptr && idx < ptr->size();
1439 }
1440
1441 // Handle specialized array types
1442 if (data.is<fl::vector<i16>>()) {
1443 auto ptr = data.ptr<fl::vector<i16>>();
1444 return ptr && idx < ptr->size();
1445 }
1446 if (data.is<fl::vector<u8>>()) {
1447 auto ptr = data.ptr<fl::vector<u8>>();
1448 return ptr && idx < ptr->size();
1449 }
1450 if (data.is<fl::vector<float>>()) {
1451 auto ptr = data.ptr<fl::vector<float>>();
1452 return ptr && idx < ptr->size();
1453 }
1454 return false;
1455 }
1456
1457 bool contains(const fl::string &key) const FL_NOEXCEPT {
1458 if (!is_object()) return false;
1459 auto ptr = data.ptr<json_object>();
1460 return ptr && ptr->find(key) != ptr->end();
1461 }
1462
1463 // Object iteration support (needed for screenmap conversion)
1466 if (is_object()) {
1467 for (auto it = begin(); it != end(); ++it) {
1468 auto keyValue = *it;
1469 result.push_back(keyValue.first);
1470 }
1471 }
1472 return result;
1473 }
1474
1475 // Backward compatibility method
1477
1478 // Size methods
1479 size_t size() const FL_NOEXCEPT {
1480 SizeVisitor visitor;
1481 data.visit(visitor);
1482 return visitor.result;
1483 }
1484
1485 // Serialization
1487
1488 // Visitor-based serialization helper
1489 friend struct SerializerVisitor;
1490
1491 // Custom two-phase JSON parser (PRODUCTION READY)
1492 // Features:
1493 // - Two-phase: validation (zero alloc) + building
1494 // - Array lookahead: Direct parsing to typed vectors (uint8, int16, float)
1495 // - Zero-copy tokenization with fl::span<const char>
1496 // - ~608 bytes stack overhead, recursion depth limit 32
1497 // - Identical behavior to parse() (validated with A/B tests)
1498 static fl::shared_ptr<json_value> parse2(const fl::string &txt) FL_NOEXCEPT;
1499 static fl::shared_ptr<json_value> parse2(fl::string_view txt) FL_NOEXCEPT; // Zero-copy version
1500 static bool parse2_validate_only(const fl::string &txt) FL_NOEXCEPT; // Phase 1 validation only (for testing)
1501 static bool parse2_validate_only(fl::string_view txt) FL_NOEXCEPT; // Zero-copy version (no allocation)
1502
1503 // Iterator support for objects
1504 class iterator {
1505 private:
1507
1508 public:
1510
1511 iterator() = default;
1513
1514 // Getter for const iterator conversion
1516
1518 ++mIter;
1519 return *this;
1520 }
1521
1523 iterator tmp(*this);
1524 ++(*this);
1525 return tmp;
1526 }
1527
1528 bool operator!=(const iterator& other) const FL_NOEXCEPT {
1529 return mIter != other.mIter;
1530 }
1531
1532 bool operator==(const iterator& other) const FL_NOEXCEPT {
1533 return mIter == other.mIter;
1534 }
1535
1536 struct KeyValue {
1539
1541 : first(key), second(value_ptr ? *value_ptr : get_null_json_value()) {}
1542 };
1543
1545 return KeyValue(mIter->first, mIter->second);
1546 }
1547
1548 // Remove operator-> to avoid static variable issues
1549 };
1550
1551 // Iterator for JSON objects (const version)
1553 private:
1555
1556 public:
1558
1559 const_iterator() = default;
1561
1562 // Factory method for conversion from iterator
1564 json_object::const_iterator const_iter(other.get_iter());
1565 return const_iterator(const_iter);
1566 }
1567
1568 // Factory method for conversion from Object::iterator
1572
1574 ++mIter;
1575 return *this;
1576 }
1577
1579 const_iterator tmp(*this);
1580 ++(*this);
1581 return tmp;
1582 }
1583
1584 bool operator!=(const const_iterator& other) const FL_NOEXCEPT {
1585 return mIter != other.mIter;
1586 }
1587
1588 bool operator==(const const_iterator& other) const FL_NOEXCEPT {
1589 return mIter == other.mIter;
1590 }
1591
1592 struct KeyValue {
1595
1597 : first(key), second(value_ptr ? *value_ptr : get_null_json_value()) {}
1598 };
1599
1601 return KeyValue(mIter->first, mIter->second);
1602 }
1603
1604 // Remove operator-> to avoid static variable issues
1605 };
1606};
1607
1608// Function to get a reference to a static null json_value
1609json_value& get_null_json_value() FL_NOEXCEPT;
1610
1611// Visitor to extract a numeric value from a single json_value element
1612template<typename T>
1614 T result = T(0);
1615
1616 template<typename U>
1617 void accept(const U& value) FL_NOEXCEPT { (*this)(value); }
1618
1619 void operator()(const i64& v) FL_NOEXCEPT { result = static_cast<T>(v); }
1620 void operator()(const float& v) FL_NOEXCEPT { result = static_cast<T>(v); }
1621 void operator()(const bool& v) FL_NOEXCEPT { result = static_cast<T>(v ? 1 : 0); }
1622 // Non-numeric types → zero
1630};
1631
1632// Visitor to copy array elements into a span<T> with type conversion
1633template<typename T>
1636 size_t result;
1637
1639
1640 template<typename U>
1641 void accept(const U& value) FL_NOEXCEPT { (*this)(value); }
1642
1643 // Packed vectors: element-wise static_cast
1647
1648 // Generic json_array: visitor-based per-element extraction
1650 size_t n = (arr.size() < dst.size()) ? arr.size() : dst.size();
1651 for (size_t i = 0; i < n; ++i) {
1652 const auto& elem = arr[i];
1653 if (!elem) { dst[i] = T(0); continue; }
1655 elem->data.visit(nv);
1656 dst[i] = nv.result;
1657 }
1658 result = n;
1659 }
1660
1661 // Non-array types: nothing to copy
1663 void operator()(const bool&) FL_NOEXCEPT {}
1665 void operator()(const float&) FL_NOEXCEPT {}
1668
1669private:
1670 template<typename ElemT>
1672 size_t n = (vec.size() < dst.size()) ? vec.size() : dst.size();
1673 for (size_t i = 0; i < n; ++i) {
1674 dst[i] = static_cast<T>(vec[i]);
1675 }
1676 result = n;
1677 }
1678};
1679
1680// Visitor to stream array elements into an output iterator with type conversion.
1681// Works with fl::back_inserter(container) to append to any container.
1682template<typename T, typename OutputIt>
1684 OutputIt out;
1685 size_t result;
1686
1687 explicit CopyToOutputIteratorVisitor(OutputIt o) FL_NOEXCEPT : out(o), result(0) {}
1688
1689 template<typename U>
1690 void accept(const U& value) FL_NOEXCEPT { (*this)(value); }
1691
1692 // Packed vectors: element-wise static_cast
1696
1697 // Generic json_array: visitor-based per-element extraction
1699 for (size_t i = 0; i < arr.size(); ++i) {
1700 const auto& elem = arr[i];
1701 if (!elem) { *out = T(0); ++out; ++result; continue; }
1703 elem->data.visit(nv);
1704 *out = nv.result;
1705 ++out;
1706 ++result;
1707 }
1708 }
1709
1710 // Non-array types: nothing to write
1712 void operator()(const bool&) FL_NOEXCEPT {}
1714 void operator()(const float&) FL_NOEXCEPT {}
1717
1718private:
1719 template<typename ElemT>
1721 for (size_t i = 0; i < vec.size(); ++i) {
1722 *out = static_cast<T>(vec[i]);
1723 ++out;
1724 }
1725 result = vec.size();
1726 }
1727};
1728
1729// Main json class that provides a more fluid and user-friendly interface
1730
1731} // namespace fl
Back insert iterator - an output iterator that inserts elements at the end of a container.
Definition iterator.h:75
fl::size length() const FL_NOEXCEPT
array_iterator(variant_t *variant, size_t index) FL_NOEXCEPT
Definition types.h:1298
size_t get_size() const FL_NOEXCEPT
Definition types.h:1192
array_iterator & operator++() FL_NOEXCEPT
Definition types.h:1304
bool operator!=(const array_iterator &other) const FL_NOEXCEPT
Definition types.h:1315
parse_result< T > operator*() const FL_NOEXCEPT
Definition types.h:1300
bool operator==(const array_iterator &other) const FL_NOEXCEPT
Definition types.h:1319
parse_result< T > get_value() const FL_NOEXCEPT
Definition types.h:1219
array_iterator() FL_NOEXCEPT
Definition types.h:1297
array_iterator operator++(int) FL_NOEXCEPT
Definition types.h:1309
typename json_value::variant_t variant_t
Definition types.h:1187
fl::forward_iterator_tag iterator_category
Definition types.h:1557
static const_iterator from_object_iterator(const iterator &other) FL_NOEXCEPT
Definition types.h:1563
KeyValue operator*() const FL_NOEXCEPT
Definition types.h:1600
static const_iterator from_iterator(json_object::const_iterator iter) FL_NOEXCEPT
Definition types.h:1569
json_object::const_iterator mIter
Definition types.h:1554
bool operator==(const const_iterator &other) const FL_NOEXCEPT
Definition types.h:1588
const_iterator & operator++() FL_NOEXCEPT
Definition types.h:1573
const_iterator operator++(int) FL_NOEXCEPT
Definition types.h:1578
const_iterator(json_object::const_iterator iter) FL_NOEXCEPT
Definition types.h:1560
bool operator!=(const const_iterator &other) const FL_NOEXCEPT
Definition types.h:1584
json_object::iterator get_iter() const FL_NOEXCEPT
Definition types.h:1515
KeyValue operator*() const FL_NOEXCEPT
Definition types.h:1544
bool operator!=(const iterator &other) const FL_NOEXCEPT
Definition types.h:1528
json_object::iterator mIter
Definition types.h:1506
iterator & operator++() FL_NOEXCEPT
Definition types.h:1517
iterator operator++(int) FL_NOEXCEPT
Definition types.h:1522
fl::forward_iterator_tag iterator_category
Definition types.h:1509
bool operator==(const iterator &other) const FL_NOEXCEPT
Definition types.h:1532
iterator(json_object::iterator iter) FL_NOEXCEPT
Definition types.h:1512
fl::size size() const FL_NOEXCEPT
#define FL_ERROR(X)
Definition log.h:219
Centralized logging categories for FastLED hardware interfaces and subsystems.
constexpr T && forward(typename remove_reference< T >::type &t) FL_NOEXCEPT
Definition s16x16x4.h:234
decltype(nullptr) nullptr_t
Definition s16x16x4.h:13
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition s16x16x4.h:28
string to_string(T value) FL_NOEXCEPT
Definition string.h:450
char tolower(char c) FL_NOEXCEPT
Convert character to lowercase.
Definition cctype.h:32
constexpr int type_rank< T >::value
bool isdigit(char c) FL_NOEXCEPT
Check if character is a decimal digit (0-9)
Definition cctype.h:25
int parseInt(const char *str, fl::size len)
Parse an integer from a character buffer.
Optional< T > optional
Definition optional.h:16
json_object & get_empty_json_obj()
Definition json.cpp.hpp:69
fl::i64 i64
Definition s16x16x4.h:222
shared_ptr< T > make_shared(Args &&... args) FL_NOEXCEPT
Definition shared_ptr.h:414
fl::vector< fl::shared_ptr< json_value > > json_array
Definition types.h:33
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
json_value & get_null_json_value()
Definition json.cpp.hpp:64
constexpr nullopt_t nullopt
Definition optional.h:13
fl::flat_map< fl::string, fl::shared_ptr< json_value >, fl::StringFastLess > json_object
Definition types.h:34
float parseFloat(const char *str, fl::size len)
Parse a floating point number from a character buffer.
Base definition for an LED controller.
Definition crgb.hpp:179
Promise-based fluent API for FastLED - standalone async primitives.
#define FL_NOEXCEPT
void accept(const U &value) FL_NOEXCEPT
Definition types.h:326
void operator()(const fl::string &str) FL_NOEXCEPT
Definition types.h:353
void operator()(const double &value) FL_NOEXCEPT
Definition types.h:347
void operator()(const float &value) FL_NOEXCEPT
Definition types.h:341
fl::optional< bool > result
Definition types.h:323
void operator()(const T &) FL_NOEXCEPT
Definition types.h:387
void operator()(const i64 &value) FL_NOEXCEPT
Definition types.h:335
void operator()(const bool &value) FL_NOEXCEPT
Definition types.h:331
void operator()(const fl::vector< u8 > &v) FL_NOEXCEPT
Definition types.h:1693
void operator()(const json_object &) FL_NOEXCEPT
Definition types.h:1716
void operator()(const i64 &) FL_NOEXCEPT
Definition types.h:1713
void operator()(const fl::vector< i16 > &v) FL_NOEXCEPT
Definition types.h:1694
void operator()(const fl::nullptr_t &) FL_NOEXCEPT
Definition types.h:1711
void operator()(const fl::vector< float > &v) FL_NOEXCEPT
Definition types.h:1695
void accept(const U &value) FL_NOEXCEPT
Definition types.h:1690
void operator()(const json_array &arr) FL_NOEXCEPT
Definition types.h:1698
void write_vec(const fl::vector< ElemT > &vec) FL_NOEXCEPT
Definition types.h:1720
CopyToOutputIteratorVisitor(OutputIt o) FL_NOEXCEPT
Definition types.h:1687
void operator()(const fl::string &) FL_NOEXCEPT
Definition types.h:1715
void operator()(const float &) FL_NOEXCEPT
Definition types.h:1714
void operator()(const bool &) FL_NOEXCEPT
Definition types.h:1712
void operator()(const fl::vector< i16 > &v) FL_NOEXCEPT
Definition types.h:1645
void operator()(const fl::vector< float > &v) FL_NOEXCEPT
Definition types.h:1646
fl::span< T > dst
Definition types.h:1635
void operator()(const bool &) FL_NOEXCEPT
Definition types.h:1663
void copy_vec(const fl::vector< ElemT > &vec) FL_NOEXCEPT
Definition types.h:1671
void operator()(const float &) FL_NOEXCEPT
Definition types.h:1665
void operator()(const json_object &) FL_NOEXCEPT
Definition types.h:1667
void operator()(const json_array &arr) FL_NOEXCEPT
Definition types.h:1649
void operator()(const fl::string &) FL_NOEXCEPT
Definition types.h:1666
void operator()(const fl::nullptr_t &) FL_NOEXCEPT
Definition types.h:1662
void operator()(const fl::vector< u8 > &v) FL_NOEXCEPT
Definition types.h:1644
void accept(const U &value) FL_NOEXCEPT
Definition types.h:1641
void operator()(const i64 &) FL_NOEXCEPT
Definition types.h:1664
CopyToVisitor(fl::span< T > d) FL_NOEXCEPT
Definition types.h:1638
void operator()(const fl::vector< i16 > &) FL_NOEXCEPT
Definition types.h:1628
void operator()(const fl::string &) FL_NOEXCEPT
Definition types.h:1624
void operator()(const json_object &) FL_NOEXCEPT
Definition types.h:1626
void operator()(const fl::nullptr_t &) FL_NOEXCEPT
Definition types.h:1623
void operator()(const json_array &) FL_NOEXCEPT
Definition types.h:1625
void operator()(const i64 &v) FL_NOEXCEPT
Definition types.h:1619
void accept(const U &value) FL_NOEXCEPT
Definition types.h:1617
void operator()(const fl::vector< u8 > &) FL_NOEXCEPT
Definition types.h:1627
void operator()(const float &v) FL_NOEXCEPT
Definition types.h:1620
void operator()(const fl::vector< float > &) FL_NOEXCEPT
Definition types.h:1629
void operator()(const bool &v) FL_NOEXCEPT
Definition types.h:1621
void operator()(const fl::nullptr_t &) FL_NOEXCEPT
Definition types.h:662
void operator()(const fl::string &) FL_NOEXCEPT
Definition types.h:666
void operator()(const json_array &arr) FL_NOEXCEPT
Definition types.h:655
void operator()(const bool &) FL_NOEXCEPT
Definition types.h:663
size_t result
Definition types.h:647
void operator()(const float &) FL_NOEXCEPT
Definition types.h:665
void operator()(const fl::vector< u8 > &vec) FL_NOEXCEPT
Definition types.h:658
void operator()(const fl::vector< i16 > &vec) FL_NOEXCEPT
Definition types.h:657
void operator()(const i64 &) FL_NOEXCEPT
Definition types.h:664
void accept(const U &value) FL_NOEXCEPT
Definition types.h:650
void operator()(const json_object &obj) FL_NOEXCEPT
Definition types.h:656
void operator()(const fl::vector< float > &vec) FL_NOEXCEPT
Definition types.h:659
void operator()(const bool &value) FL_NOEXCEPT
Definition types.h:629
void operator()(const i64 &value) FL_NOEXCEPT
Definition types.h:614
void accept(const U &value) FL_NOEXCEPT
Definition types.h:605
void operator()(const fl::string &value) FL_NOEXCEPT
Definition types.h:610
void operator()(const double &value) FL_NOEXCEPT
Definition types.h:619
void operator()(const T &) FL_NOEXCEPT
Definition types.h:640
void operator()(const float &value) FL_NOEXCEPT
Definition types.h:624
fl::optional< fl::string > result
Definition types.h:602
void operator()(const fl::nullptr_t &) FL_NOEXCEPT
Definition types.h:634
fl::enable_if< fl::is_floating_point< T >::value &&fl::is_integral< U >::value, void >::type operator()(const U &value) FL_NOEXCEPT
Definition types.h:107
fl::enable_if< fl::is_integral< T >::value &&fl::is_integral< U >::value, void >::type operator()(const U &value) FL_NOEXCEPT
Definition types.h:89
void accept(const U &value) FL_NOEXCEPT
Definition types.h:76
fl::enable_if< fl::is_floating_point< T >::value &&fl::is_floating_point< U >::value &&!fl::is_same< T, U >::value, void >::type operator()(const U &value) FL_NOEXCEPT
Definition types.h:116
fl::enable_if< fl::is_integral< T >::value &&fl::is_floating_point< U >::value, void >::type operator()(const U &value) FL_NOEXCEPT
Definition types.h:98
default_value_visitor(const T &fb) FL_NOEXCEPT
Definition types.h:72
void operator()(const T &value) FL_NOEXCEPT
Definition types.h:82
void operator()(const fl::nullptr_t &)
Definition types.h:135
fl::enable_if<!(fl::is_integral< T >::value &&fl::is_integral< U >::value) FL_NOEXCEPT &&!(fl::is_integral< T >::value &&fl::is_floating_point< U >::value)&&!(fl::is_floating_point< T >::value &&fl::is_integral< U >::value)&&!(fl::is_floating_point< T >::value &&fl::is_floating_point< U >::value &&!fl::is_same< T, U >::value), void >::type operator()(const U &)
Definition types.h:130
void operator()(const fl::string &str) FL_NOEXCEPT
Definition types.h:540
void operator()(const bool &value) FL_NOEXCEPT
Definition types.h:536
void accept(const U &value) FL_NOEXCEPT
Definition types.h:509
void operator()(const i64 &value) FL_NOEXCEPT
Definition types.h:522
fl::optional< double > result
Definition types.h:506
void operator()(const double &value) FL_NOEXCEPT
Definition types.h:514
void operator()(const T &) FL_NOEXCEPT
Definition types.h:595
void operator()(const float &value) FL_NOEXCEPT
Definition types.h:518
void accept(const U &value) FL_NOEXCEPT
Definition types.h:398
void operator()(const bool &value) FL_NOEXCEPT
Definition types.h:437
void operator()(const fl::string &str) FL_NOEXCEPT
Definition types.h:443
void operator()(const i64 &value) FL_NOEXCEPT
Definition types.h:421
void operator()(const FloatType &value) FL_NOEXCEPT
Definition types.h:403
fl::optional< FloatType > result
Definition types.h:395
void operator()(const T &) FL_NOEXCEPT
Definition types.h:498
fl::enable_if<!fl::is_same< T, double >::value, void >::type operator()(const double &value) FL_NOEXCEPT
Definition types.h:410
fl::enable_if<!fl::is_same< T, float >::value, void >::type operator()(const float &value) FL_NOEXCEPT
Definition types.h:417
fl::optional< i64 > result
Definition types.h:248
void operator()(const double &value) FL_NOEXCEPT
Definition types.h:281
void operator()(const T &) FL_NOEXCEPT
Definition types.h:316
void operator()(const float &value) FL_NOEXCEPT
Definition types.h:264
void operator()(const bool &value) FL_NOEXCEPT
Definition types.h:260
void accept(const U &value) FL_NOEXCEPT
Definition types.h:251
void operator()(const i64 &value) FL_NOEXCEPT
Definition types.h:256
void operator()(const fl::string &str) FL_NOEXCEPT
Definition types.h:288
fl::enable_if< fl::is_same< T, i64 >::value, void >::type operator()(const i64 &value) FL_NOEXCEPT
Definition types.h:161
void operator()(const T &) FL_NOEXCEPT
Definition types.h:240
void accept(const U &value) FL_NOEXCEPT
Definition types.h:146
void operator()(const bool &value) FL_NOEXCEPT
Definition types.h:194
void operator()(const float &value) FL_NOEXCEPT
Definition types.h:199
void operator()(const fl::string &str) FL_NOEXCEPT
Definition types.h:212
fl::enable_if< fl::is_same< T, double >::value, void >::type operator()(const double &value) FL_NOEXCEPT
Definition types.h:168
fl::optional< IntType > result
Definition types.h:143
fl::enable_if<!fl::is_same< T, i64 >::value, void >::type operator()(const i64 &value) FL_NOEXCEPT
Definition types.h:176
fl::enable_if<!fl::is_same< T, double >::value, void >::type operator()(const double &value) FL_NOEXCEPT
Definition types.h:207
fl::enable_if<!fl::is_same< T, i64 >::value &&!fl::is_same< T, double >::value, void >::type operator()(const IntType &value) FL_NOEXCEPT
Definition types.h:154
void operator()(const fl::vector< u8 > &) FL_NOEXCEPT
Definition types.h:879
void operator()(const fl::vector< i16 > &) FL_NOEXCEPT
Definition types.h:875
void operator()(const json_array &) FL_NOEXCEPT
Definition types.h:870
void operator()(const fl::vector< float > &) FL_NOEXCEPT
Definition types.h:883
void accept(const T &value) FL_NOEXCEPT
Definition types.h:864
void operator()(const T &) FL_NOEXCEPT
Definition types.h:889
KeyValue(const fl::string &key, const fl::shared_ptr< json_value > &value_ptr) FL_NOEXCEPT
Definition types.h:1596
KeyValue(const fl::string &key, const fl::shared_ptr< json_value > &value_ptr) FL_NOEXCEPT
Definition types.h:1540
json_value & operator=(i64 i) FL_NOEXCEPT
Definition types.h:775
fl::optional< json_object > clone_object() const FL_NOEXCEPT
Definition types.h:1097
fl::optional< fl::string > as_string() FL_NOEXCEPT
Definition types.h:985
const_iterator end() const FL_NOEXCEPT
Definition types.h:1173
fl::optional< bool > as_bool() FL_NOEXCEPT
Definition types.h:924
json_value & operator[](const fl::string &key) FL_NOEXCEPT
Definition types.h:1405
fl::optional< FloatType > as_float() FL_NOEXCEPT
Definition types.h:974
json_value(const fl::vector< i16 > &audio) FL_NOEXCEPT
Definition types.h:721
json_value(const json_array &a) FL_NOEXCEPT
Definition types.h:715
fl::vector< fl::string > get_object_keys() const FL_NOEXCEPT
Definition types.h:1476
fl::optional< T > get() const FL_NOEXCEPT
Definition types.h:1133
fl::optional< float > as_float() const FL_NOEXCEPT
Definition types.h:1035
friend const_iterator end(const json_value &v) FL_NOEXCEPT
Definition types.h:1361
json_value & operator=(json_value &&other) FL_NOEXCEPT
Definition types.h:753
fl::optional< fl::string > as_string() const FL_NOEXCEPT
Definition types.h:1051
size_t copy_to_output_iterator(fl::back_insert_iterator< Container > out) const FL_NOEXCEPT
Definition types.h:1124
size_t size() const FL_NOEXCEPT
Definition types.h:1479
fl::string to_string() const FL_NOEXCEPT
array_iterator< T > begin_array() const FL_NOEXCEPT
Definition types.h:1342
array_iterator< T > end_array() FL_NOEXCEPT
Definition types.h:1334
fl::optional< i64 > as_int() const FL_NOEXCEPT
Definition types.h:1012
T operator|(const T &fallback) const FL_NOEXCEPT
Definition types.h:1419
json_array * as_array() FL_NOEXCEPT
Definition types.h:997
friend struct SerializerVisitor
Definition types.h:1489
bool is_double() const FL_NOEXCEPT
Definition types.h:844
bool is_int() const FL_NOEXCEPT
Definition types.h:840
const_iterator begin() const FL_NOEXCEPT
Definition types.h:1163
friend iterator begin(json_value &v) FL_NOEXCEPT
Definition types.h:1358
fl::optional< bool > as_bool() const FL_NOEXCEPT
Definition types.h:1001
bool is_floats() const FL_NOEXCEPT
Definition types.h:918
json_value & operator=(float f) FL_NOEXCEPT
Definition types.h:785
auto visit(Visitor &&visitor) FL_NOEXCEPT -> decltype(visitor(fl::nullptr_t{}))
Definition types.h:822
const json_array * as_array() const FL_NOEXCEPT
Definition types.h:1063
fl::enable_if<!fl::is_same< typenamefl::remove_cv< typenamefl::remove_reference< T >::type >::type, json_value >::value, json_value & >::type operator=(T &&value) FL_NOEXCEPT
Definition types.h:760
bool is_audio() const FL_NOEXCEPT
Definition types.h:910
json_value(fl::vector< u8 > &&bytes) FL_NOEXCEPT
Definition types.h:733
fl::optional< double > as_double() const FL_NOEXCEPT
Definition types.h:958
json_value() FL_NOEXCEPT
Definition types.h:703
json_value & operator=(const json_value &other) FL_NOEXCEPT
Definition types.h:748
json_value(unsigned int i) FL_NOEXCEPT
Definition types.h:711
json_value(const fl::vector< u8 > &bytes) FL_NOEXCEPT
Definition types.h:729
bool contains(const fl::string &key) const FL_NOEXCEPT
Definition types.h:1457
json_value & operator=(fl::string s) FL_NOEXCEPT
Definition types.h:790
bool contains(size_t idx) const FL_NOEXCEPT
Definition types.h:1434
json_value(fl::vector< float > &&floats) FL_NOEXCEPT
Definition types.h:741
static bool parse2_validate_only(const fl::string &txt) FL_NOEXCEPT
json_value(const json_value &other) FL_NOEXCEPT
Definition types.h:746
size_t copy_to_output_iterator(OutputIt out) const FL_NOEXCEPT
Definition types.h:1116
static fl::shared_ptr< json_value > from_char(char c) FL_NOEXCEPT
Definition types.h:816
json_value::iterator iterator
Definition types.h:697
json_value(const fl::vector< float > &floats) FL_NOEXCEPT
Definition types.h:737
variant_t data
Definition types.h:700
json_value & operator=(bool b) FL_NOEXCEPT
Definition types.h:770
json_value & operator=(fl::vector< float > floats) FL_NOEXCEPT
Definition types.h:810
friend class json
Definition types.h:681
json_value & operator=(fl::nullptr_t) FL_NOEXCEPT
Definition types.h:765
array_iterator< T > end_array() const FL_NOEXCEPT
Definition types.h:1350
fl::optional< FloatType > as_float() const FL_NOEXCEPT
Definition types.h:1040
fl::optional< i64 > as_int() FL_NOEXCEPT
Definition types.h:935
const json_object * as_object() const FL_NOEXCEPT
Definition types.h:1064
bool is_null() const FL_NOEXCEPT
Definition types.h:832
json_object * as_object() FL_NOEXCEPT
Definition types.h:998
json_value(int i) FL_NOEXCEPT
Definition types.h:710
fl::optional< json_array > clone_array() const FL_NOEXCEPT
Definition types.h:1067
bool is_object() const FL_NOEXCEPT
Definition types.h:906
bool is_string() const FL_NOEXCEPT
Definition types.h:855
json_value(const json_object &o) FL_NOEXCEPT
Definition types.h:718
json_value(fl::vector< i16 > &&audio) FL_NOEXCEPT
Definition types.h:725
json_value & operator=(json_array a) FL_NOEXCEPT
Definition types.h:795
json_value(const fl::string &s) FL_NOEXCEPT
Definition types.h:713
static fl::shared_ptr< json_value > parse2(const fl::string &txt) FL_NOEXCEPT
fl::vector< fl::string > keys() const FL_NOEXCEPT
Definition types.h:1464
json_value & operator=(fl::vector< i16 > audio) FL_NOEXCEPT
Definition types.h:800
fl::optional< IntType > as_int() FL_NOEXCEPT
Definition types.h:947
fl::optional< IntType > as_int() const FL_NOEXCEPT
Definition types.h:1024
json_value(fl::nullptr_t) FL_NOEXCEPT
Definition types.h:704
fl::variant< fl::nullptr_t, bool, i64, float, fl::string, json_array, json_object, fl::vector< i16 >, fl::vector< u8 >, fl::vector< float > > variant_t
Definition types.h:684
bool is_bytes() const FL_NOEXCEPT
Definition types.h:914
bool is_generic_array() const FL_NOEXCEPT
Definition types.h:902
fl::optional< T > get() FL_NOEXCEPT
Definition types.h:1139
array_iterator< T > begin_array() FL_NOEXCEPT
Definition types.h:1326
bool is_number() const FL_NOEXCEPT
Definition types.h:852
friend iterator end(json_value &v) FL_NOEXCEPT
Definition types.h:1359
json_value(i64 i) FL_NOEXCEPT
Definition types.h:706
friend const_iterator begin(const json_value &v) FL_NOEXCEPT
Definition types.h:1360
auto visit(Visitor &&visitor) const FL_NOEXCEPT -> decltype(visitor(fl::nullptr_t{}))
Definition types.h:827
bool is_float() const FL_NOEXCEPT
Definition types.h:848
iterator begin() FL_NOEXCEPT
Definition types.h:1145
iterator end() FL_NOEXCEPT
Definition types.h:1154
size_t copy_to(fl::span< T > out) const FL_NOEXCEPT
Definition types.h:1106
json_value(float f) FL_NOEXCEPT
Definition types.h:712
json_value & operator[](size_t idx) FL_NOEXCEPT
Definition types.h:1364
bool is_array() const FL_NOEXCEPT
Definition types.h:894
json_value & operator=(fl::vector< u8 > bytes) FL_NOEXCEPT
Definition types.h:805
T as_or(const T &fallback) const FL_NOEXCEPT
Definition types.h:1427
json_value & operator=(double d) FL_NOEXCEPT
Definition types.h:780
json_value(bool b) FL_NOEXCEPT
Definition types.h:705
fl::optional< float > as_float() FL_NOEXCEPT
Definition types.h:969
bool is_bool() const FL_NOEXCEPT
Definition types.h:836
static constexpr T min() FL_NOEXCEPT
Definition limits.h:107
static constexpr T max() FL_NOEXCEPT
Definition limits.h:108
task::Error error
Definition types.h:40
const T & get_value() const FL_NOEXCEPT
Definition types.h:46
bool has_error() const FL_NOEXCEPT
Definition types.h:45
parse_result(const task::Error &err) FL_NOEXCEPT
Definition types.h:43
parse_result(const T &val) FL_NOEXCEPT
Definition types.h:42
const task::Error & get_error() const FL_NOEXCEPT
Definition types.h:47
Error type for promises.
Definition promise.h:39