FastLED 3.9.15
Loading...
Searching...
No Matches
json_to_type.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/stl/json.h"
6#include "fl/stl/tuple.h"
8#include "fl/stl/string.h"
9#include "fl/stl/move.h"
10#include "fl/stl/vector.h"
11#include "fl/stl/span.h"
13#include "fl/stl/noexcept.h"
14namespace fl {
15
16// Helper wrapper for const char* parameters in RPC
17// Stores fl::string internally, provides implicit conversion to const char*
20
22 ConstCharPtrWrapper(const fl::string& s) : value(s) {}
24
25 operator const char*() const { return value.c_str(); }
26 const char* c_str() const { return value.c_str(); }
27};
28
29// Helper wrapper for span<const T> parameters in RPC
30// Stores fl::vector<T> internally, provides implicit conversion to span<const T>
31template <typename T>
34
38
39 operator fl::span<const T>() const {
40 return value;
41 }
42
44 return value;
45 }
46};
47
48namespace detail {
49
50// =============================================================================
51// JsonToType - Primary template and specializations using visitor pattern
52// =============================================================================
53
54// Primary template declaration for JsonToType (with two template parameters for SFINAE)
55template <typename T, typename Enable = void>
56struct JsonToType {
58 (void)j;
60 result.setError("unsupported type for JSON conversion");
61 return fl::make_tuple(T(), result);
62 }
63};
64
65// Integer conversion (excluding bool) - uses visitor pattern
66template <typename T>
67struct JsonToType<T, typename fl::enable_if<fl::is_integral<T>::value && !fl::is_same<T, bool>::value>::type> {
69 // Access internal json_value directly instead of re-parsing
70 const json_value* val = j.internal_value();
71 if (!val) {
73 result.setError("failed to access JSON value");
74 return fl::make_tuple(T(), result);
75 }
76
78 val->data.visit(visitor);
79 return fl::make_tuple(visitor.mValue, visitor.mResult);
80 }
81};
82
83// Boolean conversion - uses visitor pattern
84template <>
85struct JsonToType<bool, void> {
87 // Access internal json_value directly instead of re-parsing
88 const json_value* val = j.internal_value();
89 if (!val) {
91 result.setError("failed to access JSON value");
92 return fl::make_tuple(bool(false), result);
93 }
94
95 JsonToBoolVisitor visitor;
96 val->data.visit(visitor);
97 return fl::make_tuple(visitor.mValue, visitor.mResult);
98 }
99};
100
101// Float/double conversion - uses visitor pattern
102template <typename T>
103struct JsonToType<T, typename fl::enable_if<fl::is_floating_point<T>::value>::type> {
105 // Access internal json_value directly instead of re-parsing
106 const json_value* val = j.internal_value();
107 if (!val) {
109 result.setError("failed to access JSON value");
110 return fl::make_tuple(T(), result);
111 }
112
113 JsonToFloatVisitor<T> visitor;
114 val->data.visit(visitor);
115 return fl::make_tuple(visitor.mValue, visitor.mResult);
116 }
117};
118
119// String conversion - uses visitor pattern
120template <>
121struct JsonToType<fl::string, void> {
123 // Access internal json_value directly instead of re-parsing
124 const json_value* val = j.internal_value();
125 if (!val) {
127 result.setError("failed to access JSON value");
129 }
130
131 JsonToStringVisitor visitor;
132 val->data.visit(visitor);
133 return fl::make_tuple(visitor.mValue, visitor.mResult);
134 }
135};
136
137// json identity conversion - pass json through unchanged
138// This enables RPC methods to accept fl::json parameters for dynamic typing
139template <>
140struct JsonToType<fl::json, void> {
142 TypeConversionResult result; // Success by default
143 return fl::make_tuple(j, result);
144 }
145};
146
147// ConstCharPtrWrapper conversion - converts JSON string to wrapper
148// The wrapper stores fl::string and converts to const char* on access
149template <>
152 // Reuse the string converter
153 auto stringResult = JsonToType<fl::string>::convert(j);
154 fl::string str = fl::get<0>(stringResult);
155 TypeConversionResult result = fl::get<1>(stringResult);
156
158 }
159};
160
161// ConstSpanWrapper conversion - converts JSON array to vector wrapper
162template <typename T>
163struct JsonToType<fl::ConstSpanWrapper<T>, void> {
166
167 if (!j.is_array()) {
168 result.setError("expected array for span parameter");
170 }
171
172 fl::vector<T> vec;
173 for (fl::size i = 0; i < j.size(); i++) {
174 auto elemResult = JsonToType<T>::convert(j[i]);
175 T elem = fl::get<0>(elemResult);
176 TypeConversionResult elemConvResult = fl::get<1>(elemResult);
177
178 if (elemConvResult.hasError()) {
179 result.setError("element " + fl::to_string(static_cast<fl::i64>(i)) + ": " + elemConvResult.errorMessage());
181 }
182
183 vec.push_back(elem);
184 }
185
187 }
188};
189
190// fl::vector<T> conversion - converts JSON array to vector
191// Works for any T that has a JsonToType specialization
192template <typename T>
193struct JsonToType<fl::vector<T>, void> {
196
197 if (!j.is_array()) {
198 result.setError("expected array for vector parameter");
200 }
201
202 fl::vector<T> vec;
203 for (fl::size i = 0; i < j.size(); i++) {
204 auto elemResult = JsonToType<T>::convert(j[i]);
205 T elem = fl::get<0>(elemResult);
206 TypeConversionResult elemConvResult = fl::get<1>(elemResult);
207
208 if (elemConvResult.hasError()) {
209 result.setError("element " + fl::to_string(static_cast<fl::i64>(i)) + ": " + elemConvResult.errorMessage());
211 }
212
213 vec.push_back(fl::move(elem));
214 }
215
216 return fl::make_tuple(fl::move(vec), result);
217 }
218};
219
220// fl::vector<fl::u8> specialization - accepts base64 string OR integer array.
221// Base64 strings provide compact binary transport for JSON-RPC.
222template <>
223struct JsonToType<fl::vector<fl::u8>, void> {
226
227 if (j.is_string()) {
228 // Decode base64 string to binary
229 fl::string encoded;
230 auto strResult = JsonToType<fl::string>::convert(j);
231 encoded = fl::get<0>(strResult);
232 TypeConversionResult strConvResult = fl::get<1>(strResult);
233 if (strConvResult.hasError()) {
234 return fl::make_tuple(fl::vector<fl::u8>(), strConvResult);
235 }
236 fl::vector<fl::u8> decoded = fl::base64_decode(encoded);
237 if (decoded.empty() && !encoded.empty()) {
238 result.setError("invalid base64 string");
240 }
241 return fl::make_tuple(fl::move(decoded), result);
242 }
243
244 if (j.is_array()) {
245 // Fall back to integer array
247 for (fl::size i = 0; i < j.size(); i++) {
248 auto elemResult = JsonToType<fl::u8>::convert(j[i]);
249 fl::u8 elem = fl::get<0>(elemResult);
250 TypeConversionResult elemConvResult = fl::get<1>(elemResult);
251 if (elemConvResult.hasError()) {
252 result.setError("element " + fl::to_string(static_cast<fl::i64>(i)) + ": " + elemConvResult.errorMessage());
254 }
255 vec.push_back(elem);
256 }
257 return fl::make_tuple(fl::move(vec), result);
258 }
259
260 result.setError("expected base64 string or integer array for byte vector");
262 }
263};
264
265} // namespace detail
266} // namespace fl
const fl::string & errorMessage() const
bool empty() const FL_NOEXCEPT
const json_value * internal_value() const FL_NOEXCEPT
Definition json.h:660
bool is_array() const FL_NOEXCEPT
Definition json.h:246
size_t size() const FL_NOEXCEPT
Definition json.h:633
bool is_string() const FL_NOEXCEPT
Definition json.h:245
bool empty() const FL_NOEXCEPT
void push_back(const T &value) FL_NOEXCEPT
Definition vector.h:624
FastLED's Elegant JSON Library: fl::json
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition s16x16x4.h:28
unsigned char u8
Definition s16x16x4.h:132
string to_string(T value) FL_NOEXCEPT
Definition string.h:450
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition move.h:28
fl::vector< fl::u8 > base64_decode(const fl::string &encoded)
fl::i64 i64
Definition s16x16x4.h:222
tuple< typename fl::decay< Ts >::type... > make_tuple(Ts &&... args) FL_NOEXCEPT
Definition tuple.h:104
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
pair_element< I, T1, T2 >::type & get(pair< T1, T2 > &p) FL_NOEXCEPT
Definition pair.h:115
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_NOEXCEPT
ConstCharPtrWrapper() FL_NOEXCEPT=default
ConstCharPtrWrapper(fl::string &&s)
const char * c_str() const
ConstSpanWrapper() FL_NOEXCEPT=default
ConstSpanWrapper(const fl::vector< T > &v)
fl::vector< int > value
fl::span< const T > get() const
TypeConversionResult mResult
TypeConversionResult mResult
static fl::tuple< bool, TypeConversionResult > convert(const json &j)
static fl::tuple< fl::ConstCharPtrWrapper, TypeConversionResult > convert(const json &j)
static fl::tuple< fl::ConstSpanWrapper< T >, TypeConversionResult > convert(const json &j)
static fl::tuple< fl::json, TypeConversionResult > convert(const json &j)
static fl::tuple< fl::string, TypeConversionResult > convert(const json &j)
static fl::tuple< fl::vector< T >, TypeConversionResult > convert(const json &j)
static fl::tuple< fl::vector< fl::u8 >, TypeConversionResult > convert(const json &j)
static fl::tuple< T, TypeConversionResult > convert(const json &j)
variant_t data
Definition types.h:700