FastLED 3.9.15
Loading...
Searching...
No Matches
json.h
Go to the documentation of this file.
1#pragma once
2
143
144
145#include "fl/string.h"
146#include "fl/vector.h"
147#include "fl/hash_map.h"
148#include "fl/variant.h"
149#include "fl/optional.h"
150#include "fl/unique_ptr.h"
151#include "fl/shared_ptr.h"
152#include "fl/functional.h"
153#include "fl/str.h" // For StringFormatter
154#include "fl/promise.h" // For Error type
155#include "fl/warn.h" // For FL_WARN
156
157#include "fl/sketch_macros.h"
159#ifndef FASTLED_ENABLE_JSON
160#define FASTLED_ENABLE_JSON SKETCH_HAS_LOTS_OF_MEMORY
161#endif
162
163
164namespace fl {
165
166
167// Forward declarations
168struct JsonValue;
169
170// Define Array and Object as pointers to avoid incomplete type issues
171// We'll use heap-allocated containers for these to avoid alignment issues
174
175// ParseResult struct to replace variant<T, Error>
176template<typename T>
178 T value;
181 ParseResult(const T& val) : value(val), error() {}
182 ParseResult(const Error& err) : value(), error(err) {}
184 bool has_error() const { return !error.is_empty(); }
185 const T& get_value() const { return value; }
186 const Error& get_error() const { return error; }
188 // Implicit conversion operator to allow using ParseResult as T directly
189 operator const T&() const {
190 if (has_error()) {
191 // This should ideally trigger some kind of error handling
192 // For now, we'll just return the value (which might be default-initialized)
193 }
194 return value;
195 }
196};
197
198// Function to get a reference to a static null JsonValue
199JsonValue& get_null_value();
200
201// Function to get a reference to a static empty JsonObject
203
204// AI - pay attention to this - implementing visitor pattern
205template<typename T>
207 const T& fallback;
208 const T* result = nullptr;
209 T storage; // Use instance storage instead of static
210
211 DefaultValueVisitor(const T& fb) : fallback(fb) {}
212
213 // This is the method that fl::Variant expects
214 template<typename U>
215 void accept(const U& value) {
216 // Dispatch to the correct operator() overload
217 (*this)(value);
218 }
220 // Specific overload for the type T
221 void operator()(const T& value) {
222 result = &value;
223 }
224
225 // Special handling for integer conversions
226 template<typename U>
228 operator()(const U& value) {
229 // Convert between integer types
230 storage = static_cast<T>(value);
231 result = &storage;
232 }
233
234 // Special handling for floating point to integer conversion
235 template<typename U>
237 operator()(const U& value) {
238 // Convert float to integer
239 storage = static_cast<T>(value);
240 result = &storage;
241 }
242
243 // Special handling for integer to floating point conversion
244 template<typename U>
246 operator()(const U& value) {
247 // Convert integer to float
248 storage = static_cast<T>(value);
249 result = &storage;
250 }
251
252 // Special handling for floating point to floating point conversion
253 template<typename U>
255 operator()(const U& value) {
256 // Convert between floating point types (e.g., double to float)
257 storage = static_cast<T>(value);
258 result = &storage;
259 }
260
261
262
263 // Generic overload for all other types
264 template<typename U>
265 typename fl::enable_if<
272 // Do nothing for other types
273 }
275 // Special handling for nullptr_t
276 void operator()(const fl::nullptr_t&) {
277 // Do nothing - will return fallback
278 }
279};
280
281// Visitor for converting values to int
282template<typename IntType = int64_t>
286 template<typename U>
287 void accept(const U& value) {
288 // Dispatch to the correct operator() overload
289 (*this)(value);
290 }
291
292 // Special handling to avoid conflict when IntType is int64_t
293 template<typename T = IntType>
295 operator()(const IntType& value) {
296 result = value;
297 }
298
299 // Special handling for int64_t case
300 template<typename T = IntType>
302 operator()(const int64_t& value) {
303 result = value;
304 }
305
306 // Special handling for double case (when IntType is double)
307 template<typename T = IntType>
309 operator()(const double& value) {
310 result = value;
311 }
312
313 // Special handling to avoid conflict when IntType is int64_t
314 template<typename T = IntType>
316 operator()(const int64_t& value) {
317 result = static_cast<IntType>(value);
319
320 void operator()(const bool& value) {
321 result = static_cast<IntType>(value ? 1 : 0);
322 }
323
324 // Special handling for double to int conversion
325 template<typename T = IntType>
327 operator()(const double& value) {
328 // NEW INSTRUCTIONS: AUTO CONVERT FLOAT TO INT
329 result = static_cast<IntType>(value);
331
332 void operator()(const fl::string& str) {
333 // NEW INSTRUCTIONS: AUTO CONVERT STRING TO INT
334 // Try to parse the string as an integer using FastLED's StringFormatter
335 // Validate by checking if string contains only digits (and optional +/- sign)
336 bool isValidInt = true;
337 fl::size startPos = 0;
338
339 // Check for sign
340 if (str.length() > 0 && (str[0] == '+' || str[0] == '-')) {
341 startPos = 1;
342 }
343
344 // Check that all remaining characters are digits
345 for (fl::size i = startPos; i < str.length(); i++) {
346 if (!StringFormatter::isDigit(str[i])) {
347 isValidInt = false;
348 break;
349 }
350 }
351
352 // If it looks like a valid integer, try to parse it
353 if (isValidInt && str.length() > 0) {
354 int parsed = StringFormatter::parseInt(str.c_str(), str.length());
355 result = static_cast<IntType>(parsed);
356 }
357 }
359 template<typename T>
360 void operator()(const T&) {
361 // Do nothing for other types
362 }
363};
364
365// Specialization for int64_t to avoid template conflicts
366template<>
367struct IntConversionVisitor<int64_t> {
370 template<typename U>
371 void accept(const U& value) {
372 // Dispatch to the correct operator() overload
373 (*this)(value);
375
376 void operator()(const int64_t& value) {
377 result = value;
379
380 void operator()(const bool& value) {
381 result = value ? 1 : 0;
383
384 void operator()(const double& value) {
385 // NEW INSTRUCTIONS: AUTO CONVERT FLOAT TO INT
386 result = static_cast<int64_t>(value);
388
389 void operator()(const fl::string& str) {
390 // NEW INSTRUCTIONS: AUTO CONVERT STRING TO INT
391 // Try to parse the string as an integer using FastLED's StringFormatter
392 // Validate by checking if string contains only digits (and optional +/- sign)
393 bool isValidInt = true;
394 fl::size startPos = 0;
395
396 // Check for sign
397 if (str.length() > 0 && (str[0] == '+' || str[0] == '-')) {
398 startPos = 1;
399 }
400
401 // Check that all remaining characters are digits
402 for (fl::size i = startPos; i < str.length(); i++) {
403 if (!StringFormatter::isDigit(str[i])) {
404 isValidInt = false;
405 break;
406 }
407 }
408
409 // If it looks like a valid integer, try to parse it
410 if (isValidInt && str.length() > 0) {
411 int parsed = StringFormatter::parseInt(str.c_str(), str.length());
412 result = static_cast<int64_t>(parsed);
413 }
414 }
416 template<typename T>
417 void operator()(const T&) {
418 // Do nothing for other types
419 }
420};
421
422// Visitor for converting values to float
423template<typename FloatType = double>
427 template<typename U>
428 void accept(const U& value) {
429 // Dispatch to the correct operator() overload
430 (*this)(value);
432
433 void operator()(const FloatType& value) {
434 result = value;
435 }
436
437 // Special handling to avoid conflict when FloatType is double
438 template<typename T = FloatType>
440 operator()(const double& value) {
441 result = static_cast<FloatType>(value);
442 }
443
444 // Special handling to avoid conflict when FloatType is float
445 template<typename T = FloatType>
447 operator()(const float& value) {
448 result = static_cast<FloatType>(value);
450
451 void operator()(const int64_t& value) {
452 // NEW INSTRUCTIONS: AUTO CONVERT INT TO FLOAT
453 result = static_cast<FloatType>(value);
455
456 void operator()(const bool& value) {
457 result = static_cast<FloatType>(value ? 1.0 : 0.0);
459
460 void operator()(const fl::string& str) {
461 // NEW INSTRUCTIONS: AUTO CONVERT STRING TO FLOAT
462 // Try to parse the string as a float using FastLED's StringFormatter
463 // Validate by checking if string contains valid float characters
464 bool isValidFloat = true;
465 bool hasDecimal = false;
466 fl::size startPos = 0;
467
468 // Check for sign
469 if (str.length() > 0 && (str[0] == '+' || str[0] == '-')) {
470 startPos = 1;
471 }
472
473 // Check that all remaining characters are valid for a float
474 for (fl::size i = startPos; i < str.length(); i++) {
475 char c = str[i];
476 if (c == '.') {
477 if (hasDecimal) {
478 // Multiple decimal points
479 isValidFloat = false;
480 break;
481 }
482 hasDecimal = true;
483 } else if (!StringFormatter::isDigit(c) && c != 'e' && c != 'E') {
484 isValidFloat = false;
485 break;
486 }
487 }
488
489 // If it looks like a valid float, try to parse it
490 if (isValidFloat && str.length() > 0) {
491 // For simple cases, we can use a more precise approach
492 // Check if it's a simple decimal number
493 bool isSimpleDecimal = true;
494 for (fl::size i = startPos; i < str.length(); i++) {
495 char c = str[i];
496 if (c != '.' && !StringFormatter::isDigit(c)) {
497 isSimpleDecimal = false;
498 break;
499 }
500 }
501
502 if (isSimpleDecimal) {
503 // For simple decimals, we can do a more direct conversion
504 float parsed = StringFormatter::parseFloat(str.c_str(), str.length());
505 result = static_cast<FloatType>(parsed);
506 } else {
507 // For complex floats (with exponents), use the standard approach
508 float parsed = StringFormatter::parseFloat(str.c_str(), str.length());
509 result = static_cast<FloatType>(parsed);
510 }
511 }
512 }
514 template<typename T>
515 void operator()(const T&) {
516 // Do nothing for other types
517 }
518};
519
520// Specialization for double to avoid template conflicts
521template<>
522struct FloatConversionVisitor<double> {
525 template<typename U>
526 void accept(const U& value) {
527 // Dispatch to the correct operator() overload
528 (*this)(value);
530
531 void operator()(const double& value) {
532 result = value;
534
535 void operator()(const float& value) {
536 result = static_cast<double>(value);
538
539 void operator()(const int64_t& value) {
540 // NEW INSTRUCTIONS: AUTO CONVERT INT TO FLOAT
541 result = static_cast<double>(value);
543
544 void operator()(const bool& value) {
545 result = value ? 1.0 : 0.0;
547
548 void operator()(const fl::string& str) {
549 // NEW INSTRUCTIONS: AUTO CONVERT STRING TO FLOAT
550 // Try to parse the string as a float using FastLED's StringFormatter
551 // Validate by checking if string contains valid float characters
552 bool isValidFloat = true;
553 bool hasDecimal = false;
554 fl::size startPos = 0;
555
556 // Check for sign
557 if (str.length() > 0 && (str[0] == '+' || str[0] == '-')) {
558 startPos = 1;
559 }
560
561 // Check that all remaining characters are valid for a float
562 for (fl::size i = startPos; i < str.length(); i++) {
563 char c = str[i];
564 if (c == '.') {
565 if (hasDecimal) {
566 // Multiple decimal points
567 isValidFloat = false;
568 break;
569 }
570 hasDecimal = true;
571 } else if (!StringFormatter::isDigit(c) && c != 'e' && c != 'E') {
572 isValidFloat = false;
573 break;
574 }
575 }
576
577 // If it looks like a valid float, try to parse it
578 if (isValidFloat && str.length() > 0) {
579 // For simple cases, we can use a more precise approach
580 // Check if it's a simple decimal number
581 bool isSimpleDecimal = true;
582 for (fl::size i = startPos; i < str.length(); i++) {
583 char c = str[i];
584 if (c != '.' && !StringFormatter::isDigit(c)) {
585 isSimpleDecimal = false;
586 break;
587 }
588 }
589
590 if (isSimpleDecimal) {
591 // For simple decimals, we can do a more direct conversion
592 float parsed = StringFormatter::parseFloat(str.c_str(), str.length());
593 result = static_cast<double>(parsed);
594 } else {
595 // For complex floats (with exponents), use the standard approach
596 float parsed = StringFormatter::parseFloat(str.c_str(), str.length());
597 result = static_cast<double>(parsed);
598 }
599 }
600 }
602 template<typename T>
603 void operator()(const T&) {
604 // Do nothing for other types
605 }
606};
608// Visitor for converting values to string
612 template<typename U>
613 void accept(const U& value) {
614 // Dispatch to the correct operator() overload
615 (*this)(value);
617
618 void operator()(const fl::string& value) {
619 result = value;
621
622 void operator()(const int64_t& value) {
623 // Convert integer to string
624 result = fl::to_string(value);
626
627 void operator()(const double& value) {
628 // Convert double to string with higher precision for JSON representation
629 result = fl::to_string(static_cast<float>(value), 6);
631
632 void operator()(const float& value) {
633 // Convert float to string with higher precision for JSON representation
634 result = fl::to_string(value, 6);
636
637 void operator()(const bool& value) {
638 // Convert bool to string
639 result = value ? "true" : "false";
641
642 void operator()(const fl::nullptr_t&) {
643 // Convert null to string
644 result = "null";
645 }
647 template<typename T>
648 void operator()(const T&) {
649 // Do nothing for other types (arrays, objects)
650 }
651};
653// The JSON node
654struct JsonValue {
655 // Forward declarations for nested iterator classes
656 class iterator;
657 class const_iterator;
659 // Friend declarations
660 friend class Json;
661
663 // The variant holds exactly one of these alternatives
664 using variant_t = fl::Variant<
665 fl::nullptr_t, // null
666 bool, // true/false
667 int64_t, // integer
668 float, // floating-point (changed from double to float)
669 fl::string, // string
670 JsonArray, // array
671 JsonObject, // object
672 fl::vector<int16_t>, // audio data (specialized array of int16_t)
673 fl::vector<uint8_t>, // byte data (specialized array of uint8_t)
674 fl::vector<float> // float data (specialized array of float)
675 >;
679
682 // Constructors
683 JsonValue() noexcept : data(nullptr) {}
684 JsonValue(fl::nullptr_t) noexcept : data(nullptr) {}
685 JsonValue(bool b) noexcept : data(b) {}
686 JsonValue(int64_t i) noexcept : data(i) {}
687 JsonValue(float f) noexcept : data(f) {} // Changed from double to float
688 JsonValue(const fl::string& s) : data(s) {
689 }
690 JsonValue(const JsonArray& a) : data(a) {
691 //FASTLED_WARN("Created JsonValue with array");
692 }
693 JsonValue(const JsonObject& o) : data(o) {
694 //FASTLED_WARN("Created JsonValue with object");
695 }
697 //FASTLED_WARN("Created JsonValue with audio data");
701 //FASTLED_WARN("Created JsonValue with moved audio data");
703
704 JsonValue(const fl::vector<uint8_t>& bytes) : data(bytes) {
705 //FASTLED_WARN("Created JsonValue with byte data");
707
708 JsonValue(fl::vector<uint8_t>&& bytes) : data(fl::move(bytes)) {
709 //FASTLED_WARN("Created JsonValue with moved byte data");
711
712 JsonValue(const fl::vector<float>& floats) : data(floats) {
713 //FASTLED_WARN("Created JsonValue with float data");
715
716 JsonValue(fl::vector<float>&& floats) : data(fl::move(floats)) {
717 //FASTLED_WARN("Created JsonValue with moved float data");
718 }
720 // Copy constructor
721 JsonValue(const JsonValue& other) : data(other.data) {}
722
723 JsonValue& operator=(const JsonValue& other) {
724 data = other.data;
725 return *this;
727
728 JsonValue& operator=(JsonValue&& other) {
729 data = fl::move(other.data);
730 return *this;
731 }
732
733 template<typename T>
735 operator=(T&& value) {
736 data = fl::forward<T>(value);
737 return *this;
739
741 data = nullptr;
742 return *this;
744
745 JsonValue& operator=(bool b) {
746 data = b;
747 return *this;
749
750 JsonValue& operator=(int64_t i) {
751 data = i;
752 return *this;
754
755 JsonValue& operator=(double d) {
756 data = static_cast<float>(d);
757 return *this;
759
760 JsonValue& operator=(float f) {
761 data = f;
762 return *this;
764
766 data = fl::move(s);
767 return *this;
769
771 data = fl::move(a);
772 return *this;
777 return *this;
779
781 data = fl::move(bytes);
782 return *this;
784
786 data = fl::move(floats);
787 return *this;
788 }
789
790
792 // Special constructor for char values
793 static fl::shared_ptr<JsonValue> from_char(char c) {
795 }
796
797 // Visitor pattern implementation
798 template<typename Visitor>
799 auto visit(Visitor&& visitor) -> decltype(visitor(fl::nullptr_t{})) {
800 return data.visit(fl::forward<Visitor>(visitor));
801 }
803 template<typename Visitor>
804 auto visit(Visitor&& visitor) const -> decltype(visitor(fl::nullptr_t{})) {
805 return data.visit(fl::forward<Visitor>(visitor));
806 }
808 // Type queries - using is<T>() instead of index() for fl::Variant
809 bool is_null() const noexcept {
810 //FASTLED_WARN("is_null called, tag=" << data.tag());
811 return data.is<fl::nullptr_t>();
812 }
813 bool is_bool() const noexcept {
814 //FASTLED_WARN("is_bool called, tag=" << data.tag());
815 return data.is<bool>();
816 }
817 bool is_int() const noexcept {
818 //FASTLED_WARN("is_int called, tag=" << data.tag());
819 return data.is<int64_t>() || data.is<bool>();
820 }
821 bool is_double() const noexcept {
822 //FASTLED_WARN("is_double called, tag=" << data.tag());
823 return data.is<float>();
824 }
825 bool is_float() const noexcept {
826 return data.is<float>();
827 }
828 bool is_string() const noexcept {
829 //FASTLED_WARN("is_string called, tag=" << data.tag());
830 return data.is<fl::string>();
832 // Visitor for array type checking
833 struct IsArrayVisitor {
834 bool result = false;
836 template<typename T>
837 void accept(const T& value) {
838 // Dispatch to the correct operator() overload
839 (*this)(value);
840 }
842 // JsonArray is an array
843 void operator()(const JsonArray&) {
844 result = true;
845 }
847 // Specialized array types ARE arrays
848 void operator()(const fl::vector<int16_t>&) {
849 result = true; // Audio data is still an array
851
852 void operator()(const fl::vector<uint8_t>&) {
853 result = true; // Byte data is still an array
855
856 void operator()(const fl::vector<float>&) {
857 result = true; // Float data is still an array
858 }
859
860 // Generic handler for all other types
861 template<typename T>
862 void operator()(const T&) {
863 result = false;
864 }
865 };
866
867 bool is_array() const noexcept {
868 //FASTLED_WARN("is_array called, tag=" << data.tag());
869 IsArrayVisitor visitor;
870 data.visit(visitor);
871 return visitor.result;
872 }
874 // Returns true only for JsonArray (not specialized array types)
875 bool is_generic_array() const noexcept {
876 return data.is<JsonArray>();
877 }
878
880
881 bool is_object() const noexcept {
882 //FASTLED_WARN("is_object called, tag=" << data.tag());
883 return data.is<JsonObject>();
884 }
885 bool is_audio() const noexcept {
886 //FASTLED_WARN("is_audio called, tag=" << data.tag());
888 }
889 bool is_bytes() const noexcept {
890 //FASTLED_WARN("is_bytes called, tag=" << data.tag());
892 }
893 bool is_floats() const noexcept {
894 //FASTLED_WARN("is_floats called, tag=" << data.tag());
895 return data.is<fl::vector<float>>();
896 }
898 // Safe extractors (return optional values, not references)
900 auto ptr = data.ptr<bool>();
901 return ptr ? fl::optional<bool>(*ptr) : fl::nullopt;
903
905 // Check if we have a valid value first
906 if (data.empty()) {
907 return fl::nullopt;
908 }
909
910 IntConversionVisitor<int64_t> visitor;
911 data.visit(visitor);
912 return visitor.result;
913 }
915 template<typename IntType>
917 // Check if we have a valid value first
918 if (data.empty()) {
919 return fl::nullopt;
920 }
921
923 data.visit(visitor);
924 return visitor.result;
926
928 // Check if we have a valid value first
929 if (data.empty()) {
930 return fl::nullopt;
931 }
932
933 FloatConversionVisitor<double> visitor;
934 data.visit(visitor);
935 return visitor.result;
939 return as_float<float>();
940 }
942 template<typename FloatType>
944 // Check if we have a valid value first
945 if (data.empty()) {
946 return fl::nullopt;
947 }
948
950 data.visit(visitor);
951 return visitor.result;
953
955 // Check if we have a valid value first
956 if (data.empty()) {
957 return fl::nullopt;
958 }
959
960 StringConversionVisitor visitor;
961 data.visit(visitor);
962 return visitor.result;
964
966 auto ptr = data.ptr<JsonArray>();
967 if (ptr) return fl::optional<JsonArray>(*ptr);
968
969 // Handle specialized array types by converting them to regular JsonArray
970 if (data.is<fl::vector<int16_t>>()) {
971 auto audioPtr = data.ptr<fl::vector<int16_t>>();
973 for (const auto& item : *audioPtr) {
974 result.push_back(fl::make_shared<JsonValue>(static_cast<int64_t>(item)));
975 }
977 }
978
979 if (data.is<fl::vector<uint8_t>>()) {
980 auto bytePtr = data.ptr<fl::vector<uint8_t>>();
981 JsonArray result;
982 for (const auto& item : *bytePtr) {
983 result.push_back(fl::make_shared<JsonValue>(static_cast<int64_t>(item)));
984 }
985 return fl::optional<JsonArray>(result);
986 }
987
988 if (data.is<fl::vector<float>>()) {
989 auto floatPtr = data.ptr<fl::vector<float>>();
990 JsonArray result;
991 for (const auto& item : *floatPtr) {
992 result.push_back(fl::make_shared<JsonValue>(item)); // Use float directly
993 }
994 return fl::optional<JsonArray>(result);
995 }
996
997 return fl::nullopt;
999
1001 auto ptr = data.ptr<JsonObject>();
1002 return ptr ? fl::optional<JsonObject>(*ptr) : fl::nullopt;
1007 return ptr ? fl::optional<fl::vector<int16_t>>(*ptr) : fl::nullopt;
1012 return ptr ? fl::optional<fl::vector<uint8_t>>(*ptr) : fl::nullopt;
1017 return ptr ? fl::optional<fl::vector<float>>(*ptr) : fl::nullopt;
1018 }
1020 // Const overloads
1021 fl::optional<bool> as_bool() const {
1022 auto ptr = data.ptr<bool>();
1023 return ptr ? fl::optional<bool>(*ptr) : fl::nullopt;
1025
1027 // Check if we have a valid value first
1028 if (data.empty()) {
1029 return fl::nullopt;
1030 }
1031
1032 IntConversionVisitor<int64_t> visitor;
1033 data.visit(visitor);
1034 return visitor.result;
1035 }
1037 template<typename IntType>
1039 // Check if we have a valid value first
1040 if (data.empty()) {
1041 return fl::nullopt;
1042 }
1043
1045 data.visit(visitor);
1046 return visitor.result;
1048
1050 return as_float<float>();
1051 }
1053 template<typename FloatType>
1055 // Check if we have a valid value first
1056 if (data.empty()) {
1057 return fl::nullopt;
1058 }
1059
1061 data.visit(visitor);
1062 return visitor.result;
1064
1066 // Check if we have a valid value first
1067 if (data.empty()) {
1068 return fl::nullopt;
1069 }
1070
1071 StringConversionVisitor visitor;
1072 data.visit(visitor);
1073 return visitor.result;
1075
1077 auto ptr = data.ptr<JsonArray>();
1078 if (ptr) return fl::optional<JsonArray>(*ptr);
1079
1080 // Handle specialized array types by converting them to regular JsonArray
1081 if (data.is<fl::vector<int16_t>>()) {
1082 auto audioPtr = data.ptr<fl::vector<int16_t>>();
1084 for (const auto& item : *audioPtr) {
1085 result.push_back(fl::make_shared<JsonValue>(static_cast<int64_t>(item)));
1086 }
1088 }
1089
1090 if (data.is<fl::vector<uint8_t>>()) {
1091 auto bytePtr = data.ptr<fl::vector<uint8_t>>();
1092 JsonArray result;
1093 for (const auto& item : *bytePtr) {
1094 result.push_back(fl::make_shared<JsonValue>(static_cast<int64_t>(item)));
1095 }
1096 return fl::optional<JsonArray>(result);
1097 }
1098
1099 if (data.is<fl::vector<float>>()) {
1100 auto floatPtr = data.ptr<fl::vector<float>>();
1101 JsonArray result;
1102 for (const auto& item : *floatPtr) {
1103 result.push_back(fl::make_shared<JsonValue>(item)); // Use float directly
1104 }
1105 return fl::optional<JsonArray>(result);
1106 }
1107
1108 return fl::nullopt;
1110
1112 auto ptr = data.ptr<JsonObject>();
1113 return ptr ? fl::optional<JsonObject>(*ptr) : fl::nullopt;
1115
1117 auto ptr = data.ptr<fl::vector<int16_t>>();
1118 return ptr ? fl::optional<fl::vector<int16_t>>(*ptr) : fl::nullopt;
1120
1122 auto ptr = data.ptr<fl::vector<uint8_t>>();
1123 return ptr ? fl::optional<fl::vector<uint8_t>>(*ptr) : fl::nullopt;
1125
1127 auto ptr = data.ptr<fl::vector<float>>();
1128 return ptr ? fl::optional<fl::vector<float>>(*ptr) : fl::nullopt;
1129 }
1130
1131 // Generic getter template method
1132 template<typename T>
1133 fl::optional<T> get() const {
1134 auto ptr = data.ptr<T>();
1135 return ptr ? fl::optional<T>(*ptr) : fl::nullopt;
1136 }
1138 template<typename T>
1140 auto ptr = data.ptr<T>();
1141 return ptr ? fl::optional<T>(*ptr) : fl::nullopt;
1142 }
1144 // Iterator support for objects and arrays
1145 iterator begin() {
1146 if (is_object()) {
1147 auto ptr = data.ptr<JsonObject>();
1148 return iterator(ptr->begin());
1149 }
1150 // Use temporary empty object to avoid static initialization conflicts with Teensy
1151 return iterator(JsonObject().begin());
1153
1154 iterator end() {
1155 if (is_object()) {
1156 auto ptr = data.ptr<JsonObject>();
1157 return iterator(ptr->end());
1158 }
1159 // Use temporary empty object to avoid static initialization conflicts with Teensy
1160 return iterator(JsonObject().end());
1162
1163 const_iterator begin() const {
1164 if (is_object()) {
1165 auto ptr = data.ptr<const JsonObject>();
1166 if (!ptr) return const_iterator::from_iterator(JsonObject().begin());
1167 return const_iterator::from_iterator(ptr->begin());
1168 }
1169 // Use temporary empty object to avoid static initialization conflicts with Teensy
1171 }
1173
1174 const_iterator end() const {
1175 if (is_object()) {
1176 auto ptr = data.ptr<const JsonObject>();
1177 if (!ptr) return const_iterator::from_iterator(JsonObject().end());
1178 return const_iterator::from_iterator(ptr->end());
1179 }
1180 // Use temporary empty object to avoid static initialization conflicts with Teensy
1182 }
1183
1184 // Iterator support for packed arrays
1185 template<typename T>
1187 private:
1190 size_t m_index;
1192 // Helper to get the size of the array regardless of its type
1193 size_t get_size() const {
1194 if (!m_variant) return 0;
1195
1196 if (m_variant->is<JsonArray>()) {
1197 auto ptr = m_variant->ptr<JsonArray>();
1198 return ptr ? ptr->size() : 0;
1199 }
1200
1201 if (m_variant->is<fl::vector<int16_t>>()) {
1202 auto ptr = m_variant->ptr<fl::vector<int16_t>>();
1203 return ptr ? ptr->size() : 0;
1204 }
1205
1206 if (m_variant->is<fl::vector<uint8_t>>()) {
1207 auto ptr = m_variant->ptr<fl::vector<uint8_t>>();
1208 return ptr ? ptr->size() : 0;
1209 }
1210
1211 if (m_variant->is<fl::vector<float>>()) {
1212 auto ptr = m_variant->ptr<fl::vector<float>>();
1213 return ptr ? ptr->size() : 0;
1214 }
1215
1216 return 0;
1217 }
1219 // Helper to convert current element to target type T
1220 ParseResult<T> get_value() const {
1221 if (!m_variant || m_index >= get_size()) {
1222 return ParseResult<T>(Error("Index out of bounds"));
1223 }
1224
1225 if (m_variant->is<JsonArray>()) {
1226 auto ptr = m_variant->ptr<JsonArray>();
1227 if (ptr && m_index < ptr->size() && (*ptr)[m_index]) {
1228 auto& val = *((*ptr)[m_index]);
1229
1230 // Try to convert to T using the JsonValue conversion methods
1231 // Using FastLED type traits instead of std:: ones
1233 auto opt = val.as_bool();
1234 if (opt) {
1235 return ParseResult<T>(*opt);
1236 } else {
1237 return ParseResult<T>(Error("Cannot convert to bool"));
1238 }
1240 auto opt = val.template as_int<T>();
1241 if (opt) {
1242 return ParseResult<T>(*opt);
1243 } else {
1244 return ParseResult<T>(Error("Cannot convert to signed integer"));
1245 }
1247 // For unsigned types, we check that it's integral but not signed
1248 auto opt = val.template as_int<T>();
1249 if (opt) {
1250 return ParseResult<T>(*opt);
1251 } else {
1252 return ParseResult<T>(Error("Cannot convert to unsigned integer"));
1253 }
1255 auto opt = val.template as_float<T>();
1256 if (opt) {
1257 return ParseResult<T>(*opt);
1258 } else {
1259 return ParseResult<T>(Error("Cannot convert to floating point"));
1260 }
1261 }
1262 } else {
1263 return ParseResult<T>(Error("Invalid array access"));
1264 }
1265 }
1266
1267 if (m_variant->is<fl::vector<int16_t>>()) {
1268 auto ptr = m_variant->ptr<fl::vector<int16_t>>();
1269 if (ptr && m_index < ptr->size()) {
1270 return ParseResult<T>(static_cast<T>((*ptr)[m_index]));
1271 } else {
1272 return ParseResult<T>(Error("Index out of bounds in int16_t array"));
1273 }
1274 }
1275
1276 if (m_variant->is<fl::vector<uint8_t>>()) {
1277 auto ptr = m_variant->ptr<fl::vector<uint8_t>>();
1278 if (ptr && m_index < ptr->size()) {
1279 return ParseResult<T>(static_cast<T>((*ptr)[m_index]));
1280 } else {
1281 return ParseResult<T>(Error("Index out of bounds in uint8_t array"));
1282 }
1283 }
1284
1285 if (m_variant->is<fl::vector<float>>()) {
1286 auto ptr = m_variant->ptr<fl::vector<float>>();
1287 if (ptr && m_index < ptr->size()) {
1288 return ParseResult<T>(static_cast<T>((*ptr)[m_index]));
1289 } else {
1290 return ParseResult<T>(Error("Index out of bounds in float array"));
1291 }
1292 }
1293
1294 return ParseResult<T>(Error("Unknown array type"));
1295 }
1297 public:
1298 array_iterator() : m_variant(nullptr), m_index(0) {}
1299 array_iterator(variant_t* variant, size_t index) : m_variant(variant), m_index(index) {}
1300
1301 ParseResult<T> operator*() const {
1302 return get_value();
1304
1306 ++m_index;
1307 return *this;
1309
1311 array_iterator tmp(*this);
1312 ++(*this);
1313 return tmp;
1315
1316 bool operator!=(const array_iterator& other) const {
1317 return m_index != other.m_index || m_variant != other.m_variant;
1319
1320 bool operator==(const array_iterator& other) const {
1321 return m_index == other.m_index && m_variant == other.m_variant;
1322 }
1323 };
1324
1325 // Begin/end methods for array iteration
1326 template<typename T>
1328 if (is_array()) {
1329 return array_iterator<T>(&data, 0);
1330 }
1331 return array_iterator<T>();
1332 }
1334 template<typename T>
1336 if (is_array()) {
1337 return array_iterator<T>(&data, size());
1338 }
1339 return array_iterator<T>();
1340 }
1342 template<typename T>
1344 if (is_array()) {
1345 return array_iterator<T>(const_cast<variant_t*>(&data), 0);
1346 }
1347 return array_iterator<T>();
1348 }
1350 template<typename T>
1352 if (is_array()) {
1353 return array_iterator<T>(const_cast<variant_t*>(&data), size());
1354 }
1355 return array_iterator<T>();
1356 }
1358 // Free functions for range-based for loops
1359 friend iterator begin(JsonValue& v) { return v.begin(); }
1360 friend iterator end(JsonValue& v) { return v.end(); }
1361 friend const_iterator begin(const JsonValue& v) { return v.begin(); }
1362 friend const_iterator end(const JsonValue& v) { return v.end(); }
1364 // Indexing for fluid chaining
1365 JsonValue& operator[](size_t idx) {
1366 if (!is_array()) data = JsonArray{};
1367 // Handle regular JsonArray
1368 if (data.is<JsonArray>()) {
1369 auto ptr = data.ptr<JsonArray>();
1370 if (!ptr) return get_null_value(); // Handle error case
1371 auto &arr = *ptr;
1372 if (idx >= arr.size()) {
1373 // Resize array and fill with null values
1374 for (size_t i = arr.size(); i <= idx; i++) {
1375 arr.push_back(fl::make_shared<JsonValue>());
1376 }
1377 }
1378 if (idx >= arr.size()) return get_null_value(); // Handle error case
1379 return *arr[idx];
1380 }
1381 // For packed arrays, we need to convert them to regular arrays first
1382 // This is needed for compatibility with existing code that expects JsonArray
1383 if (data.is<fl::vector<int16_t>>() ||
1384 data.is<fl::vector<uint8_t>>() ||
1385 data.is<fl::vector<float>>()) {
1386 // Convert to regular JsonArray
1387 auto arr = as_array();
1388 if (arr) {
1389 data = fl::move(*arr);
1390 auto ptr = data.ptr<JsonArray>();
1391 if (!ptr) return get_null_value();
1392 auto &jsonArr = *ptr;
1393 if (idx >= jsonArr.size()) {
1394 // Resize array and fill with null values
1395 for (size_t i = jsonArr.size(); i <= idx; i++) {
1396 jsonArr.push_back(fl::make_shared<JsonValue>());
1397 }
1398 }
1399 if (idx >= jsonArr.size()) return get_null_value();
1400 return *jsonArr[idx];
1401 }
1402 }
1403 return get_null_value();
1405
1406 JsonValue& operator[](const fl::string &key) {
1407 if (!is_object()) data = JsonObject{};
1408 auto ptr = data.ptr<JsonObject>();
1409 if (!ptr) return get_null_value(); // Handle error case
1410 auto &obj = *ptr;
1411 if (obj.find(key) == obj.end()) {
1412 // Create a new entry if key doesn't exist
1413 obj[key] = fl::make_shared<JsonValue>();
1414 }
1415 return *obj[key];
1416 }
1417
1418 // Default-value operator (pipe)
1419 template<typename T>
1420 T operator|(const T& fallback) const {
1421 DefaultValueVisitor<T> visitor(fallback);
1422 data.visit(visitor);
1423 return visitor.result ? *visitor.result : fallback;
1424 }
1425
1426 // Explicit method for default values (alternative to operator|)
1427 template<typename T>
1428 T as_or(const T& fallback) const {
1429 DefaultValueVisitor<T> visitor(fallback);
1430 data.visit(visitor);
1431 return visitor.result ? *visitor.result : fallback;
1432 }
1434 // Contains methods for checking existence
1435 bool contains(size_t idx) const {
1436 // Handle regular JsonArray first
1437 if (data.is<JsonArray>()) {
1438 auto ptr = data.ptr<JsonArray>();
1439 return ptr && idx < ptr->size();
1440 }
1441
1442 // Handle specialized array types
1443 if (data.is<fl::vector<int16_t>>()) {
1444 auto ptr = data.ptr<fl::vector<int16_t>>();
1445 return ptr && idx < ptr->size();
1446 }
1447 if (data.is<fl::vector<uint8_t>>()) {
1448 auto ptr = data.ptr<fl::vector<uint8_t>>();
1449 return ptr && idx < ptr->size();
1450 }
1451 if (data.is<fl::vector<float>>()) {
1452 auto ptr = data.ptr<fl::vector<float>>();
1453 return ptr && idx < ptr->size();
1454 }
1455 return false;
1457
1458 bool contains(const fl::string &key) const {
1459 if (!is_object()) return false;
1460 auto ptr = data.ptr<JsonObject>();
1461 return ptr && ptr->find(key) != ptr->end();
1462 }
1464 // Object iteration support (needed for screenmap conversion)
1467 if (is_object()) {
1468 for (auto it = begin(); it != end(); ++it) {
1469 auto keyValue = *it;
1470 result.push_back(keyValue.first);
1471 }
1472 }
1473 return result;
1474 }
1476 // Backward compatibility method
1477 fl::vector<fl::string> getObjectKeys() const { return keys(); }
1479 // Size methods
1480 size_t size() const {
1481 // Handle regular JsonArray first
1482 if (data.is<JsonArray>()) {
1483 auto ptr = data.ptr<JsonArray>();
1484 return ptr ? ptr->size() : 0;
1485 }
1486
1487 // Handle specialized array types
1488 if (data.is<fl::vector<int16_t>>()) {
1489 auto ptr = data.ptr<fl::vector<int16_t>>();
1490 return ptr ? ptr->size() : 0;
1491 }
1492 if (data.is<fl::vector<uint8_t>>()) {
1493 auto ptr = data.ptr<fl::vector<uint8_t>>();
1494 return ptr ? ptr->size() : 0;
1495 }
1496 if (data.is<fl::vector<float>>()) {
1497 auto ptr = data.ptr<fl::vector<float>>();
1498 return ptr ? ptr->size() : 0;
1499 }
1500
1501 if (is_object()) {
1502 auto ptr = data.ptr<JsonObject>();
1503 return ptr ? ptr->size() : 0;
1504 }
1505 return 0;
1506 }
1507
1508 // Serialization
1509 fl::string to_string() const;
1511 // Visitor-based serialization helper
1512 friend class SerializerVisitor;
1513
1514 // Parsing factory (FLArduinoJson implementation)
1515 static fl::shared_ptr<JsonValue> parse(const fl::string &txt);
1517 // Iterator support for objects
1518 class iterator {
1519 private:
1520 JsonObject::iterator m_iter;
1522 public:
1523 iterator() = default;
1524 iterator(JsonObject::iterator iter) : m_iter(iter) {}
1526 // Getter for const iterator conversion
1527 JsonObject::iterator get_iter() const { return m_iter; }
1528
1529 iterator& operator++() {
1530 ++m_iter;
1531 return *this;
1533
1534 iterator operator++(int) {
1535 iterator tmp(*this);
1536 ++(*this);
1537 return tmp;
1539
1540 bool operator!=(const iterator& other) const {
1541 return m_iter != other.m_iter;
1543
1544 bool operator==(const iterator& other) const {
1545 return m_iter == other.m_iter;
1548 struct KeyValue {
1552 KeyValue(const fl::string& key, const fl::shared_ptr<JsonValue>& value_ptr)
1553 : first(key), second(value_ptr ? *value_ptr : get_null_value()) {}
1555
1556 KeyValue operator*() const {
1557 return KeyValue(m_iter->first, m_iter->second);
1558 }
1559
1560 // Remove operator-> to avoid static variable issues
1561 };
1563 // Iterator for JSON objects (const version)
1565 private:
1566 JsonObject::const_iterator m_iter;
1568 public:
1569 const_iterator() = default;
1570 const_iterator(JsonObject::const_iterator iter) : m_iter(iter) {}
1572 // Factory method for conversion from iterator
1573 static const_iterator from_object_iterator(const iterator& other) {
1574 JsonObject::const_iterator const_iter(other.get_iter());
1575 return const_iterator(const_iter);
1576 }
1578 // Factory method for conversion from Object::iterator
1579 static const_iterator from_iterator(JsonObject::const_iterator iter) {
1580 return const_iterator(iter);
1582
1584 ++m_iter;
1585 return *this;
1587
1589 const_iterator tmp(*this);
1590 ++(*this);
1591 return tmp;
1593
1594 bool operator!=(const const_iterator& other) const {
1595 return m_iter != other.m_iter;
1597
1598 bool operator==(const const_iterator& other) const {
1599 return m_iter == other.m_iter;
1602 struct KeyValue {
1605
1606 KeyValue(const fl::string& key, const fl::shared_ptr<JsonValue>& value_ptr)
1607 : first(key), second(value_ptr ? *value_ptr : get_null_value()) {}
1609
1610 KeyValue operator*() const {
1611 return KeyValue(m_iter->first, m_iter->second);
1612 }
1613
1614 // Remove operator-> to avoid static variable issues
1615 };
1616};
1617
1618// Function to get a reference to a static null JsonValue
1621// Main Json class that provides a more fluid and user-friendly interface
1622class Json {
1623private:
1625
1626public:
1627 // Constructors
1628 Json() : m_value() {} // Default initialize to nullptr
1631 Json(int i) : m_value(fl::make_shared<JsonValue>(static_cast<int64_t>(i))) {}
1632 Json(int64_t i) : m_value(fl::make_shared<JsonValue>(i)) {}
1633 Json(float f) : m_value(fl::make_shared<JsonValue>(f)) {} // Use float directly
1634 Json(double d) : m_value(fl::make_shared<JsonValue>(static_cast<float>(d))) {} // Convert double to float
1636 Json(const char* s): Json(fl::string(s)) {}
1639 // Constructor from shared_ptr<JsonValue>
1642 // Factory method to create a Json from a JsonValue
1643 static Json from_value(const JsonValue& value) {
1644 Json result;
1646 return result;
1647 }
1649 // Constructor for fl::vector<float> - converts to JSON array
1651 auto ptr = m_value->data.ptr<JsonArray>();
1652 if (ptr) {
1653 for (const auto& item : vec) {
1654 ptr->push_back(fl::make_shared<JsonValue>(item)); // Use float directly
1655 }
1656 }
1657 }
1659 // Special constructor for char values
1660 static Json from_char(char c) {
1661 Json result;
1663 //FASTLED_WARN("Created JsonValue with string: " << value->is_string() << ", int: " << value->is_int());
1664 result.m_value = value;
1665 //FASTLED_WARN("Json has string: " << result.is_string() << ", int: " << result.is_int());
1666 return result;
1667 }
1669 // Copy constructor
1670 Json(const Json& other) : m_value(other.m_value) {}
1672 // Assignment operator
1673 Json& operator=(const Json& other) {
1674 //FL_WARN("Json& operator=(const Json& other): " << (other.m_value ? other.m_value.get() : 0));
1675 if (this != &other) {
1676 m_value = other.m_value;
1677 }
1678 return *this;
1680
1681 Json& operator=(Json&& other) {
1682 if (this != &other) {
1683 m_value = fl::move(other.m_value);
1684 }
1685 return *this;
1686 }
1688 // Assignment operators for primitive types to avoid ambiguity
1689 Json& operator=(bool value) {
1691 return *this;
1693
1694 Json& operator=(int value) {
1695 m_value = fl::make_shared<JsonValue>(static_cast<int64_t>(value));
1696 return *this;
1701 return *this;
1703
1704 Json& operator=(double value) {
1705 m_value = fl::make_shared<JsonValue>(static_cast<float>(value));
1706 return *this;
1711 return *this;
1716 return *this;
1717 }
1719 // Assignment operator for fl::vector<float>
1722 auto ptr = m_value->data.ptr<JsonArray>();
1723 if (ptr) {
1724 for (const auto& item : vec) {
1725 ptr->push_back(fl::make_shared<JsonValue>(item)); // Use float directly
1726 }
1727 }
1728 return *this;
1729 }
1731 // Type queries
1732 bool is_null() const { return m_value ? m_value->is_null() : true; }
1733 bool is_bool() const { return m_value && m_value->is_bool(); }
1734 bool is_int() const { return m_value && (m_value->is_int() || m_value->is_bool()); }
1735 bool is_float() const { return m_value && m_value->is_float(); }
1736 bool is_double() const { return m_value && m_value->is_double(); }
1737 bool is_string() const { return m_value && m_value->is_string(); }
1738 bool is_array() const { return m_value && m_value->is_array(); }
1739 bool is_generic_array() const { return m_value && m_value->is_generic_array(); }
1740 bool is_object() const { return m_value && m_value->is_object(); }
1741 bool is_audio() const { return m_value && m_value->is_audio(); }
1742 bool is_bytes() const { return m_value && m_value->is_bytes(); }
1743 bool is_floats() const { return m_value && m_value->is_floats(); }
1745 // Safe extractors
1746 fl::optional<bool> as_bool() const { return m_value ? m_value->as_bool() : fl::nullopt; }
1747 fl::optional<int64_t> as_int() const {
1748 if (!m_value) return fl::nullopt;
1749 return m_value->as_int();
1750 }
1752 template<typename IntType>
1753 fl::optional<IntType> as_int() const {
1754 if (!m_value) return fl::nullopt;
1755 return m_value->template as_int<IntType>();
1757
1758 fl::optional<float> as_float() const {
1759 if (!m_value) return fl::nullopt;
1760 return m_value->as_float();
1762
1764 if (!m_value) return fl::nullopt;
1765 return m_value->as_double();
1766 }
1768 template<typename FloatType>
1770 if (!m_value) return fl::nullopt;
1771 return m_value->template as_float<FloatType>();
1773
1775 if (!m_value) return fl::nullopt;
1776 return m_value->as_string();
1778 fl::optional<JsonArray> as_array() const { return m_value ? m_value->as_array() : fl::nullopt; }
1779 fl::optional<JsonObject> as_object() const { return m_value ? m_value->as_object() : fl::nullopt; }
1781 fl::optional<fl::vector<uint8_t>> as_bytes() const { return m_value ? m_value->as_bytes() : fl::nullopt; }
1782 fl::optional<fl::vector<float>> as_floats() const { return m_value ? m_value->as_floats() : fl::nullopt; }
1783
1784 // NEW ERGONOMIC API: try_as<T>() - Explicit optional handling
1785 // Use when you need to explicitly handle conversion failure
1786 template<typename T>
1787 fl::optional<T> try_as() const {
1788 if (!m_value) {
1789 return fl::nullopt;
1790 }
1791 return as_impl<T>();
1792 }
1793
1794 // BACKWARD COMPATIBILITY: Keep existing as<T>() that returns fl::optional<T>
1795 // This maintains compatibility with existing code
1796 template<typename T>
1797 fl::optional<T> as() const {
1798 return try_as<T>();
1799 }
1800
1801 // NEW ERGONOMIC API: value<T>() - Direct conversion with sensible defaults
1802 // Use when you want a value immediately with reasonable defaults on failure
1803 template<typename T>
1804 T value() const {
1805 auto result = try_as<T>();
1806 return result.has_value() ? *result : get_default_value<T>();
1807 }
1808
1809private:
1810 // Integer types (excluding bool)
1811 template<typename T>
1813 as_impl() const {
1814 return m_value->template as_int<T>();
1815 }
1816
1817 // Boolean type
1818 template<typename T>
1820 as_impl() const {
1821 return m_value->as_bool();
1822 }
1823
1824 // Floating point types
1825 template<typename T>
1827 as_impl() const {
1828 // Force template call by explicitly using the templated method
1829 return m_value->template as_float<T>();
1830 }
1831
1832 // String type
1833 template<typename T>
1835 as_impl() const {
1836 return m_value->as_string();
1837 }
1838
1839 // Array type
1840 template<typename T>
1842 as_impl() const {
1843 return m_value->as_array();
1844 }
1845
1846 // Object type
1847 template<typename T>
1849 as_impl() const {
1850 return m_value->as_object();
1851 }
1852
1853 // Specialized vector types
1854 template<typename T>
1856 as_impl() const {
1857 return m_value->as_audio();
1858 }
1859
1860 template<typename T>
1862 as_impl() const {
1863 return m_value->as_bytes();
1864 }
1865
1866 template<typename T>
1868 as_impl() const {
1869 return m_value->as_floats();
1870 }
1871
1872 // Helper methods for getting default values for each type
1873 template<typename T>
1875 get_default_value() const {
1876 return T(0); // All integer types default to 0
1877 }
1878
1879 template<typename T>
1881 get_default_value() const {
1882 return false; // Boolean defaults to false
1883 }
1884
1885 template<typename T>
1887 get_default_value() const {
1888 return T(0.0); // Floating point types default to 0.0
1889 }
1890
1891 template<typename T>
1893 get_default_value() const {
1894 return fl::string(); // String defaults to empty string
1895 }
1896
1897 template<typename T>
1899 get_default_value() const {
1900 return JsonArray(); // Array defaults to empty array
1901 }
1902
1903 template<typename T>
1905 get_default_value() const {
1906 return JsonObject(); // Object defaults to empty object
1907 }
1908
1909 template<typename T>
1911 get_default_value() const {
1912 return fl::vector<int16_t>(); // Audio vector defaults to empty
1913 }
1914
1915 template<typename T>
1917 get_default_value() const {
1918 return fl::vector<uint8_t>(); // Bytes vector defaults to empty
1919 }
1920
1921 template<typename T>
1923 get_default_value() const {
1924 return fl::vector<float>(); // Float vector defaults to empty
1925 }
1926
1927public:
1929 // Iterator support for objects
1931 if (!m_value) return JsonValue::iterator(JsonObject().begin());
1932 return m_value->begin();
1933 }
1935 if (!m_value) return JsonValue::iterator(JsonObject().end());
1945 }
1946
1947 // Iterator support for arrays with type conversion
1948 template<typename T>
1949 typename JsonValue::template array_iterator<T> begin_array() {
1950 if (!m_value) return typename JsonValue::template array_iterator<T>();
1951 return m_value->template begin_array<T>();
1952 }
1954 template<typename T>
1955 typename JsonValue::template array_iterator<T> end_array() {
1956 if (!m_value) return typename JsonValue::template array_iterator<T>();
1957 return m_value->template end_array<T>();
1958 }
1960 template<typename T>
1961 typename JsonValue::template array_iterator<T> begin_array() const {
1962 if (!m_value) return typename JsonValue::template array_iterator<T>();
1963 return m_value->template begin_array<T>();
1964 }
1966 template<typename T>
1967 typename JsonValue::template array_iterator<T> end_array() const {
1968 if (!m_value) return typename JsonValue::template array_iterator<T>();
1969 return m_value->template end_array<T>();
1970 }
1972 // Free functions for range-based for loops
1973 friend JsonValue::iterator begin(Json& j) { return j.begin(); }
1974 friend JsonValue::iterator end(Json& j) { return j.end(); }
1975 friend JsonValue::const_iterator begin(const Json& j) { return j.begin(); }
1976 friend JsonValue::const_iterator end(const Json& j) { return j.end(); }
1978 // Object iteration support (needed for screenmap conversion)
1981 if (m_value && m_value->is_object()) {
1982 for (auto it = begin(); it != end(); ++it) {
1983 auto keyValue = *it;
1984 result.push_back(keyValue.first);
1985 }
1986 }
1987 return result;
1988 }
1990 // Backward compatibility method
1991 fl::vector<fl::string> getObjectKeys() const { return keys(); }
1993 // Indexing for fluid chaining
1994 Json operator[](size_t idx) {
1995 if (!m_value) {
1997 }
1998 // If we're indexing into a specialized array, convert it to regular JsonArray first
1999 if (m_value->data.is<fl::vector<int16_t>>() ||
2000 m_value->data.is<fl::vector<uint8_t>>() ||
2001 m_value->data.is<fl::vector<float>>()) {
2002 // Convert to regular JsonArray
2003 auto arr = m_value->as_array();
2004 if (arr) {
2006 }
2007 }
2008 // Get the shared_ptr directly from the JsonArray to maintain reference semantics
2009 if (m_value->data.is<JsonArray>()) {
2010 auto arr = m_value->as_array();
2011 if (arr) {
2012 // Ensure the array is large enough
2013 if (idx >= arr->size()) {
2014 for (size_t i = arr->size(); i <= idx; i++) {
2015 arr->push_back(fl::make_shared<JsonValue>(nullptr));
2016 }
2017 }
2018 return Json((*arr)[idx]);
2019 }
2020 }
2021 return Json(nullptr);
2023
2024 const Json operator[](size_t idx) const {
2025 if (!m_value) {
2026 return Json(nullptr);
2027 }
2028 // Handle regular JsonArray
2029 if (m_value->data.is<JsonArray>()) {
2030 auto arr = m_value->as_array();
2031 if (arr && idx < arr->size()) {
2032 return Json((*arr)[idx]);
2033 }
2034 }
2035 // For specialized arrays, we need to convert them to regular arrays first
2036 // This is needed for compatibility with existing code that expects JsonArray
2037 if (m_value->data.is<fl::vector<int16_t>>() ||
2038 m_value->data.is<fl::vector<uint8_t>>() ||
2039 m_value->data.is<fl::vector<float>>()) {
2040 // Convert to regular JsonArray
2041 auto arr = m_value->as_array();
2042 if (arr && idx < arr->size()) {
2043 return Json((*arr)[idx]);
2044 }
2045 }
2046 return Json(nullptr);
2048
2049 Json operator[](const fl::string &key) {
2050 if (!m_value || !m_value->is_object()) {
2052 }
2053 // Get reference to the JsonValue
2054 auto objPtr = m_value->data.ptr<JsonObject>();
2055 if (objPtr) {
2056 // If key doesn't exist, create a new JsonValue and insert it
2057 if (objPtr->find(key) == objPtr->end()) {
2058 (*objPtr)[key] = fl::make_shared<JsonValue>(nullptr);
2059 }
2060 // Return a new Json object that wraps the shared_ptr to the JsonValue
2061 return Json((*objPtr)[key]);
2062 }
2063 // Should not happen if m_value is properly initialized as an object
2064 //return *reinterpret_cast<Json*>(&get_null_value());
2065 return Json(nullptr);
2067
2068 const Json operator[](const fl::string &key) const {
2069 if (!m_value || !m_value->is_object()) {
2070 return Json(nullptr);
2071 }
2072 auto obj = m_value->as_object();
2073 if (obj && obj->find(key) != obj->end()) {
2074 return Json((*obj)[key]);
2075 }
2076 return Json(nullptr);
2077 }
2079 // Contains methods for checking existence
2080 bool contains(size_t idx) const {
2081 return m_value && m_value->contains(idx);
2082 }
2083 bool contains(const fl::string &key) const {
2084 return m_value && m_value->contains(key);
2085 }
2087 // Size method
2088 size_t size() const {
2089 return m_value ? m_value->size() : 0;
2090 }
2091
2092 // Default-value operator (pipe)
2093 template<typename T>
2094 T operator|(const T& fallback) const {
2095 if (!m_value) return fallback;
2096 return (*m_value) | fallback;
2097 }
2098
2099 // NEW ERGONOMIC API: as_or<T>(default) - Conversion with custom defaults
2100 // Use when you want to specify your own default value
2101 // This method uses try_as<T>() for proper string-to-number conversion
2102 template<typename T>
2103 T as_or(const T& fallback) const {
2104 auto result = try_as<T>();
2105 return result.has_value() ? *result : fallback;
2106 }
2108 // has_value method for compatibility
2109 bool has_value() const {
2110 return m_value && !m_value->is_null();
2111 }
2113 // Method to set the internal value (for JsonValue::to_string())
2115 m_value = value;
2116 }
2118 // Public method to access to_string_native for JsonValue::to_string()
2121 // Serialization - now delegates to native implementation
2122 fl::string to_string() const { return to_string_native(); }
2123
2124 // Native serialization (without external libraries)
2127 // Parsing factory method
2128 static Json parse(const fl::string &txt) {
2129 auto parsed = JsonValue::parse(txt);
2130 if (parsed) {
2131 Json result;
2132 result.m_value = parsed;
2133 return result;
2134 }
2135 return Json(nullptr);
2136 }
2138 // Convenience methods for creating arrays and objects
2139 static Json array() {
2140 return Json(JsonArray{});
2142
2143 static Json object() {
2144 return Json(JsonObject{});
2145 }
2147 // Compatibility with existing API for array/object access
2148 size_t getSize() const { return size(); }
2150 // Set methods for building objects
2151 void set(const fl::string& key, const Json& value) {
2152 if (!m_value || !m_value->is_object()) {
2154 }
2155 // Directly assign the value to the object without going through Json::operator[]
2156 auto objPtr = m_value->data.ptr<JsonObject>();
2157 if (objPtr) {
2158 // Create or update the entry directly
2159 (*objPtr)[key] = value.m_value;
2160 }
2163 void set(const fl::string& key, bool value) { set(key, Json(value)); }
2164 void set(const fl::string& key, int value) { set(key, Json(value)); }
2165 void set(const fl::string& key, int64_t value) { set(key, Json(value)); }
2166 void set(const fl::string& key, float value) { set(key, Json(value)); }
2167 void set(const fl::string& key, double value) { set(key, Json(value)); }
2168 void set(const fl::string& key, const fl::string& value) { set(key, Json(value)); }
2169 void set(const fl::string& key, const char* value) { set(key, Json(value)); }
2170 template<typename T, typename = fl::enable_if_t<fl::is_same<T, char>::value>>
2171 void set(const fl::string& key, T value) { set(key, Json(value)); }
2173 // Array push_back methods
2174 void push_back(const Json& value) {
2175 if (!m_value || !m_value->is_array()) {
2177 }
2178 // If we're pushing to a packed array, convert it to regular JsonArray first
2179 if (m_value->is_array() &&
2180 (m_value->data.is<fl::vector<int16_t>>() ||
2181 m_value->data.is<fl::vector<uint8_t>>() ||
2182 m_value->data.is<fl::vector<float>>())) {
2183 // Convert to regular JsonArray
2184 auto arr = m_value->as_array();
2185 if (arr) {
2187 }
2188 }
2189 // For arrays, we need to manually handle the insertion since our indexing
2190 // mechanism auto-creates elements
2191 auto ptr = m_value->data.ptr<JsonArray>();
2192 if (ptr) {
2193 ptr->push_back(value.m_value);
2194 }
2195 }
2197 // Create methods for compatibility
2198 static Json createArray() { return Json::array(); }
2199 static Json createObject() { return Json::object(); }
2201 // Serialize method for compatibility
2202 fl::string serialize() const { return to_string(); }
2203
2204 // Helper function to normalize JSON string (remove whitespace)
2205 static fl::string normalizeJsonString(const char* jsonStr);
2206};
2207
2208} // namespace fl
UIAudio audio("Audio Input")
void push_back(const T &value)
Definition vector.h:552
bool is_floats() const
Definition json.h:1741
bool is_array() const
Definition json.h:1736
T value() const
Definition json.h:1802
fl::enable_if< fl::is_integral< T >::value &&!fl::is_same< T, bool >::value, fl::optional< T > >::type as_impl() const
Definition json.h:1811
fl::enable_if< fl::is_integral< T >::value &&!fl::is_same< T, bool >::value, T >::type get_default_value() const
Definition json.h:1873
static Json createObject()
Definition json.h:2197
fl::optional< JsonObject > as_object() const
Definition json.h:1777
fl::string to_string() const
Definition json.h:2120
void set(const fl::string &key, double value)
Definition json.h:2165
void set_value(const fl::shared_ptr< JsonValue > &value)
Definition json.h:2112
Json(float f)
Definition json.h:1631
fl::optional< fl::string > as_string() const
Definition json.h:1772
static Json from_value(const JsonValue &value)
Definition json.h:1641
bool is_string() const
Definition json.h:1735
fl::optional< int64_t > as_int() const
Definition json.h:1745
bool is_null() const
Definition json.h:1730
bool is_bytes() const
Definition json.h:1740
fl::optional< fl::vector< uint8_t > > as_bytes() const
Definition json.h:1779
bool has_value() const
Definition json.h:2107
bool is_double() const
Definition json.h:1734
JsonValue::iterator begin()
Definition json.h:1928
JsonValue::template array_iterator< T > begin_array()
Definition json.h:1947
T operator|(const T &fallback) const
Definition json.h:2092
fl::optional< fl::vector< float > > as_floats() const
Definition json.h:1780
friend JsonValue::const_iterator begin(const Json &j)
Definition json.h:1973
bool is_generic_array() const
Definition json.h:1737
fl::shared_ptr< JsonValue > m_value
Definition json.h:1622
static Json from_char(char c)
Definition json.h:1658
size_t getSize() const
Definition json.h:2146
static fl::string normalizeJsonString(const char *jsonStr)
Definition json.cpp:494
Json(const fl::shared_ptr< JsonValue > &value)
Definition json.h:1638
Json(const char *s)
Definition json.h:1634
Json(int i)
Definition json.h:1629
Json(const fl::string &s)
Definition json.h:1633
Json & operator=(const Json &other)
Definition json.h:1671
JsonValue::template array_iterator< T > end_array()
Definition json.h:1953
void set(const fl::string &key, int64_t value)
Definition json.h:2163
Json()
Definition json.h:1626
bool contains(size_t idx) const
Definition json.h:2078
static Json object()
Definition json.h:2141
bool is_audio() const
Definition json.h:1739
void set(const fl::string &key, const Json &value)
Definition json.h:2149
void push_back(const Json &value)
Definition json.h:2172
fl::string to_string_native_public() const
Definition json.h:2117
Json(int64_t i)
Definition json.h:1630
fl::optional< T > try_as() const
Definition json.h:1785
fl::optional< float > as_float() const
Definition json.h:1756
Json(JsonObject o)
Definition json.h:1636
fl::vector< fl::string > keys() const
Definition json.h:1977
fl::optional< bool > as_bool() const
Definition json.h:1744
fl::optional< T > as() const
Definition json.h:1795
void set(const fl::string &key, const fl::string &value)
Definition json.h:2166
static Json createArray()
Definition json.h:2196
static Json array()
Definition json.h:2137
void set(const fl::string &key, T value)
Definition json.h:2169
T as_or(const T &fallback) const
Definition json.h:2101
void set(const fl::string &key, float value)
Definition json.h:2164
fl::optional< fl::vector< int16_t > > as_audio() const
Definition json.h:1778
fl::optional< JsonArray > as_array() const
Definition json.h:1776
Json(bool b)
Definition json.h:1628
fl::string to_string_native() const
Definition json.cpp:290
static Json parse(const fl::string &txt)
Definition json.h:2126
bool is_bool() const
Definition json.h:1731
fl::optional< double > as_double() const
Definition json.h:1761
JsonValue::iterator end()
Definition json.h:1932
bool is_float() const
Definition json.h:1733
void set(const fl::string &key, const char *value)
Definition json.h:2167
size_t size() const
Definition json.h:2086
Json operator[](size_t idx)
Definition json.h:1992
Json(double d)
Definition json.h:1632
fl::string serialize() const
Definition json.h:2200
friend JsonValue::const_iterator end(const Json &j)
Definition json.h:1974
bool is_object() const
Definition json.h:1738
bool is_int() const
Definition json.h:1732
fl::vector< fl::string > getObjectKeys() const
Definition json.h:1989
Json(JsonArray a)
Definition json.h:1635
bool operator!=(const array_iterator &other) const
Definition json.h:1314
bool operator==(const array_iterator &other) const
Definition json.h:1318
ParseResult< T > operator*() const
Definition json.h:1299
ParseResult< T > get_value() const
Definition json.h:1218
array_iterator & operator++()
Definition json.h:1303
typename JsonValue::variant_t variant_t
Definition json.h:1186
size_t get_size() const
Definition json.h:1191
KeyValue operator*() const
Definition json.h:1608
bool operator!=(const const_iterator &other) const
Definition json.h:1592
const_iterator & operator++()
Definition json.h:1581
JsonObject::const_iterator m_iter
Definition json.h:1564
bool operator==(const const_iterator &other) const
Definition json.h:1596
static const_iterator from_iterator(JsonObject::const_iterator iter)
Definition json.h:1577
static const_iterator from_object_iterator(const iterator &other)
Definition json.h:1571
KeyValue operator*() const
Definition json.h:1554
bool operator!=(const iterator &other) const
Definition json.h:1538
JsonObject::iterator m_iter
Definition json.h:1518
bool operator==(const iterator &other) const
Definition json.h:1542
iterator & operator++()
Definition json.h:1527
JsonObject::iterator get_iter() const
Definition json.h:1525
const char * c_str() const
Definition str.h:326
fl::size length() const
Definition str.h:325
static int parseInt(const char *str, fl::size len)
Definition str.cpp:300
static float parseFloat(const char *str, fl::size len)
Definition str.cpp:296
static bool isDigit(char c)
Definition str.h:101
bool is() const noexcept
Definition variant.h:106
T * ptr()
Definition variant.h:110
void visit(Visitor &visitor)
Definition variant.h:154
bool empty() const noexcept
Definition variant.h:104
Result type for promise operations.
constexpr remove_reference< T >::type && move(T &&t) noexcept
Definition move.h:27
JsonObject & get_empty_json_object()
Definition json.cpp:75
Optional< T > optional
Definition optional.h:14
string to_string(T value)
Definition str.h:957
decltype(nullptr) nullptr_t
Definition cstddef.h:11
shared_ptr< T > make_shared(Args &&... args)
Definition shared_ptr.h:348
fl::HashMap< fl::string, fl::shared_ptr< JsonValue > > JsonObject
Definition json.h:171
constexpr nullopt_t nullopt
Definition optional.h:11
fl::vector< fl::shared_ptr< JsonValue > > JsonArray
Definition json.h:170
HeapVector< T, Allocator > vector
Definition vector.h:1214
FL_DISABLE_WARNING_POP JsonValue & get_null_value()
Definition json.cpp:70
constexpr T && forward(typename remove_reference< T >::type &t) noexcept
IMPORTANT!
Definition crgb.h:20
Promise-based fluent API for FastLED - standalone async primitives.
void accept(const U &value)
Definition json.h:213
const T & fallback
Definition json.h:205
DefaultValueVisitor(const T &fb)
Definition json.h:209
void operator()(const T &value)
Definition json.h:219
Error type for promises.
Definition promise.h:53
fl::optional< double > result
Definition json.h:521
fl::optional< FloatType > result
Definition json.h:423
void accept(const U &value)
Definition json.h:426
void operator()(const FloatType &value)
Definition json.h:431
fl::optional< int64_t > result
Definition json.h:366
void accept(const U &value)
Definition json.h:285
fl::optional< IntType > result
Definition json.h:282
fl::enable_if<!fl::is_same< T, int64_t >::value &&!fl::is_same< T, double >::value, void >::type operator()(const IntType &value)
Definition json.h:293
void operator()(const JsonArray &)
Definition json.h:841
void accept(const T &value)
Definition json.h:835
KeyValue(const fl::string &key, const fl::shared_ptr< JsonValue > &value_ptr)
Definition json.h:1604
KeyValue(const fl::string &key, const fl::shared_ptr< JsonValue > &value_ptr)
Definition json.h:1550
fl::optional< double > as_double() const
Definition json.h:925
JsonValue(int64_t i) noexcept
Definition json.h:684
fl::optional< T > get() const
Definition json.h:1131
bool contains(size_t idx) const
Definition json.h:1433
bool is_audio() const noexcept
Definition json.h:883
bool is_object() const noexcept
Definition json.h:879
bool is_float() const noexcept
Definition json.h:823
JsonValue & operator=(const JsonValue &other)
Definition json.h:721
bool is_bool() const noexcept
Definition json.h:811
size_t size() const
Definition json.h:1478
T operator|(const T &fallback) const
Definition json.h:1418
bool is_double() const noexcept
Definition json.h:819
bool is_int() const noexcept
Definition json.h:815
friend const_iterator begin(const JsonValue &v)
Definition json.h:1359
bool is_floats() const noexcept
Definition json.h:891
auto visit(Visitor &&visitor) -> decltype(visitor(fl::nullptr_t{}))
Definition json.h:797
bool is_string() const noexcept
Definition json.h:826
JsonValue() noexcept
Definition json.h:681
static fl::shared_ptr< JsonValue > from_char(char c)
Definition json.h:791
JsonValue & operator[](size_t idx)
Definition json.h:1363
bool is_generic_array() const noexcept
Definition json.h:873
bool is_array() const noexcept
Definition json.h:865
iterator end()
Definition json.h:1152
friend class SerializerVisitor
Definition json.h:1510
friend class Json
Definition json.h:658
fl::optional< JsonObject > as_object()
Definition json.h:998
JsonValue(bool b) noexcept
Definition json.h:683
JsonValue::const_iterator const_iterator
Definition json.h:676
fl::optional< float > as_float()
Definition json.h:936
variant_t data
Definition json.h:678
fl::vector< fl::string > getObjectKeys() const
Definition json.h:1475
array_iterator< T > begin_array()
Definition json.h:1325
fl::optional< fl::vector< float > > as_floats()
Definition json.h:1013
static fl::shared_ptr< JsonValue > parse(const fl::string &txt)
Definition json.cpp:81
JsonValue::iterator iterator
Definition json.h:675
fl::vector< fl::string > keys() const
Definition json.h:1463
bool is_null() const noexcept
Definition json.h:807
friend const_iterator end(const JsonValue &v)
Definition json.h:1360
fl::optional< fl::vector< int16_t > > as_audio()
Definition json.h:1003
fl::optional< JsonArray > as_array()
Definition json.h:963
fl::optional< fl::vector< uint8_t > > as_bytes()
Definition json.h:1008
fl::optional< fl::string > as_string()
Definition json.h:952
fl::string to_string() const
Definition json.cpp:277
fl::Variant< fl::nullptr_t, bool, int64_t, float, fl::string, JsonArray, JsonObject, fl::vector< int16_t >, fl::vector< uint8_t >, fl::vector< float > > variant_t
Definition json.h:662
JsonValue(float f) noexcept
Definition json.h:685
fl::optional< bool > as_bool()
Definition json.h:897
JsonValue(const JsonArray &a)
Definition json.h:688
T as_or(const T &fallback) const
Definition json.h:1426
bool is_bytes() const noexcept
Definition json.h:887
JsonValue(const fl::string &s)
Definition json.h:686
array_iterator< T > end_array()
Definition json.h:1333
fl::optional< int64_t > as_int()
Definition json.h:902
iterator begin()
Definition json.h:1143
const Error & get_error() const
Definition json.h:184
ParseResult(const T &val)
Definition json.h:179
bool has_error() const
Definition json.h:182
const T & get_value() const
Definition json.h:183
Error error
Definition json.h:177
void operator()(const fl::string &value)
Definition json.h:616
void accept(const U &value)
Definition json.h:611
fl::optional< fl::string > result
Definition json.h:608
static constexpr bool value
static constexpr bool value
static constexpr bool value
Definition type_traits.h:84
static constexpr bool value
T1 first
Definition pair.h:14
T2 second
Definition pair.h:15