summaryrefslogtreecommitdiff
path: root/include/lib/ArduinoJson/JsonVariant.hpp
blob: 8326cbe86d3f3019695ea8c9de88cef119173cc8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License

#pragma once

#include <stddef.h>
#include <stdint.h>  // for uint8_t

#include "Data/JsonVariantContent.hpp"
#include "Data/JsonVariantDefault.hpp"
#include "Data/JsonVariantType.hpp"
#include "JsonVariantBase.hpp"
#include "RawJson.hpp"
#include "Serialization/JsonPrintable.hpp"
#include "TypeTraits/EnableIf.hpp"
#include "TypeTraits/IsChar.hpp"
#include "TypeTraits/IsFloatingPoint.hpp"
#include "TypeTraits/IsIntegral.hpp"
#include "TypeTraits/IsSame.hpp"
#include "TypeTraits/IsSignedIntegral.hpp"
#include "TypeTraits/IsUnsignedIntegral.hpp"
#include "TypeTraits/RemoveConst.hpp"
#include "TypeTraits/RemoveReference.hpp"

namespace ArduinoJson {

// Forward declarations.
class JsonArray;
class JsonObject;

// A variant that can be a any value serializable to a JSON value.
//
// It can be set to:
// - a boolean
// - a char, short, int or a long (signed or unsigned)
// - a string (const char*)
// - a reference to a JsonArray or JsonObject
class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
  template <typename Print>
  friend class Internals::JsonSerializer;

 public:
  // Creates an uninitialized JsonVariant
  JsonVariant() : _type(Internals::JSON_UNDEFINED) {}

  // Create a JsonVariant containing a boolean value.
  // It will be serialized as "true" or "false" in JSON.
  JsonVariant(bool value) {
    using namespace Internals;
    _type = JSON_BOOLEAN;
    _content.asInteger = static_cast<JsonUInt>(value);
  }

  // Create a JsonVariant containing a floating point value.
  // JsonVariant(double value);
  // JsonVariant(float value);
  template <typename T>
  JsonVariant(T value, typename Internals::EnableIf<
                           Internals::IsFloatingPoint<T>::value>::type * = 0) {
    using namespace Internals;
    _type = JSON_FLOAT;
    _content.asFloat = static_cast<JsonFloat>(value);
  }
  template <typename T>
  DEPRECATED("Second argument is not supported anymore")
  JsonVariant(T value, uint8_t,
              typename Internals::EnableIf<
                  Internals::IsFloatingPoint<T>::value>::type * = 0) {
    using namespace Internals;
    _type = JSON_FLOAT;
    _content.asFloat = static_cast<JsonFloat>(value);
  }

  // Create a JsonVariant containing an integer value.
  // JsonVariant(char)
  // JsonVariant(signed short)
  // JsonVariant(signed int)
  // JsonVariant(signed long)
  // JsonVariant(signed char)
  template <typename T>
  JsonVariant(
      T value,
      typename Internals::EnableIf<Internals::IsSignedIntegral<T>::value ||
                                   Internals::IsSame<T, char>::value>::type * =
          0) {
    using namespace Internals;
    if (value >= 0) {
      _type = JSON_POSITIVE_INTEGER;
      _content.asInteger = static_cast<JsonUInt>(value);
    } else {
      _type = JSON_NEGATIVE_INTEGER;
      _content.asInteger = static_cast<JsonUInt>(-value);
    }
  }
  // JsonVariant(unsigned short)
  // JsonVariant(unsigned int)
  // JsonVariant(unsigned long)
  template <typename T>
  JsonVariant(T value,
              typename Internals::EnableIf<
                  Internals::IsUnsignedIntegral<T>::value>::type * = 0) {
    using namespace Internals;
    _type = JSON_POSITIVE_INTEGER;
    _content.asInteger = static_cast<JsonUInt>(value);
  }

  // Create a JsonVariant containing a string.
  // JsonVariant(const char*);
  // JsonVariant(const signed char*);
  // JsonVariant(const unsigned char*);
  template <typename TChar>
  JsonVariant(
      const TChar *value,
      typename Internals::EnableIf<Internals::IsChar<TChar>::value>::type * =
          0) {
    _type = Internals::JSON_STRING;
    _content.asString = reinterpret_cast<const char *>(value);
  }

  // Create a JsonVariant containing an unparsed string
  JsonVariant(Internals::RawJsonString<const char *> value) {
    _type = Internals::JSON_UNPARSED;
    _content.asString = value;
  }

  // Create a JsonVariant containing a reference to an array.
  // CAUTION: we are lying about constness, because the array can be modified if
  // the variant is converted back to a JsonArray&
  JsonVariant(const JsonArray &array);

  // Create a JsonVariant containing a reference to an object.
  // CAUTION: we are lying about constness, because the object can be modified
  // if the variant is converted back to a JsonObject&
  JsonVariant(const JsonObject &object);

