summaryrefslogtreecommitdiff
path: root/include/lib/ArduinoJson/Variant
diff options
context:
space:
mode:
authorDaniel Friesel <daniel.friesel@uos.de>2021-05-12 09:12:09 +0200
committerDaniel Friesel <daniel.friesel@uos.de>2021-05-12 09:12:09 +0200
commit39895a677e5d370824e702cfe90ebc67737b8482 (patch)
treeff5b4cc9e373d33a795d50d9333e05549bd9f2b8 /include/lib/ArduinoJson/Variant
parent42e7fdf01c3a5701bb51e93ad6c650c3dbbc5450 (diff)
import ArduinoJson 6.18.0
Diffstat (limited to 'include/lib/ArduinoJson/Variant')
-rw-r--r--include/lib/ArduinoJson/Variant/Converter.hpp12
-rw-r--r--include/lib/ArduinoJson/Variant/ConverterImpl.hpp268
-rw-r--r--include/lib/ArduinoJson/Variant/SlotFunctions.hpp60
-rw-r--r--include/lib/ArduinoJson/Variant/VariantCompare.hpp208
-rw-r--r--include/lib/ArduinoJson/Variant/VariantContent.hpp59
-rw-r--r--include/lib/ArduinoJson/Variant/VariantData.hpp368
-rw-r--r--include/lib/ArduinoJson/Variant/VariantFunctions.hpp104
-rw-r--r--include/lib/ArduinoJson/Variant/VariantImpl.hpp143
-rw-r--r--include/lib/ArduinoJson/Variant/VariantOperators.hpp180
-rw-r--r--include/lib/ArduinoJson/Variant/VariantRef.hpp375
-rw-r--r--include/lib/ArduinoJson/Variant/VariantShortcuts.hpp23
-rw-r--r--include/lib/ArduinoJson/Variant/VariantSlot.hpp116
-rw-r--r--include/lib/ArduinoJson/Variant/VariantTag.hpp16
-rw-r--r--include/lib/ArduinoJson/Variant/VariantTo.hpp32
-rw-r--r--include/lib/ArduinoJson/Variant/Visitor.hpp54
15 files changed, 2018 insertions, 0 deletions
diff --git a/include/lib/ArduinoJson/Variant/Converter.hpp b/include/lib/ArduinoJson/Variant/Converter.hpp
new file mode 100644
index 0000000..476ca8f
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/Converter.hpp
@@ -0,0 +1,12 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename T, typename Enable = void>
+struct Converter;
+
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Variant/ConverterImpl.hpp b/include/lib/ArduinoJson/Variant/ConverterImpl.hpp
new file mode 100644
index 0000000..34e12bb
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/ConverterImpl.hpp
@@ -0,0 +1,268 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Strings/IsWriteableString.hpp>
+#include <ArduinoJson/Variant/VariantFunctions.hpp>
+#include <ArduinoJson/Variant/VariantRef.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename T, typename Enable>
+struct Converter {
+ static bool toJson(const T& src, VariantRef dst) {
+ // clang-format off
+ return convertToJson(src, dst); // Error here? See https://arduinojson.org/v6/unsupported-set/
+ // clang-format on
+ }
+
+ static T fromJson(VariantConstRef src) {
+ // clang-format off
+ T result; // Error here? See https://arduinojson.org/v6/non-default-constructible/
+ convertFromJson(src, result); // Error here? See https://arduinojson.org/v6/unsupported-as/
+ // clang-format on
+ return result;
+ }
+
+ static bool checkJson(VariantConstRef src) {
+ T dummy;
+ // clang-format off
+ return canConvertFromJson(src, dummy); // Error here? See https://arduinojson.org/v6/unsupported-is/
+ // clang-format on
+ }
+};
+
+template <typename T>
+struct Converter<
+ T, typename enable_if<is_integral<T>::value && !is_same<bool, T>::value &&
+ !is_same<char, T>::value>::type> {
+ static bool toJson(T src, VariantRef dst) {
+ VariantData* data = getData(dst);
+ ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
+ if (!data)
+ return false;
+ data->setInteger(src);
+ return true;
+ }
+
+ static T fromJson(VariantConstRef src) {
+ ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
+ const VariantData* data = getData(src);
+ return data ? data->asIntegral<T>() : T();
+ }
+
+ static bool checkJson(VariantConstRef src) {
+ const VariantData* data = getData(src);
+ return data && data->isInteger<T>();
+ }
+};
+
+template <typename T>
+struct Converter<T, typename enable_if<is_enum<T>::value>::type> {
+ static bool toJson(T src, VariantRef dst) {
+ return dst.set(static_cast<Integer>(src));
+ }
+
+ static T fromJson(VariantConstRef src) {
+ const VariantData* data = getData(src);
+ return data ? static_cast<T>(data->asIntegral<int>()) : T();
+ }
+
+ static bool checkJson(VariantConstRef src) {
+ const VariantData* data = getData(src);
+ return data && data->isInteger<int>();
+ }
+};
+
+template <>
+struct Converter<bool> {
+ static bool toJson(bool src, VariantRef dst) {
+ VariantData* data = getData(dst);
+ if (!data)
+ return false;
+ data->setBoolean(src);
+ return true;
+ }
+
+ static bool fromJson(VariantConstRef src) {
+ const VariantData* data = getData(src);
+ return data ? data->asBoolean() : false;
+ }
+
+ static bool checkJson(VariantConstRef src) {
+ const VariantData* data = getData(src);
+ return data && data->isBoolean();
+ }
+};
+
+template <typename T>
+struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> {
+ static bool toJson(T src, VariantRef dst) {
+ VariantData* data = getData(dst);
+ if (!data)
+ return false;
+ data->setFloat(static_cast<Float>(src));
+ return true;
+ }
+
+ static T fromJson(VariantConstRef src) {
+ const VariantData* data = getData(src);
+ return data ? data->asFloat<T>() : false;
+ }
+
+ static bool checkJson(VariantConstRef src) {
+ const VariantData* data = getData(src);
+ return data && data->isFloat();
+ }
+};
+
+template <>
+struct Converter<const char*> {
+ static bool toJson(const char* src, VariantRef dst) {
+ return variantSetString(getData(dst), adaptString(src), getPool(dst));
+ }
+
+ static const char* fromJson(VariantConstRef src) {
+ const VariantData* data = getData(src);
+ return data ? data->asString() : 0;
+ }
+
+ static bool checkJson(VariantConstRef src) {
+ const VariantData* data = getData(src);
+ return data && data->isString();
+ }
+};
+
+template <typename T>
+inline typename enable_if<IsString<T>::value, bool>::type convertToJson(
+ const T& src, VariantRef dst) {
+ VariantData* data = getData(dst);
+ MemoryPool* pool = getPool(dst);
+ return variantSetString(data, adaptString(src), pool);
+}
+
+template <typename T>
+inline typename enable_if<IsWriteableString<T>::value>::type convertFromJson(
+ VariantConstRef src, T& dst) {
+ const VariantData* data = getData(src);
+ const char* cstr = data != 0 ? data->asString() : 0;
+ if (cstr)
+ dst = cstr;
+ else
+ serializeJson(src, dst);
+}
+
+template <typename T>
+inline typename enable_if<IsWriteableString<T>::value, bool>::type
+canConvertFromJson(VariantConstRef src, const T&) {
+ const VariantData* data = getData(src);
+ return data && data->isString();
+}
+
+template <>
+struct Converter<SerializedValue<const char*> > {
+ static bool toJson(SerializedValue<const char*> src, VariantRef dst) {
+ VariantData* data = getData(dst);
+ if (!data)
+ return false;
+ data->setLinkedRaw(src);
+ return true;
+ }
+};
+
+// SerializedValue<std::string>
+// SerializedValue<String>
+// SerializedValue<const __FlashStringHelper*>
+template <typename T>
+struct Converter<SerializedValue<T>,
+ typename enable_if<!is_same<const char*, T>::value>::type> {
+ static bool toJson(SerializedValue<T> src, VariantRef dst) {
+ VariantData* data = getData(dst);
+ MemoryPool* pool = getPool(dst);
+ return data != 0 && data->setOwnedRaw(src, pool);
+ }
+};
+
+#if ARDUINOJSON_HAS_NULLPTR
+
+template <>
+struct Converter<decltype(nullptr)> {
+ static bool toJson(decltype(nullptr), VariantRef dst) {
+ variantSetNull(getData(dst));
+ return true;
+ }
+ static decltype(nullptr) fromJson(VariantConstRef) {
+ return nullptr;
+ }
+ static bool checkJson(VariantConstRef src) {
+ const VariantData* data = getData(src);
+ return data == 0 || data->isNull();
+ }
+};
+
+#endif
+
+#if ARDUINOJSON_ENABLE_ARDUINO_STREAM
+
+class MemoryPoolPrint : public Print {
+ public:
+ MemoryPoolPrint(MemoryPool* pool) : _pool(pool), _size(0) {
+ pool->getFreeZone(&_string, &_capacity);
+ }
+
+ const char* c_str() {
+ _string[_size++] = 0;
+ ARDUINOJSON_ASSERT(_size <= _capacity);
+ return _pool->saveStringFromFreeZone(_size);
+ }
+
+ size_t write(uint8_t c) {
+ if (_size >= _capacity)
+ return 0;
+
+ _string[_size++] = char(c);
+ return 1;
+ }
+
+ size_t write(const uint8_t* buffer, size_t size) {
+ if (_size + size >= _capacity) {
+ _size = _capacity; // mark as overflowed
+ return 0;
+ }
+ memcpy(&_string[_size], buffer, size);
+ _size += size;
+ return size;
+ }
+
+ bool overflowed() const {
+ return _size >= _capacity;
+ }
+
+ private:
+ MemoryPool* _pool;
+ size_t _size;
+ char* _string;
+ size_t _capacity;
+};
+
+inline bool convertToJson(const ::Printable& src, VariantRef dst) {
+ MemoryPool* pool = getPool(dst);
+ VariantData* data = getData(dst);
+ if (!pool || !data)
+ return false;
+ MemoryPoolPrint print(pool);
+ src.printTo(print);
+ if (print.overflowed()) {
+ pool->markAsOverflowed();
+ data->setNull();
+ return false;
+ }
+ data->setStringPointer(print.c_str(), storage_policies::store_by_copy());
+ return true;
+}
+
+#endif
+
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Variant/SlotFunctions.hpp b/include/lib/ArduinoJson/Variant/SlotFunctions.hpp
new file mode 100644
index 0000000..74ac5a7
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/SlotFunctions.hpp
@@ -0,0 +1,60 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Polyfills/assert.hpp>
+#include <ArduinoJson/Variant/VariantData.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename TAdaptedString>
+inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) {
+ if (!var)
+ return false;
+ return slotSetKey(var, key, pool, typename TAdaptedString::storage_policy());
+}
+
+template <typename TAdaptedString>
+inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool,
+ storage_policies::decide_at_runtime) {
+ if (key.isStatic()) {
+ return slotSetKey(var, key, pool, storage_policies::store_by_address());
+ } else {
+ return slotSetKey(var, key, pool, storage_policies::store_by_copy());
+ }
+}
+
+template <typename TAdaptedString>
+inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*,
+ storage_policies::store_by_address) {
+ ARDUINOJSON_ASSERT(var);
+ var->setKey(key.data(), storage_policies::store_by_address());
+ return true;
+}
+
+template <typename TAdaptedString>
+inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool,
+ storage_policies::store_by_copy) {
+ const char* dup = pool->saveString(key);
+ if (!dup)
+ return false;
+ ARDUINOJSON_ASSERT(var);
+ var->setKey(dup, storage_policies::store_by_copy());
+ return true;
+}
+
+inline size_t slotSize(const VariantSlot* var) {
+ size_t n = 0;
+ while (var) {
+ n++;
+ var = var->next();
+ }
+ return n;
+}
+
+inline VariantData* slotData(VariantSlot* slot) {
+ return reinterpret_cast<VariantData*>(slot);
+}
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Variant/VariantCompare.hpp b/include/lib/ArduinoJson/Variant/VariantCompare.hpp
new file mode 100644
index 0000000..025ef90
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/VariantCompare.hpp
@@ -0,0 +1,208 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Configuration.hpp>
+#include <ArduinoJson/Misc/Visitable.hpp>
+#include <ArduinoJson/Numbers/arithmeticCompare.hpp>
+#include <ArduinoJson/Polyfills/type_traits.hpp>
+#include <ArduinoJson/Strings/IsString.hpp>
+#include <ArduinoJson/Variant/Visitor.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+class CollectionData;
+
+struct ComparerBase : Visitor<CompareResult> {};
+
+template <typename T, typename Enable = void>
+struct Comparer;
+
+template <typename T>
+struct Comparer<T, typename enable_if<IsString<T>::value>::type>
+ : ComparerBase {
+ T rhs;
+
+ explicit Comparer(T value) : rhs(value) {}
+
+ CompareResult visitString(const char *lhs) {
+ int i = adaptString(rhs).compare(lhs);
+ if (i < 0)
+ return COMPARE_RESULT_GREATER;
+ else if (i > 0)
+ return COMPARE_RESULT_LESS;
+ else
+ return COMPARE_RESULT_EQUAL;
+ }
+
+ CompareResult visitNull() {
+ if (adaptString(rhs).isNull())
+ return COMPARE_RESULT_EQUAL;
+ else
+ return COMPARE_RESULT_DIFFER;
+ }
+};
+
+template <typename T>
+struct Comparer<T, typename enable_if<is_integral<T>::value ||
+ is_floating_point<T>::value>::type>
+ : ComparerBase {
+ T rhs;
+
+ explicit Comparer(T value) : rhs(value) {}
+
+ CompareResult visitFloat(Float lhs) {
+ return arithmeticCompare(lhs, rhs);
+ }
+
+ CompareResult visitSignedInteger(Integer lhs) {
+ return arithmeticCompare(lhs, rhs);
+ }
+
+ CompareResult visitUnsignedInteger(UInt lhs) {
+ return arithmeticCompare(lhs, rhs);
+ }
+
+ CompareResult visitBoolean(bool lhs) {
+ return visitUnsignedInteger(static_cast<UInt>(lhs));
+ }
+};
+
+struct NullComparer : ComparerBase {
+ CompareResult visitNull() {
+ return COMPARE_RESULT_EQUAL;
+ }
+};
+
+#if ARDUINOJSON_HAS_NULLPTR
+template <>
+struct Comparer<decltype(nullptr), void> : NullComparer {
+ explicit Comparer(decltype(nullptr)) : NullComparer() {}
+};
+#endif
+
+struct ArrayComparer : ComparerBase {
+ const CollectionData *_rhs;
+
+ explicit ArrayComparer(const CollectionData &rhs) : _rhs(&rhs) {}
+
+ CompareResult visitArray(const CollectionData &lhs) {
+ if (lhs.equalsArray(*_rhs))
+ return COMPARE_RESULT_EQUAL;
+ else
+ return COMPARE_RESULT_DIFFER;
+ }
+};
+
+struct ObjectComparer : ComparerBase {
+ const CollectionData *_rhs;
+
+ explicit ObjectComparer(const CollectionData &rhs) : _rhs(&rhs) {}
+
+ CompareResult visitObject(const CollectionData &lhs) {
+ if (lhs.equalsObject(*_rhs))
+ return COMPARE_RESULT_EQUAL;
+ else
+ return COMPARE_RESULT_DIFFER;
+ }
+};
+
+struct RawComparer : ComparerBase {
+ const char *_rhsData;
+ size_t _rhsSize;
+
+ explicit RawComparer(const char *rhsData, size_t rhsSize)
+ : _rhsData(rhsData), _rhsSize(rhsSize) {}
+
+ CompareResult visitRawJson(const char *lhsData, size_t lhsSize) {
+ size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize;
+ int n = memcmp(lhsData, _rhsData, size);
+ if (n < 0)
+ return COMPARE_RESULT_LESS;
+ else if (n > 0)
+ return COMPARE_RESULT_GREATER;
+ else
+ return COMPARE_RESULT_EQUAL;
+ }
+};
+
+template <typename T>
+struct Comparer<T, typename enable_if<IsVisitable<T>::value>::type>
+ : ComparerBase {
+ T rhs;
+
+ explicit Comparer(T value) : rhs(value) {}
+
+ CompareResult visitArray(const CollectionData &lhs) {
+ ArrayComparer comparer(lhs);
+ return accept(comparer);
+ }
+
+ CompareResult visitObject(const CollectionData &lhs) {
+ ObjectComparer comparer(lhs);
+ return accept(comparer);
+ }
+
+ CompareResult visitFloat(Float lhs) {
+ Comparer<Float> comparer(lhs);
+ return accept(comparer);
+ }
+
+ CompareResult visitString(const char *lhs) {
+ Comparer<const char *> comparer(lhs);
+ return accept(comparer);
+ }
+
+ CompareResult visitRawJson(const char *lhsData, size_t lhsSize) {
+ RawComparer comparer(lhsData, lhsSize);
+ return accept(comparer);
+ }
+
+ CompareResult visitSignedInteger(Integer lhs) {
+ Comparer<Integer> comparer(lhs);
+ return accept(comparer);
+ }
+
+ CompareResult visitUnsignedInteger(UInt lhs) {
+ Comparer<UInt> comparer(lhs);
+ return accept(comparer);
+ }
+
+ CompareResult visitBoolean(bool lhs) {
+ Comparer<bool> comparer(lhs);
+ return accept(comparer);
+ }
+
+ CompareResult visitNull() {
+ NullComparer comparer;
+ return accept(comparer);
+ }
+
+ private:
+ template <typename TComparer>
+ CompareResult accept(TComparer &comparer) {
+ CompareResult reversedResult = rhs.accept(comparer);
+ switch (reversedResult) {
+ case COMPARE_RESULT_GREATER:
+ return COMPARE_RESULT_LESS;
+ case COMPARE_RESULT_LESS:
+ return COMPARE_RESULT_GREATER;
+ default:
+ return reversedResult;
+ }
+ }
+};
+
+template <typename T1, typename T2>
+CompareResult compare(const T1 &lhs, const T2 &rhs) {
+ Comparer<T2> comparer(rhs);
+ return lhs.accept(comparer);
+}
+
+inline int variantCompare(const VariantData *a, const VariantData *b) {
+ return compare(VariantConstRef(a), VariantConstRef(b));
+}
+
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Variant/VariantContent.hpp b/include/lib/ArduinoJson/Variant/VariantContent.hpp
new file mode 100644
index 0000000..47bf09c
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/VariantContent.hpp
@@ -0,0 +1,59 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <stddef.h> // size_t
+
+#include <ArduinoJson/Collection/CollectionData.hpp>
+#include <ArduinoJson/Numbers/Float.hpp>
+#include <ArduinoJson/Numbers/Integer.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+//
+enum {
+ VALUE_MASK = 0x7F,
+
+ OWNED_VALUE_BIT = 0x01,
+ VALUE_IS_NULL = 0,
+ VALUE_IS_LINKED_RAW = 0x02,
+ VALUE_IS_OWNED_RAW = 0x03,
+ VALUE_IS_LINKED_STRING = 0x04,
+ VALUE_IS_OWNED_STRING = 0x05,
+
+ // CAUTION: no OWNED_VALUE_BIT below
+
+ VALUE_IS_BOOLEAN = 0x06,
+
+ NUMBER_BIT = 0x08,
+ VALUE_IS_UNSIGNED_INTEGER = 0x08,
+ VALUE_IS_SIGNED_INTEGER = 0x0A,
+ VALUE_IS_FLOAT = 0x0C,
+
+ COLLECTION_MASK = 0x60,
+ VALUE_IS_OBJECT = 0x20,
+ VALUE_IS_ARRAY = 0x40,
+
+ OWNED_KEY_BIT = 0x80
+};
+
+struct RawData {
+ const char *data;
+ size_t size;
+};
+
+union VariantContent {
+ Float asFloat;
+ bool asBoolean;
+ UInt asUnsignedInteger;
+ Integer asSignedInteger;
+ CollectionData asCollection;
+ const char *asString;
+ struct {
+ const char *data;
+ size_t size;
+ } asRaw;
+};
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Variant/VariantData.hpp b/include/lib/ArduinoJson/Variant/VariantData.hpp
new file mode 100644
index 0000000..82ae745
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/VariantData.hpp
@@ -0,0 +1,368 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Memory/MemoryPool.hpp>
+#include <ArduinoJson/Misc/SerializedValue.hpp>
+#include <ArduinoJson/Numbers/convertNumber.hpp>
+#include <ArduinoJson/Strings/RamStringAdapter.hpp>
+#include <ArduinoJson/Variant/VariantContent.hpp>
+
+// VariantData can't have a constructor (to be a POD), so we have no way to fix
+// this warning
+#if defined(__GNUC__)
+#if __GNUC__ >= 7
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#pragma GCC diagnostic ignored "-Wuninitialized"
+#endif
+#endif
+
+namespace ARDUINOJSON_NAMESPACE {
+
+class VariantData {
+ VariantContent _content; // must be first to allow cast from array to variant
+ uint8_t _flags;
+
+ public:
+ // Must be a POD!
+ // - no constructor
+ // - no destructor
+ // - no virtual
+ // - no inheritance
+ void init() {
+ _flags = 0;
+ }
+
+ template <typename TVisitor>
+ typename TVisitor::result_type accept(TVisitor &visitor) const {
+ switch (type()) {
+ case VALUE_IS_FLOAT:
+ return visitor.visitFloat(_content.asFloat);
+
+ case VALUE_IS_ARRAY:
+ return visitor.visitArray(_content.asCollection);
+
+ case VALUE_IS_OBJECT:
+ return visitor.visitObject(_content.asCollection);
+
+ case VALUE_IS_LINKED_STRING:
+ case VALUE_IS_OWNED_STRING:
+ return visitor.visitString(_content.asString);
+
+ case VALUE_IS_OWNED_RAW:
+ case VALUE_IS_LINKED_RAW:
+ return visitor.visitRawJson(_content.asRaw.data, _content.asRaw.size);
+
+ case VALUE_IS_SIGNED_INTEGER:
+ return visitor.visitSignedInteger(_content.asSignedInteger);
+
+ case VALUE_IS_UNSIGNED_INTEGER:
+ return visitor.visitUnsignedInteger(_content.asUnsignedInteger);
+
+ case VALUE_IS_BOOLEAN:
+ return visitor.visitBoolean(_content.asBoolean != 0);
+
+ default:
+ return visitor.visitNull();
+ }
+ }
+
+ template <typename T>
+ T asIntegral() const;
+
+ template <typename T>
+ T asFloat() const;
+
+ const char *asString() const;
+
+ bool asBoolean() const;
+
+ CollectionData *asArray() {
+ return isArray() ? &_content.asCollection : 0;
+ }
+
+ const CollectionData *asArray() const {
+ return const_cast<VariantData *>(this)->asArray();
+ }
+
+ CollectionData *asObject() {
+ return isObject() ? &_content.asCollection : 0;
+ }
+
+ const CollectionData *asObject() const {
+ return const_cast<VariantData *>(this)->asObject();
+ }
+
+ bool copyFrom(const VariantData &src, MemoryPool *pool) {
+ switch (src.type()) {
+ case VALUE_IS_ARRAY:
+ return toArray().copyFrom(src._content.asCollection, pool);
+ case VALUE_IS_OBJECT:
+ return toObject().copyFrom(src._content.asCollection, pool);
+ case VALUE_IS_OWNED_STRING:
+ return setString(RamStringAdapter(src._content.asString), pool);
+ case VALUE_IS_OWNED_RAW:
+ return setOwnedRaw(
+ serialized(src._content.asRaw.data, src._content.asRaw.size), pool);
+ default:
+ setType(src.type());
+ _content = src._content;
+ return true;
+ }
+ }
+
+ bool isArray() const {
+ return (_flags & VALUE_IS_ARRAY) != 0;
+ }
+
+ bool isBoolean() const {
+ return type() == VALUE_IS_BOOLEAN;
+ }
+
+ bool isCollection() const {
+ return (_flags & COLLECTION_MASK) != 0;
+ }
+
+ template <typename T>
+ bool isInteger() const {
+ switch (type()) {
+ case VALUE_IS_UNSIGNED_INTEGER:
+ return canConvertNumber<T>(_content.asUnsignedInteger);
+
+ case VALUE_IS_SIGNED_INTEGER:
+ return canConvertNumber<T>(_content.asSignedInteger);
+
+ default:
+ return false;
+ }
+ }
+
+ bool isFloat() const {
+ return (_flags & NUMBER_BIT) != 0;
+ }
+
+ bool isString() const {
+ return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING;
+ }
+
+ bool isObject() const {
+ return (_flags & VALUE_IS_OBJECT) != 0;
+ }
+
+ bool isNull() const {
+ return type() == VALUE_IS_NULL;
+ }
+
+ bool isEnclosed() const {
+ return !isFloat();
+ }
+
+ void remove(size_t index) {
+ if (isArray())
+ _content.asCollection.removeElement(index);
+ }
+
+ template <typename TAdaptedString>
+ void remove(TAdaptedString key) {
+ if (isObject())
+ _content.asCollection.removeMember(key);
+ }
+
+ void setBoolean(bool value) {
+ setType(VALUE_IS_BOOLEAN);
+ _content.asBoolean = value;
+ }
+
+ void setFloat(Float value) {
+ setType(VALUE_IS_FLOAT);
+ _content.asFloat = value;
+ }
+
+ void setLinkedRaw(SerializedValue<const char *> value) {
+ if (value.data()) {
+ setType(VALUE_IS_LINKED_RAW);
+ _content.asRaw.data = value.data();
+ _content.asRaw.size = value.size();
+ } else {
+ setType(VALUE_IS_NULL);
+ }
+ }
+
+ template <typename T>
+ bool setOwnedRaw(SerializedValue<T> value, MemoryPool *pool) {
+ const char *dup = pool->saveString(adaptString(value.data(), value.size()));
+ if (dup) {
+ setType(VALUE_IS_OWNED_RAW);
+ _content.asRaw.data = dup;
+ _content.asRaw.size = value.size();
+ return true;
+ } else {
+ setType(VALUE_IS_NULL);
+ return false;
+ }
+ }
+
+ template <typename T>
+ typename enable_if<is_unsigned<T>::value>::type setInteger(T value) {
+ setType(VALUE_IS_UNSIGNED_INTEGER);
+ _content.asUnsignedInteger = static_cast<UInt>(value);
+ }
+
+ template <typename T>
+ typename enable_if<is_signed<T>::value>::type setInteger(T value) {
+ setType(VALUE_IS_SIGNED_INTEGER);
+ _content.asSignedInteger = value;
+ }
+
+ void setNull() {
+ setType(VALUE_IS_NULL);
+ }
+
+ void setStringPointer(const char *s, storage_policies::store_by_copy) {
+ ARDUINOJSON_ASSERT(s != 0);
+ setType(VALUE_IS_OWNED_STRING);
+ _content.asString = s;
+ }
+
+ void setStringPointer(const char *s, storage_policies::store_by_address) {
+ ARDUINOJSON_ASSERT(s != 0);
+ setType(VALUE_IS_LINKED_STRING);
+ _content.asString = s;
+ }
+
+ template <typename TAdaptedString>
+ bool setString(TAdaptedString value, MemoryPool *pool) {
+ return storeString(value, pool, typename TAdaptedString::storage_policy());
+ }
+
+ CollectionData &toArray() {
+ setType(VALUE_IS_ARRAY);
+ _content.asCollection.clear();
+ return _content.asCollection;
+ }
+
+ CollectionData &toObject() {
+ setType(VALUE_IS_OBJECT);
+ _content.asCollection.clear();
+ return _content.asCollection;
+ }
+
+ size_t memoryUsage() const {
+ switch (type()) {
+ case VALUE_IS_OWNED_STRING:
+ return strlen(_content.asString) + 1;
+ case VALUE_IS_OWNED_RAW:
+ return _content.asRaw.size;
+ case VALUE_IS_OBJECT:
+ case VALUE_IS_ARRAY:
+ return _content.asCollection.memoryUsage();
+ default:
+ return 0;
+ }
+ }
+
+ size_t nesting() const {
+ return isCollection() ? _content.asCollection.nesting() : 0;
+ }
+
+ size_t size() const {
+ return isCollection() ? _content.asCollection.size() : 0;
+ }
+
+ VariantData *addElement(MemoryPool *pool) {
+ if (isNull())
+ toArray();
+ if (!isArray())
+ return 0;
+ return _content.asCollection.addElement(pool);
+ }
+
+ VariantData *getElement(size_t index) const {
+ return isArray() ? _content.asCollection.getElement(index) : 0;
+ }
+
+ VariantData *getOrAddElement(size_t index, MemoryPool *pool) {
+ if (isNull())
+ toArray();
+ if (!isArray())
+ return 0;
+ return _content.asCollection.getOrAddElement(index, pool);
+ }
+
+ template <typename TAdaptedString>
+ VariantData *getMember(TAdaptedString key) const {
+ return isObject() ? _content.asCollection.getMember(key) : 0;
+ }
+
+ template <typename TAdaptedString>
+ VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool) {
+ if (isNull())
+ toObject();
+ if (!isObject())
+ return 0;
+ return _content.asCollection.getOrAddMember(key, pool);
+ }
+
+ void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) {
+ if (_flags & OWNED_VALUE_BIT)
+ _content.asString += stringDistance;
+ if (_flags & COLLECTION_MASK)
+ _content.asCollection.movePointers(stringDistance, variantDistance);
+ }
+
+ uint8_t type() const {
+ return _flags & VALUE_MASK;
+ }
+
+ private:
+ void setType(uint8_t t) {
+ _flags &= OWNED_KEY_BIT;
+ _flags |= t;
+ }
+
+ template <typename TAdaptedString>
+ inline bool storeString(TAdaptedString value, MemoryPool *pool,
+ storage_policies::decide_at_runtime) {
+ if (value.isStatic())
+ return storeString(value, pool, storage_policies::store_by_address());
+ else
+ return storeString(value, pool, storage_policies::store_by_copy());
+ }
+
+ template <typename TAdaptedString>
+ inline bool storeString(TAdaptedString value, MemoryPool *,
+ storage_policies::store_by_address) {
+ if (value.isNull())
+ setNull();
+ else
+ setStringPointer(value.data(), storage_policies::store_by_address());
+ return true;
+ }
+
+ template <typename TAdaptedString>
+ inline bool storeString(TAdaptedString value, MemoryPool *pool,
+ storage_policies::store_by_copy) {
+ if (value.isNull()) {
+ setNull();
+ return true;
+ }
+ const char *copy = pool->saveString(value);
+ if (!copy) {
+ setNull();
+ return false;
+ }
+ setStringPointer(copy, storage_policies::store_by_copy());
+ return true;
+ }
+};
+
+} // namespace ARDUINOJSON_NAMESPACE
+
+#if defined(__GNUC__)
+#if __GNUC__ >= 8
+#pragma GCC diagnostic pop
+#endif
+#endif
diff --git a/include/lib/ArduinoJson/Variant/VariantFunctions.hpp b/include/lib/ArduinoJson/Variant/VariantFunctions.hpp
new file mode 100644
index 0000000..3fc9cbb
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/VariantFunctions.hpp
@@ -0,0 +1,104 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Polyfills/attributes.hpp>
+#include <ArduinoJson/Variant/VariantData.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename TVisitor>
+inline typename TVisitor::result_type variantAccept(const VariantData *var,
+ TVisitor &visitor) {
+ if (var != 0)
+ return var->accept(visitor);
+ else
+ return visitor.visitNull();
+}
+
+inline const CollectionData *variantAsArray(const VariantData *var) {
+ return var != 0 ? var->asArray() : 0;
+}
+
+inline const CollectionData *variantAsObject(const VariantData *var) {
+ return var != 0 ? var->asObject() : 0;
+}
+
+inline CollectionData *variantAsObject(VariantData *var) {
+ return var != 0 ? var->asObject() : 0;
+}
+
+inline bool variantCopyFrom(VariantData *dst, const VariantData *src,
+ MemoryPool *pool) {
+ if (!dst)
+ return false;
+ if (!src) {
+ dst->setNull();
+ return true;
+ }
+ return dst->copyFrom(*src, pool);
+}
+
+inline int variantCompare(const VariantData *a, const VariantData *b);
+
+inline void variantSetNull(VariantData *var) {
+ if (!var)
+ return;
+ var->setNull();
+}
+
+template <typename TAdaptedString>
+inline bool variantSetString(VariantData *var, TAdaptedString value,
+ MemoryPool *pool) {
+ if (!var)
+ return false;
+ return var->setString(value, pool);
+}
+
+inline size_t variantSize(const VariantData *var) {
+ return var != 0 ? var->size() : 0;
+}
+
+inline CollectionData *variantToArray(VariantData *var) {
+ if (!var)
+ return 0;
+ return &var->toArray();
+}
+
+inline CollectionData *variantToObject(VariantData *var) {
+ if (!var)
+ return 0;
+ return &var->toObject();
+}
+
+inline NO_INLINE VariantData *variantAddElement(VariantData *var,
+ MemoryPool *pool) {
+ return var != 0 ? var->addElement(pool) : 0;
+}
+
+inline NO_INLINE VariantData *variantGetOrAddElement(VariantData *var,
+ size_t index,
+ MemoryPool *pool) {
+ return var != 0 ? var->getOrAddElement(index, pool) : 0;
+}
+
+template <typename TChar>
+NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, TChar *key,
+ MemoryPool *pool) {
+ return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0;
+}
+
+template <typename TString>
+NO_INLINE VariantData *variantGetOrAddMember(VariantData *var,
+ const TString &key,
+ MemoryPool *pool) {
+ return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0;
+}
+
+inline bool variantIsNull(const VariantData *var) {
+ return var == 0 || var->isNull();
+}
+
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Variant/VariantImpl.hpp b/include/lib/ArduinoJson/Variant/VariantImpl.hpp
new file mode 100644
index 0000000..b91e584
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/VariantImpl.hpp
@@ -0,0 +1,143 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Array/ArrayRef.hpp>
+#include <ArduinoJson/Configuration.hpp>
+#include <ArduinoJson/Numbers/convertNumber.hpp>
+#include <ArduinoJson/Numbers/parseNumber.hpp>
+#include <ArduinoJson/Object/ObjectRef.hpp>
+#include <ArduinoJson/Variant/VariantRef.hpp>
+
+#include <string.h> // for strcmp
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename T>
+inline T VariantData::asIntegral() const {
+ switch (type()) {
+ case VALUE_IS_BOOLEAN:
+ return _content.asBoolean;
+ case VALUE_IS_UNSIGNED_INTEGER:
+ return convertNumber<T>(_content.asUnsignedInteger);
+ case VALUE_IS_SIGNED_INTEGER:
+ return convertNumber<T>(_content.asSignedInteger);
+ case VALUE_IS_LINKED_STRING:
+ case VALUE_IS_OWNED_STRING:
+ return parseNumber<T>(_content.asString);
+ case VALUE_IS_FLOAT:
+ return convertNumber<T>(_content.asFloat);
+ default:
+ return 0;
+ }
+}
+
+inline bool VariantData::asBoolean() const {
+ switch (type()) {
+ case VALUE_IS_BOOLEAN:
+ return _content.asBoolean;
+ case VALUE_IS_SIGNED_INTEGER:
+ case VALUE_IS_UNSIGNED_INTEGER:
+ return _content.asUnsignedInteger != 0;
+ case VALUE_IS_FLOAT:
+ return _content.asFloat != 0;
+ case VALUE_IS_NULL:
+ return false;
+ default:
+ return true;
+ }
+}
+
+// T = float/double
+template <typename T>
+inline T VariantData::asFloat() const {
+ switch (type()) {
+ case VALUE_IS_BOOLEAN:
+ return static_cast<T>(_content.asBoolean);
+ case VALUE_IS_UNSIGNED_INTEGER:
+ return static_cast<T>(_content.asUnsignedInteger);
+ case VALUE_IS_SIGNED_INTEGER:
+ return static_cast<T>(_content.asSignedInteger);
+ case VALUE_IS_LINKED_STRING:
+ case VALUE_IS_OWNED_STRING:
+ return parseNumber<T>(_content.asString);
+ case VALUE_IS_FLOAT:
+ return static_cast<T>(_content.asFloat);
+ default:
+ return 0;
+ }
+}
+
+inline const char *VariantData::asString() const {
+ switch (type()) {
+ case VALUE_IS_LINKED_STRING:
+ case VALUE_IS_OWNED_STRING:
+ return _content.asString;
+ default:
+ return 0;
+ }
+}
+
+template <typename T>
+inline typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type
+VariantRef::to() const {
+ return ArrayRef(_pool, variantToArray(_data));
+}
+
+template <typename T>
+typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type
+VariantRef::to() const {
+ return ObjectRef(_pool, variantToObject(_data));
+}
+
+template <typename T>
+typename enable_if<is_same<T, VariantRef>::value, VariantRef>::type
+VariantRef::to() const {
+ variantSetNull(_data);
+ return *this;
+}
+
+inline VariantConstRef VariantConstRef::getElement(size_t index) const {
+ return ArrayConstRef(_data != 0 ? _data->asArray() : 0)[index];
+}
+
+inline VariantRef VariantRef::addElement() const {
+ return VariantRef(_pool, variantAddElement(_data, _pool));
+}
+
+inline VariantRef VariantRef::getElement(size_t index) const {
+ return VariantRef(_pool, _data != 0 ? _data->getElement(index) : 0);
+}
+
+inline VariantRef VariantRef::getOrAddElement(size_t index) const {
+ return VariantRef(_pool, variantGetOrAddElement(_data, index, _pool));
+}
+
+template <typename TChar>
+inline VariantRef VariantRef::getMember(TChar *key) const {
+ return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0);
+}
+
+template <typename TString>
+inline typename enable_if<IsString<TString>::value, VariantRef>::type
+VariantRef::getMember(const TString &key) const {
+ return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0);
+}
+
+template <typename TChar>
+inline VariantRef VariantRef::getOrAddMember(TChar *key) const {
+ return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool));
+}
+
+template <typename TString>
+inline VariantRef VariantRef::getOrAddMember(const TString &key) const {
+ return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool));
+}
+
+inline VariantConstRef operator|(VariantConstRef preferedValue,
+ VariantConstRef defaultValue) {
+ return preferedValue ? preferedValue : defaultValue;
+}
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Variant/VariantOperators.hpp b/include/lib/ArduinoJson/Variant/VariantOperators.hpp
new file mode 100644
index 0000000..54174a4
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/VariantOperators.hpp
@@ -0,0 +1,180 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Misc/Visitable.hpp>
+#include <ArduinoJson/Numbers/arithmeticCompare.hpp>
+#include <ArduinoJson/Polyfills/attributes.hpp>
+#include <ArduinoJson/Polyfills/type_traits.hpp>
+#include <ArduinoJson/Variant/VariantTag.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename T1, typename T2>
+CompareResult compare(const T1 &lhs, const T2 &rhs); // VariantCompare.cpp
+
+template <typename TVariant>
+struct VariantOperators {
+ // Returns the default value if the VariantRef is undefined or incompatible
+ //
+ // int operator|(JsonVariant, int)
+ // float operator|(JsonVariant, float)
+ // bool operator|(JsonVariant, bool)
+ template <typename T>
+ friend
+ typename enable_if<!IsVariant<T>::value && !is_array<T>::value, T>::type
+ operator|(const TVariant &variant, const T &defaultValue) {
+ if (variant.template is<T>())
+ return variant.template as<T>();
+ else
+ return defaultValue;
+ }
+ //
+ // const char* operator|(JsonVariant, const char*)
+ friend const char *operator|(const TVariant &variant,
+ const char *defaultValue) {
+ if (variant.template is<const char *>())
+ return variant.template as<const char *>();
+ else
+ return defaultValue;
+ }
+ //
+ // JsonVariant operator|(JsonVariant, JsonVariant)
+ template <typename T>
+ friend typename enable_if<IsVariant<T>::value, typename T::variant_type>::type
+ operator|(const TVariant &variant, T defaultValue) {
+ if (variant)
+ return variant;
+ else
+ return defaultValue;
+ }
+
+ // value == TVariant
+ template <typename T>
+ friend bool operator==(T *lhs, TVariant rhs) {
+ return compare(rhs, lhs) == COMPARE_RESULT_EQUAL;
+ }
+ template <typename T>
+ friend bool operator==(const T &lhs, TVariant rhs) {
+ return compare(rhs, lhs) == COMPARE_RESULT_EQUAL;
+ }
+
+ // TVariant == value
+ template <typename T>
+ friend bool operator==(TVariant lhs, T *rhs) {
+ return compare(lhs, rhs) == COMPARE_RESULT_EQUAL;
+ }
+ template <typename T>
+ friend typename enable_if<!IsVisitable<T>::value, bool>::type operator==(
+ TVariant lhs, const T &rhs) {
+ return compare(lhs, rhs) == COMPARE_RESULT_EQUAL;
+ }
+
+ // value != TVariant
+ template <typename T>
+ friend bool operator!=(T *lhs, TVariant rhs) {
+ return compare(rhs, lhs) != COMPARE_RESULT_EQUAL;
+ }
+ template <typename T>
+ friend bool operator!=(const T &lhs, TVariant rhs) {
+ return compare(rhs, lhs) != COMPARE_RESULT_EQUAL;
+ }
+
+ // TVariant != value
+ template <typename T>
+ friend bool operator!=(TVariant lhs, T *rhs) {
+ return compare(lhs, rhs) != COMPARE_RESULT_EQUAL;
+ }
+ template <typename T>
+ friend typename enable_if<!IsVisitable<T>::value, bool>::type operator!=(
+ TVariant lhs, const T &rhs) {
+ return compare(lhs, rhs) != COMPARE_RESULT_EQUAL;
+ }
+
+ // value < TVariant
+ template <typename T>
+ friend bool operator<(T *lhs, TVariant rhs) {
+ return compare(rhs, lhs) == COMPARE_RESULT_GREATER;
+ }
+ template <typename T>
+ friend bool operator<(const T &lhs, TVariant rhs) {
+ return compare(rhs, lhs) == COMPARE_RESULT_GREATER;
+ }
+
+ // TVariant < value
+ template <typename T>
+ friend bool operator<(TVariant lhs, T *rhs) {
+ return compare(lhs, rhs) == COMPARE_RESULT_LESS;
+ }
+ template <typename T>
+ friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<(
+ TVariant lhs, const T &rhs) {
+ return compare(lhs, rhs) == COMPARE_RESULT_LESS;
+ }
+
+ // value <= TVariant
+ template <typename T>
+ friend bool operator<=(T *lhs, TVariant rhs) {
+ return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
+ }
+ template <typename T>
+ friend bool operator<=(const T &lhs, TVariant rhs) {
+ return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
+ }
+
+ // TVariant <= value
+ template <typename T>
+ friend bool operator<=(TVariant lhs, T *rhs) {
+ return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
+ }
+ template <typename T>
+ friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<=(
+ TVariant lhs, const T &rhs) {
+ return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
+ }
+
+ // value > TVariant
+ template <typename T>
+ friend bool operator>(T *lhs, TVariant rhs) {
+ return compare(rhs, lhs) == COMPARE_RESULT_LESS;
+ }
+ template <typename T>
+ friend bool operator>(const T &lhs, TVariant rhs) {
+ return compare(rhs, lhs) == COMPARE_RESULT_LESS;
+ }
+
+ // TVariant > value
+ template <typename T>
+ friend bool operator>(TVariant lhs, T *rhs) {
+ return compare(lhs, rhs) == COMPARE_RESULT_GREATER;
+ }
+ template <typename T>
+ friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>(
+ TVariant lhs, const T &rhs) {
+ return compare(lhs, rhs) == COMPARE_RESULT_GREATER;
+ }
+
+ // value >= TVariant
+ template <typename T>
+ friend bool operator>=(T *lhs, TVariant rhs) {
+ return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
+ }
+ template <typename T>
+ friend bool operator>=(const T &lhs, TVariant rhs) {
+ return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
+ }
+
+ // TVariant >= value
+ template <typename T>
+ friend bool operator>=(TVariant lhs, T *rhs) {
+ return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
+ }
+ template <typename T>
+ friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>=(
+ TVariant lhs, const T &rhs) {
+ return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
+ }
+};
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Variant/VariantRef.hpp b/include/lib/ArduinoJson/Variant/VariantRef.hpp
new file mode 100644
index 0000000..8d4c410
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/VariantRef.hpp
@@ -0,0 +1,375 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h> // for uint8_t
+
+#include <ArduinoJson/Memory/MemoryPool.hpp>
+#include <ArduinoJson/Misc/Visitable.hpp>
+#include <ArduinoJson/Polyfills/type_traits.hpp>
+#include <ArduinoJson/Strings/StringAdapters.hpp>
+#include <ArduinoJson/Variant/Converter.hpp>
+#include <ArduinoJson/Variant/VariantFunctions.hpp>
+#include <ArduinoJson/Variant/VariantOperators.hpp>
+#include <ArduinoJson/Variant/VariantRef.hpp>
+#include <ArduinoJson/Variant/VariantShortcuts.hpp>
+#include <ArduinoJson/Variant/VariantTag.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+// Forward declarations.
+class ArrayRef;
+class ObjectRef;
+
+// Contains the methods shared by VariantRef and VariantConstRef
+template <typename TData>
+class VariantRefBase : public VariantTag {
+ public:
+ FORCE_INLINE bool isNull() const {
+ return variantIsNull(_data);
+ }
+
+ FORCE_INLINE bool isUndefined() const {
+ return !_data;
+ }
+
+ FORCE_INLINE size_t memoryUsage() const {
+ return _data ? _data->memoryUsage() : 0;
+ }
+
+ FORCE_INLINE size_t nesting() const {
+ return _data ? _data->nesting() : 0;
+ }
+
+ size_t size() const {
+ return variantSize(_data);
+ }
+
+ protected:
+ VariantRefBase(TData *data) : _data(data) {}
+ TData *_data;
+
+ friend TData *getData(const VariantRefBase &variant) {
+ return variant._data;
+ }
+};
+
+// 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 ArrayRef or ObjectRef
+class VariantRef : public VariantRefBase<VariantData>,
+ public VariantOperators<VariantRef>,
+ public VariantShortcuts<VariantRef>,
+ public Visitable {
+ typedef VariantRefBase<VariantData> base_type;
+ friend class VariantConstRef;
+
+ public:
+ // Intenal use only
+ FORCE_INLINE VariantRef(MemoryPool *pool, VariantData *data)
+ : base_type(data), _pool(pool) {}
+
+ // Creates an uninitialized VariantRef
+ FORCE_INLINE VariantRef() : base_type(0), _pool(0) {}
+
+ FORCE_INLINE void clear() const {
+ return variantSetNull(_data);
+ }
+
+ template <typename T>
+ FORCE_INLINE bool set(const T &value) const {
+ return Converter<T>::toJson(value, *this);
+ }
+
+ FORCE_INLINE bool ARDUINOJSON_DEPRECATED(
+ "Support for char is deprecated, use int8_t or uint8_t instead")
+ set(char value) const {
+ return set<signed char>(value);
+ }
+
+ template <typename T>
+ FORCE_INLINE bool set(T *value) const {
+ return Converter<T *>::toJson(value, *this);
+ }
+
+ template <typename T>
+ FORCE_INLINE
+ typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value,
+ T>::type
+ as() const {
+ return Converter<T>::fromJson(*this);
+ }
+
+ template <typename T>
+ FORCE_INLINE typename enable_if<is_same<T, char *>::value, const char *>::type
+ ARDUINOJSON_DEPRECATED("Replace as<char*>() with as<const char*>()")
+ as() const {
+ return as<const char *>();
+ }
+
+ template <typename T>
+ FORCE_INLINE typename enable_if<is_same<T, char>::value, char>::type
+ ARDUINOJSON_DEPRECATED(
+ "Support for char is deprecated, use int8_t or uint8_t instead")
+ as() const {
+ return as<signed char>();
+ }
+
+ template <typename T>
+ FORCE_INLINE
+ typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value,
+ bool>::type
+ is() const {
+ return Converter<T>::checkJson(*this);
+ }
+
+ template <typename T>
+ FORCE_INLINE typename enable_if<is_same<T, char *>::value, bool>::type
+ ARDUINOJSON_DEPRECATED("Replace is<char*>() with is<const char*>()")
+ is() const {
+ return is<const char *>();
+ }
+
+ template <typename T>
+ FORCE_INLINE typename enable_if<is_same<T, char>::value, bool>::type
+ ARDUINOJSON_DEPRECATED(
+ "Support for char is deprecated, use int8_t or uint8_t instead")
+ is() const {
+ return is<signed char>();
+ }
+
+ template <typename T>
+ FORCE_INLINE operator T() const {
+ return as<T>();
+ }
+
+ template <typename TVisitor>
+ typename TVisitor::result_type accept(TVisitor &visitor) const {
+ return variantAccept(_data, visitor);
+ }
+
+ // Change the type of the variant
+ //
+ // ArrayRef to<ArrayRef>()
+ template <typename T>
+ typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type to() const;
+ //
+ // ObjectRef to<ObjectRef>()
+ template <typename T>
+ typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type to() const;
+ //
+ // ObjectRef to<VariantRef>()
+ template <typename T>
+ typename enable_if<is_same<T, VariantRef>::value, VariantRef>::type to()
+ const;
+
+ VariantRef addElement() const;
+
+ FORCE_INLINE VariantRef getElement(size_t) const;
+
+ FORCE_INLINE VariantRef getOrAddElement(size_t) const;
+
+ // getMember(const char*) const
+ // getMember(const __FlashStringHelper*) const
+ template <typename TChar>
+ FORCE_INLINE VariantRef getMember(TChar *) const;
+
+ // getMember(const std::string&) const
+ // getMember(const String&) const
+ template <typename TString>
+ FORCE_INLINE typename enable_if<IsString<TString>::value, VariantRef>::type
+ getMember(const TString &) const;
+
+ // getOrAddMember(char*) const
+ // getOrAddMember(const char*) const
+ // getOrAddMember(const __FlashStringHelper*) const
+ template <typename TChar>
+ FORCE_INLINE VariantRef getOrAddMember(TChar *) const;
+
+ // getOrAddMember(const std::string&) const
+ // getOrAddMember(const String&) const
+ template <typename TString>
+ FORCE_INLINE VariantRef getOrAddMember(const TString &) const;
+
+ FORCE_INLINE void remove(size_t index) const {
+ if (_data)
+ _data->remove(index);
+ }
+ // remove(char*) const
+ // remove(const char*) const
+ // remove(const __FlashStringHelper*) const
+ template <typename TChar>
+ FORCE_INLINE typename enable_if<IsString<TChar *>::value>::type remove(
+ TChar *key) const {
+ if (_data)
+ _data->remove(adaptString(key));
+ }
+ // remove(const std::string&) const
+ // remove(const String&) const
+ template <typename TString>
+ FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(
+ const TString &key) const {
+ if (_data)
+ _data->remove(adaptString(key));
+ }
+
+ private:
+ MemoryPool *_pool;
+
+ friend MemoryPool *getPool(const VariantRef &variant) {
+ return variant._pool;
+ }
+};
+
+class VariantConstRef : public VariantRefBase<const VariantData>,
+ public VariantOperators<VariantConstRef>,
+ public VariantShortcuts<VariantConstRef>,
+ public Visitable {
+ typedef VariantRefBase<const VariantData> base_type;
+ friend class VariantRef;
+
+ public:
+ VariantConstRef() : base_type(0) {}
+ VariantConstRef(const VariantData *data) : base_type(data) {}
+ VariantConstRef(VariantRef var) : base_type(var._data) {}
+
+ template <typename TVisitor>
+ typename TVisitor::result_type accept(TVisitor &visitor) const {
+ return variantAccept(_data, visitor);
+ }
+
+ template <typename T>
+ FORCE_INLINE
+ typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value,
+ T>::type
+ as() const {
+ return Converter<T>::fromJson(*this);
+ }
+
+ template <typename T>
+ FORCE_INLINE typename enable_if<is_same<T, char *>::value, const char *>::type
+ ARDUINOJSON_DEPRECATED("Replace as<char*>() with as<const char*>()")
+ as() const {
+ return as<const char *>();
+ }
+
+ template <typename T>
+ FORCE_INLINE typename enable_if<is_same<T, char>::value, char>::type
+ ARDUINOJSON_DEPRECATED(
+ "Support for char is deprecated, use int8_t or uint8_t instead")
+ as() const {
+ return as<signed char>();
+ }
+
+ template <typename T>
+ FORCE_INLINE
+ typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value,
+ bool>::type
+ is() const {
+ return Converter<T>::checkJson(*this);
+ }
+
+ template <typename T>
+ FORCE_INLINE typename enable_if<is_same<T, char *>::value, bool>::type
+ ARDUINOJSON_DEPRECATED("Replace is<char*>() with is<const char*>()")
+ is() const {
+ return is<const char *>();
+ }
+
+ template <typename T>
+ FORCE_INLINE typename enable_if<is_same<T, char>::value, bool>::type
+ ARDUINOJSON_DEPRECATED(
+ "Support for char is deprecated, use int8_t or uint8_t instead")
+ is() const {
+ return is<signed char>();
+ }
+
+ template <typename T>
+ FORCE_INLINE operator T() const {
+ return as<T>();
+ }
+
+ FORCE_INLINE VariantConstRef getElement(size_t) const;
+
+ FORCE_INLINE VariantConstRef operator[](size_t index) const {
+ return getElement(index);
+ }
+
+ // getMember(const std::string&) const
+ // getMember(const String&) const
+ template <typename TString>
+ FORCE_INLINE VariantConstRef getMember(const TString &key) const {
+ return VariantConstRef(
+ objectGetMember(variantAsObject(_data), adaptString(key)));
+ }
+
+ // getMember(char*) const
+ // getMember(const char*) const
+ // getMember(const __FlashStringHelper*) const
+ template <typename TChar>
+ FORCE_INLINE VariantConstRef getMember(TChar *key) const {
+ const CollectionData *obj = variantAsObject(_data);
+ return VariantConstRef(obj ? obj->getMember(adaptString(key)) : 0);
+ }
+
+ // operator[](const std::string&) const
+ // operator[](const String&) const
+ template <typename TString>
+ FORCE_INLINE
+ typename enable_if<IsString<TString>::value, VariantConstRef>::type
+ operator[](const TString &key) const {
+ return getMember(key);
+ }
+
+ // operator[](char*) const
+ // operator[](const char*) const
+ // operator[](const __FlashStringHelper*) const
+ template <typename TChar>
+ FORCE_INLINE
+ typename enable_if<IsString<TChar *>::value, VariantConstRef>::type
+ operator[](TChar *key) const {
+ return getMember(key);
+ }
+};
+
+template <>
+struct Converter<VariantRef> {
+ static bool toJson(VariantRef src, VariantRef dst) {
+ return variantCopyFrom(getData(dst), getData(src), getPool(dst));
+ }
+ static VariantRef fromJson(VariantRef src) {
+ return src;
+ }
+ static bool checkJson(VariantRef src) {
+ VariantData *data = getData(src);
+ return !!data;
+ }
+ static bool checkJson(VariantConstRef) {
+ return false;
+ }
+};
+
+template <>
+struct Converter<VariantConstRef> {
+ static bool toJson(VariantConstRef src, VariantRef dst) {
+ return variantCopyFrom(getData(dst), getData(src), getPool(dst));
+ }
+
+ static VariantConstRef fromJson(VariantConstRef src) {
+ return VariantConstRef(getData(src));
+ }
+
+ static bool checkJson(VariantConstRef src) {
+ const VariantData *data = getData(src);
+ return !!data;
+ }
+};
+
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Variant/VariantShortcuts.hpp b/include/lib/ArduinoJson/Variant/VariantShortcuts.hpp
new file mode 100644
index 0000000..e62847f
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/VariantShortcuts.hpp
@@ -0,0 +1,23 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Array/ArrayShortcuts.hpp>
+#include <ArduinoJson/Object/ObjectShortcuts.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename TVariant>
+class VariantShortcuts : public ObjectShortcuts<TVariant>,
+ public ArrayShortcuts<TVariant> {
+ public:
+ using ArrayShortcuts<TVariant>::createNestedArray;
+ using ArrayShortcuts<TVariant>::createNestedObject;
+ using ArrayShortcuts<TVariant>::operator[];
+ using ObjectShortcuts<TVariant>::createNestedArray;
+ using ObjectShortcuts<TVariant>::createNestedObject;
+ using ObjectShortcuts<TVariant>::operator[];
+};
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Variant/VariantSlot.hpp b/include/lib/ArduinoJson/Variant/VariantSlot.hpp
new file mode 100644
index 0000000..a271c1e
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/VariantSlot.hpp
@@ -0,0 +1,116 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Polyfills/integer.hpp>
+#include <ArduinoJson/Polyfills/limits.hpp>
+#include <ArduinoJson/Polyfills/type_traits.hpp>
+#include <ArduinoJson/Strings/StoragePolicy.hpp>
+#include <ArduinoJson/Variant/VariantContent.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+typedef int_t<ARDUINOJSON_SLOT_OFFSET_SIZE * 8>::type VariantSlotDiff;
+
+class VariantSlot {
+ // CAUTION: same layout as VariantData
+ // we cannot use composition because it adds padding
+ // (+20% on ESP8266 for example)
+ VariantContent _content;
+ uint8_t _flags;
+ VariantSlotDiff _next;
+ const char* _key;
+
+ public:
+ // Must be a POD!
+ // - no constructor
+ // - no destructor
+ // - no virtual
+ // - no inheritance
+
+ VariantData* data() {
+ return reinterpret_cast<VariantData*>(&_content);
+ }
+
+ const VariantData* data() const {
+ return reinterpret_cast<const VariantData*>(&_content);
+ }
+
+ VariantSlot* next() {
+ return _next ? this + _next : 0;
+ }
+
+ const VariantSlot* next() const {
+ return const_cast<VariantSlot*>(this)->next();
+ }
+
+ VariantSlot* next(size_t distance) {
+ VariantSlot* slot = this;
+ while (distance--) {
+ if (!slot->_next)
+ return 0;
+ slot += slot->_next;
+ }
+ return slot;
+ }
+
+ const VariantSlot* next(size_t distance) const {
+ return const_cast<VariantSlot*>(this)->next(distance);
+ }
+
+ void setNext(VariantSlot* slot) {
+ ARDUINOJSON_ASSERT(!slot || slot - this >=
+ numeric_limits<VariantSlotDiff>::lowest());
+ ARDUINOJSON_ASSERT(!slot || slot - this <=
+ numeric_limits<VariantSlotDiff>::highest());
+ _next = VariantSlotDiff(slot ? slot - this : 0);
+ }
+
+ void setNextNotNull(VariantSlot* slot) {
+ ARDUINOJSON_ASSERT(slot != 0);
+ ARDUINOJSON_ASSERT(slot - this >=
+ numeric_limits<VariantSlotDiff>::lowest());
+ ARDUINOJSON_ASSERT(slot - this <=
+ numeric_limits<VariantSlotDiff>::highest());
+ _next = VariantSlotDiff(slot - this);
+ }
+
+ void setKey(const char* k, storage_policies::store_by_copy) {
+ ARDUINOJSON_ASSERT(k != NULL);
+ _flags |= OWNED_KEY_BIT;
+ _key = k;
+ }
+
+ void setKey(const char* k, storage_policies::store_by_address) {
+ ARDUINOJSON_ASSERT(k != NULL);
+ _flags &= VALUE_MASK;
+ _key = k;
+ }
+
+ const char* key() const {
+ return _key;
+ }
+
+ bool ownsKey() const {
+ return (_flags & OWNED_KEY_BIT) != 0;
+ }
+
+ void clear() {
+ _next = 0;
+ _flags = 0;
+ _key = 0;
+ }
+
+ void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) {
+ if (_flags & OWNED_KEY_BIT)
+ _key += stringDistance;
+ if (_flags & OWNED_VALUE_BIT)
+ _content.asString += stringDistance;
+ if (_flags & COLLECTION_MASK)
+ _content.asCollection.movePointers(stringDistance, variantDistance);
+ }
+};
+
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Variant/VariantTag.hpp b/include/lib/ArduinoJson/Variant/VariantTag.hpp
new file mode 100644
index 0000000..7164164
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/VariantTag.hpp
@@ -0,0 +1,16 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Namespace.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+struct VariantTag {};
+
+template <typename T>
+struct IsVariant : is_base_of<VariantTag, T> {};
+
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Variant/VariantTo.hpp b/include/lib/ArduinoJson/Variant/VariantTo.hpp
new file mode 100644
index 0000000..352ecba
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/VariantTo.hpp
@@ -0,0 +1,32 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Namespace.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+class ArrayRef;
+class ObjectRef;
+class VariantRef;
+
+// A metafunction that returns the type of the value returned by
+// VariantRef::to<T>()
+template <typename T>
+struct VariantTo {};
+
+template <>
+struct VariantTo<ArrayRef> {
+ typedef ArrayRef type;
+};
+template <>
+struct VariantTo<ObjectRef> {
+ typedef ObjectRef type;
+};
+template <>
+struct VariantTo<VariantRef> {
+ typedef VariantRef type;
+};
+
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Variant/Visitor.hpp b/include/lib/ArduinoJson/Variant/Visitor.hpp
new file mode 100644
index 0000000..33237dd
--- /dev/null
+++ b/include/lib/ArduinoJson/Variant/Visitor.hpp
@@ -0,0 +1,54 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Collection/CollectionData.hpp>
+#include <ArduinoJson/Numbers/Float.hpp>
+#include <ArduinoJson/Numbers/Integer.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename TResult>
+struct Visitor {
+ typedef TResult result_type;
+
+ TResult visitArray(const CollectionData &) {
+ return TResult();
+ }
+
+ TResult visitBoolean(bool) {
+ return TResult();
+ }
+
+ TResult visitFloat(Float) {
+ return TResult();
+ }
+
+ TResult visitSignedInteger(Integer) {
+ return TResult();
+ }
+
+ TResult visitNull() {
+ return TResult();
+ }
+
+ TResult visitObject(const CollectionData &) {
+ return TResult();
+ }
+
+ TResult visitUnsignedInteger(UInt) {
+ return TResult();
+ }
+
+ TResult visitRawJson(const char *, size_t) {
+ return TResult();
+ }
+
+ TResult visitString(const char *) {
+ return TResult();
+ }
+};
+
+} // namespace ARDUINOJSON_NAMESPACE