Coverage Report

Created: 2026-06-15 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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