  // Get the variant as the specified type.
  //
  // char as<char>() const;
  // signed char as<signed char>() const;
  // signed short as<signed short>() const;
  // signed int as<signed int>() const;
  // signed long as<signed long>() const;
  // unsigned char as<unsigned char>() const;
  // unsigned short as<unsigned short>() const;
  // unsigned int as<unsigned int>() const;
  // unsigned long as<unsigned long>() const;
  template <typename T>
  const typename Internals::EnableIf<Internals::IsIntegral<T>::value, T>::type
  as() const {
    return variantAsInteger<T>();
  }
  // bool as<bool>() const
  template <typename T>
  const typename Internals::EnableIf<Internals::IsSame<T, bool>::value, T>::type
  as() const {
    return variantAsInteger<int>() != 0;
  }
  //
  // double as<double>() const;
  // float as<float>() const;
  template <typename T>
  const typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value,
                                     T>::type
  as() const {
    return variantAsFloat<T>();
  }
  //
  // const char* as<const char*>() const;
  // const char* as<char*>() const;
  template <typename T>
  typename Internals::EnableIf<Internals::IsSame<T, const char *>::value ||
                                   Internals::IsSame<T, char *>::value,
                               const char *>::type
  as() const {
    return variantAsString();
  }
  //
  // std::string as<std::string>() const;
  // String as<String>() const;
  template <typename T>
  typename Internals::EnableIf<Internals::StringTraits<T>::has_append, T>::type
  as() const {
    const char *cstr = variantAsString();
    if (cstr) return T(cstr);
    T s;
    printTo(s);
    return s;
  }
  //
  // JsonArray& as<JsonArray> const;
  // JsonArray& as<JsonArray&> const;
  template <typename T>
  typename Internals::EnableIf<
      Internals::IsSame<typename Internals::RemoveReference<T>::type,
                        JsonArray>::value,
      JsonArray &>::type
  as() const {
    return variantAsArray();
  }
  //
  // const JsonArray& as<const JsonArray&> const;
  template <typename T>
  typename Internals::EnableIf<
      Internals::IsSame<typename Internals::RemoveReference<T>::type,
                        const JsonArray>::value,
      const JsonArray &>::type
  as() const {
    return variantAsArray();
  }
  //
  // JsonObject& as<JsonObject> const;
  // JsonObject& as<JsonObject&> const;
  template <typename T>
  typename Internals::EnableIf<
      Internals::IsSame<typename Internals::RemoveReference<T>::type,
                        JsonObject>::value,
      JsonObject &>::type
  as() const {
    return variantAsObject();
  }
  //
  // JsonObject& as<const JsonObject> const;
  // JsonObject& as<const JsonObject&> const;
  template <typename T>
  typename Internals::EnableIf<
      Internals::IsSame<typename Internals::RemoveReference<T>::type,
                        const JsonObject>::value,
      const JsonObject &>::type
  as() const {
    return variantAsObject();
  }
  //
  // JsonVariant as<JsonVariant> const;
  template <typename T>
  typename Internals::EnableIf<Internals::IsSame<T, JsonVariant>::value,
                               T>::type
  as() const {
    return *this;
  }

  // Tells weither the variant has the specified type.
  // Returns true if the variant has type type T, false otherwise.
  //
  // bool is<char>() const;
  // bool is<signed char>() const;
  // bool is<signed short>() const;
  // bool is<signed int>() const;
  // bool is<signed long>() const;
  // bool is<unsigned char>() const;
  // bool is<unsigned short>() const;
  // bool is<unsigned int>() const;
  // bool is<unsigned long>() const;
  template <typename T>
  typename Internals::EnableIf<Internals::IsIntegral<T>::value, bool>::type is()
      const {
    return variantIsInteger();
  }
  //
  // bool is<double>() const;
  // bool is<float>() const;
  template <typename T>
  typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value, bool>::type
  is() const {
    return variantIsFloat();
  }
  //
  // bool is<bool>() const
  template <typename T>
  typename Internals::EnableIf<Internals::IsSame<T, bool>::value, bool>::type
  is() const {
    return variantIsBoolean();
  }
  //
  // bool is<const char*>() const;
  // bool is<char*>() const;
  template <typename T>
  typename Internals::EnableIf<Internals::IsSame<T, const char *>::value ||
                                   Internals::IsSame<T, char *>::value,
                               bool>::type
  is() const {
    return variantIsString();
  }
  //
  // bool is<JsonArray> const;
  // bool is<JsonArray&> const;
  // bool is<const JsonArray&> const;
  template <typename T>
  typename Internals::EnableIf<
      Internals::IsSame<typename Internals::RemoveConst<
                            typename Internals::RemoveReference<T>::type>::type,
                        JsonArray>::value,
      bool>::type
  is() const {
    return variantIsArray();
  }
  //
  // bool is<JsonObject> const;
  // bool is<JsonObject&> const;
  // bool is<const JsonObject&> const;
  template <typename T>
  typename Internals::EnableIf<
      Internals::IsSame<typename Internals::RemoveConst<
                            typename Internals::RemoveReference<T>::type>::type,
                        JsonObject>::value,
      bool>::type
  is() const {
    return variantIsObject();
  }

  // Returns true if the variant has a value
  bool success() const {
    return _type != Internals::JSON_UNDEFINED;
  }

 private:
  JsonArray &variantAsArray() const;
  JsonObject &variantAsObject() const;
  const char *variantAsString() const;
  template <typename T>
  T variantAsFloat() const;
  template <typename T>
  T variantAsInteger() const;
  bool variantIsBoolean() const;
  bool variantIsFloat() const;
  bool variantIsInteger() const;
  bool variantIsArray() const {
    return _type == Internals::JSON_ARRAY;
  }
  bool variantIsObject() const {
    return _type == Internals::JSON_OBJECT;
  }
  bool variantIsString() const {
    return _type == Internals::JSON_STRING ||
           (_type == Internals::JSON_UNPARSED && _content.asString &&
            !strcmp("null", _content.asString));
  }

  // The current type of the variant
  Internals::JsonVariantType _type;

  // The various alternatives for the value of the variant.
  Internals::JsonVariantContent _content;
};

DEPRECATED("Decimal places are ignored, use the float value instead")
inline JsonVariant float_with_n_digits(float value, uint8_t) {
  return JsonVariant(value);
}

DEPRECATED("Decimal places are ignored, use the double value instead")
inline JsonVariant double_with_n_digits(double value, uint8_t) {
  return JsonVariant(value);
}
}