/src/arduinojson/src/ArduinoJson/Variant/ConverterImpl.hpp
Line | Count | Source |
1 | | // ArduinoJson - https://arduinojson.org |
2 | | // Copyright © 2014-2025, Benoit BLANCHON |
3 | | // MIT License |
4 | | |
5 | | #pragma once |
6 | | |
7 | | #include <ArduinoJson/Json/JsonSerializer.hpp> |
8 | | #include <ArduinoJson/Memory/StringBuilder.hpp> |
9 | | #include <ArduinoJson/Polyfills/utility.hpp> |
10 | | #include <ArduinoJson/Variant/JsonVariantConst.hpp> |
11 | | |
12 | | #if ARDUINOJSON_ENABLE_STD_STRING |
13 | | # include <string> |
14 | | #endif |
15 | | |
16 | | #if ARDUINOJSON_ENABLE_STRING_VIEW |
17 | | # include <string_view> |
18 | | #endif |
19 | | |
20 | | ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE |
21 | | |
22 | | template <typename T, typename Enable> |
23 | | struct Converter { |
24 | | static_assert(!detail::is_same<T, char>::value, |
25 | | "type 'char' is not supported, use 'signed char', 'unsigned " |
26 | | "char' or another integer type instead"); |
27 | | |
28 | | static auto toJson(const T& src, JsonVariant dst) |
29 | | -> decltype(convertToJson(src, dst)) { |
30 | | // clang-format off |
31 | | return convertToJson(src, dst); // Error here? See https://arduinojson.org/v7/unsupported-set/ |
32 | | // clang-format on |
33 | | } |
34 | | |
35 | | static detail::decay_t<T> fromJson(JsonVariantConst src) { |
36 | | static_assert(!detail::is_same<T, char*>::value, |
37 | | "type 'char*' is not supported, use 'const char*' instead"); |
38 | | |
39 | | // clang-format off |
40 | | T result; // Error here? See https://arduinojson.org/v7/non-default-constructible/ |
41 | | convertFromJson(src, result); // Error here? See https://arduinojson.org/v7/unsupported-as/ |
42 | | // clang-format on |
43 | | return result; |
44 | | } |
45 | | |
46 | | static bool checkJson(JsonVariantConst src) { |
47 | | static_assert(!detail::is_same<T, char*>::value, |
48 | | "type 'char*' is not supported, use 'const char*' instead"); |
49 | | |
50 | | T dummy = T(); |
51 | | // clang-format off |
52 | | return canConvertFromJson(src, dummy); // Error here? See https://arduinojson.org/v7/unsupported-is/ |
53 | | // clang-format on |
54 | | } |
55 | | }; |
56 | | |
57 | | template <typename T> |
58 | | struct Converter<T, detail::enable_if_t<detail::is_integral<T>::value && |
59 | | !detail::is_same<bool, T>::value && |
60 | | !detail::is_same<char, T>::value>> |
61 | | : private detail::VariantAttorney { |
62 | 0 | static bool toJson(T src, JsonVariant dst) { |
63 | 0 | ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); |
64 | 0 | return getVariantImpl(dst).setInteger(src); |
65 | 0 | } Unexecuted instantiation: ArduinoJson::V742HB42::Converter<long, void>::toJson(long, ArduinoJson::V742HB42::JsonVariant) Unexecuted instantiation: ArduinoJson::V742HB42::Converter<unsigned long, void>::toJson(unsigned long, ArduinoJson::V742HB42::JsonVariant) |
66 | | |
67 | | static T fromJson(JsonVariantConst src) { |
68 | | ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); |
69 | | return getVariantImpl(src).template asIntegral<T>(); |
70 | | } |
71 | | |
72 | | static bool checkJson(JsonVariantConst src) { |
73 | | return getVariantImpl(src).template isInteger<T>(); |
74 | | } |
75 | | }; |
76 | | |
77 | | template <typename T> |
78 | | struct Converter<T, detail::enable_if_t<detail::is_enum<T>::value>> |
79 | | : private detail::VariantAttorney { |
80 | | static bool toJson(T src, JsonVariant dst) { |
81 | | return dst.set(static_cast<JsonInteger>(src)); |
82 | | } |
83 | | |
84 | | static T fromJson(JsonVariantConst src) { |
85 | | return static_cast<T>(getVariantImpl(src).template asIntegral<int>()); |
86 | | } |
87 | | |
88 | | static bool checkJson(JsonVariantConst src) { |
89 | | return getVariantImpl(src).template isInteger<int>(); |
90 | | } |
91 | | }; |
92 | | |
93 | | template <> |
94 | | struct Converter<bool> : private detail::VariantAttorney { |
95 | 0 | static bool toJson(bool src, JsonVariant dst) { |
96 | 0 | return getVariantImpl(dst).setBoolean(src); |
97 | 0 | } |
98 | | |
99 | 0 | static bool fromJson(JsonVariantConst src) { |
100 | 0 | return getVariantImpl(src).asBoolean(); |
101 | 0 | } |
102 | | |
103 | 0 | static bool checkJson(JsonVariantConst src) { |
104 | 0 | auto data = getData(src); |
105 | 0 | return data && data->isBoolean(); |
106 | 0 | } |
107 | | }; |
108 | | |
109 | | template <typename T> |
110 | | struct Converter<T, detail::enable_if_t<detail::is_floating_point<T>::value>> |
111 | | : private detail::VariantAttorney { |
112 | 0 | static bool toJson(T src, JsonVariant dst) { |
113 | 0 | return getVariantImpl(dst).setFloat(src); |
114 | 0 | } Unexecuted instantiation: ArduinoJson::V742HB42::Converter<float, void>::toJson(float, ArduinoJson::V742HB42::JsonVariant) Unexecuted instantiation: ArduinoJson::V742HB42::Converter<double, void>::toJson(double, ArduinoJson::V742HB42::JsonVariant) |
115 | | |
116 | | static T fromJson(JsonVariantConst src) { |
117 | | return getVariantImpl(src).template asFloat<T>(); |
118 | | } |
119 | | |
120 | | static bool checkJson(JsonVariantConst src) { |
121 | | auto data = getData(src); |
122 | | return data && data->isFloat(); |
123 | | } |
124 | | }; |
125 | | |
126 | | template <> |
127 | | struct Converter<const char*> : private detail::VariantAttorney { |
128 | 0 | static bool toJson(const char* src, JsonVariant dst) { |
129 | 0 | return getVariantImpl(dst).setString(detail::adaptString(src)); |
130 | 0 | } |
131 | | |
132 | 0 | static const char* fromJson(JsonVariantConst src) { |
133 | 0 | auto data = getData(src); |
134 | 0 | return data ? data->asString().c_str() : 0; |
135 | 0 | } |
136 | | |
137 | 0 | static bool checkJson(JsonVariantConst src) { |
138 | 0 | auto data = getData(src); |
139 | 0 | return data && data->isString(); |
140 | 0 | } |
141 | | }; |
142 | | |
143 | | template <> |
144 | | struct Converter<JsonString> : private detail::VariantAttorney { |
145 | 0 | static bool toJson(JsonString src, JsonVariant dst) { |
146 | 0 | return getVariantImpl(dst).setString(detail::adaptString(src)); |
147 | 0 | } |
148 | | |
149 | 0 | static JsonString fromJson(JsonVariantConst src) { |
150 | 0 | auto data = getData(src); |
151 | 0 | return data ? data->asString() : JsonString(); |
152 | 0 | } |
153 | | |
154 | 0 | static bool checkJson(JsonVariantConst src) { |
155 | 0 | auto data = getData(src); |
156 | 0 | return data && data->isString(); |
157 | 0 | } |
158 | | }; |
159 | | |
160 | | template <typename T> |
161 | | inline detail::enable_if_t<detail::IsString<T>::value, bool> convertToJson( |
162 | | const T& src, JsonVariant dst) { |
163 | | return detail::VariantAttorney::getVariantImpl(dst).setString( |
164 | | detail::adaptString(src)); |
165 | | } |
166 | | |
167 | | // SerializedValue<std::string> |
168 | | // SerializedValue<String> |
169 | | // SerializedValue<const __FlashStringHelper*> |
170 | | template <typename T> |
171 | | struct Converter<SerializedValue<T>> : private detail::VariantAttorney { |
172 | 0 | static bool toJson(SerializedValue<T> src, JsonVariant dst) { |
173 | 0 | return getVariantImpl(dst).setRawString( |
174 | 0 | detail::adaptString(src.data(), src.size())); |
175 | 0 | } |
176 | | }; |
177 | | |
178 | | template <> |
179 | | struct Converter<detail::nullptr_t> : private detail::VariantAttorney { |
180 | 0 | static bool toJson(detail::nullptr_t, JsonVariant dst) { |
181 | 0 | return getVariantImpl(dst).clear(); |
182 | 0 | } |
183 | 0 | static detail::nullptr_t fromJson(JsonVariantConst) { |
184 | 0 | return nullptr; |
185 | 0 | } |
186 | 0 | static bool checkJson(JsonVariantConst src) { |
187 | 0 | auto data = getData(src); |
188 | 0 | return data == 0 || data->isNull(); |
189 | 0 | } |
190 | | }; |
191 | | |
192 | | #if ARDUINOJSON_ENABLE_ARDUINO_STREAM |
193 | | |
194 | | namespace detail { |
195 | | class StringBuilderPrint : public Print { |
196 | | public: |
197 | | StringBuilderPrint(ResourceManager* resources) : copier_(resources) { |
198 | | copier_.startString(); |
199 | | } |
200 | | |
201 | | void save(VariantData* data) { |
202 | | ARDUINOJSON_ASSERT(!overflowed()); |
203 | | copier_.save(data); |
204 | | } |
205 | | |
206 | | size_t write(uint8_t c) { |
207 | | copier_.append(char(c)); |
208 | | return copier_.isValid() ? 1 : 0; |
209 | | } |
210 | | |
211 | | size_t write(const uint8_t* buffer, size_t size) { |
212 | | for (size_t i = 0; i < size; i++) { |
213 | | copier_.append(char(buffer[i])); |
214 | | if (!copier_.isValid()) |
215 | | return i; |
216 | | } |
217 | | return size; |
218 | | } |
219 | | |
220 | | bool overflowed() const { |
221 | | return !copier_.isValid(); |
222 | | } |
223 | | |
224 | | private: |
225 | | StringBuilder copier_; |
226 | | }; |
227 | | } // namespace detail |
228 | | |
229 | | inline bool convertToJson(const ::Printable& src, JsonVariant dst) { |
230 | | auto resources = detail::VariantAttorney::getResourceManager(dst); |
231 | | auto data = detail::VariantAttorney::getData(dst); |
232 | | if (!resources || !data) |
233 | | return false; |
234 | | detail::VariantImpl::clear(data, resources); |
235 | | detail::StringBuilderPrint print(resources); |
236 | | src.printTo(print); |
237 | | if (print.overflowed()) |
238 | | return false; |
239 | | print.save(data); |
240 | | return true; |
241 | | } |
242 | | |
243 | | #endif |
244 | | |
245 | | #if ARDUINOJSON_ENABLE_ARDUINO_STRING |
246 | | |
247 | | inline void convertFromJson(JsonVariantConst src, ::String& dst) { |
248 | | JsonString str = src.as<JsonString>(); |
249 | | if (str) |
250 | | dst = str.c_str(); |
251 | | else |
252 | | serializeJson(src, dst); |
253 | | } |
254 | | |
255 | | inline bool canConvertFromJson(JsonVariantConst src, const ::String&) { |
256 | | return src.is<JsonString>(); |
257 | | } |
258 | | |
259 | | #endif |
260 | | |
261 | | #if ARDUINOJSON_ENABLE_STD_STRING |
262 | | |
263 | 0 | inline void convertFromJson(JsonVariantConst src, std::string& dst) { |
264 | 0 | JsonString str = src.as<JsonString>(); |
265 | 0 | if (str) |
266 | 0 | dst.assign(str.c_str(), str.size()); |
267 | 0 | else |
268 | 0 | serializeJson(src, dst); |
269 | 0 | } |
270 | | |
271 | 0 | inline bool canConvertFromJson(JsonVariantConst src, const std::string&) { |
272 | 0 | return src.is<JsonString>(); |
273 | 0 | } |
274 | | |
275 | | #endif |
276 | | |
277 | | #if ARDUINOJSON_ENABLE_STRING_VIEW |
278 | | |
279 | | inline void convertFromJson(JsonVariantConst src, std::string_view& dst) { |
280 | | JsonString str = src.as<JsonString>(); |
281 | | if (str) // the standard doesn't allow passing null to the constructor |
282 | | dst = std::string_view(str.c_str(), str.size()); |
283 | | } |
284 | | |
285 | | inline bool canConvertFromJson(JsonVariantConst src, const std::string_view&) { |
286 | | return src.is<JsonString>(); |
287 | | } |
288 | | |
289 | | #endif |
290 | | |
291 | | template <> |
292 | | struct Converter<JsonArrayConst> : private detail::VariantAttorney { |
293 | 0 | static bool toJson(JsonArrayConst src, JsonVariant dst) { |
294 | 0 | if (src.isNull()) |
295 | 0 | return dst.set(nullptr); |
296 | 0 | else |
297 | 0 | return dst.to<JsonArray>().set(src); |
298 | 0 | } |
299 | | |
300 | 0 | static JsonArrayConst fromJson(JsonVariantConst src) { |
301 | 0 | return JsonArrayConst(getData(src), getResourceManager(src)); |
302 | 0 | } |
303 | | |
304 | 0 | static bool checkJson(JsonVariantConst src) { |
305 | 0 | auto data = getData(src); |
306 | 0 | return data && data->isArray(); |
307 | 0 | } |
308 | | }; |
309 | | |
310 | | template <> |
311 | | struct Converter<JsonArray> : private detail::VariantAttorney { |
312 | 0 | static bool toJson(JsonVariantConst src, JsonVariant dst) { |
313 | 0 | if (src.isNull()) |
314 | 0 | return dst.set(nullptr); |
315 | 0 | else |
316 | 0 | return dst.to<JsonArray>().set(src); |
317 | 0 | } |
318 | | |
319 | 0 | static JsonArray fromJson(JsonVariant src) { |
320 | 0 | return JsonArray(getData(src), getResourceManager(src)); |
321 | 0 | } |
322 | | |
323 | 0 | static bool checkJson(JsonVariant src) { |
324 | 0 | auto data = getData(src); |
325 | 0 | return data && data->isArray(); |
326 | 0 | } |
327 | | }; |
328 | | |
329 | | template <> |
330 | | struct Converter<JsonObjectConst> : private detail::VariantAttorney { |
331 | 0 | static bool toJson(JsonVariantConst src, JsonVariant dst) { |
332 | 0 | if (src.isNull()) |
333 | 0 | return dst.set(nullptr); |
334 | 0 | else |
335 | 0 | return dst.to<JsonObject>().set(src); |
336 | 0 | } |
337 | | |
338 | 0 | static JsonObjectConst fromJson(JsonVariantConst src) { |
339 | 0 | return JsonObjectConst(getData(src), getResourceManager(src)); |
340 | 0 | } |
341 | | |
342 | 0 | static bool checkJson(JsonVariantConst src) { |
343 | 0 | auto data = getData(src); |
344 | 0 | return data && data->isObject(); |
345 | 0 | } |
346 | | }; |
347 | | |
348 | | template <> |
349 | | struct Converter<JsonObject> : private detail::VariantAttorney { |
350 | 0 | static bool toJson(JsonVariantConst src, JsonVariant dst) { |
351 | 0 | if (src.isNull()) |
352 | 0 | return dst.set(nullptr); |
353 | 0 | else |
354 | 0 | return dst.to<JsonObject>().set(src); |
355 | 0 | } |
356 | | |
357 | 0 | static JsonObject fromJson(JsonVariant src) { |
358 | 0 | return JsonObject(getData(src), getResourceManager(src)); |
359 | 0 | } |
360 | | |
361 | 0 | static bool checkJson(JsonVariant src) { |
362 | 0 | auto data = getData(src); |
363 | 0 | return data && data->isObject(); |
364 | 0 | } |
365 | | }; |
366 | | |
367 | | ARDUINOJSON_END_PUBLIC_NAMESPACE |