From 6f843fcb27119fe74e95b2fcf12f24302913f4e3 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Mon, 17 May 2021 12:29:30 +0200 Subject: [PATCH] Added experimental `{"on":"t"}` (resolves #1952 ) --- CHANGELOG.md | 6 + wled00/json.cpp | 2 + wled00/src/dependencies/json/ArduinoJson-v6.h | 2002 +++++++++-------- wled00/wled.h | 2 +- 4 files changed, 1076 insertions(+), 936 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bed0bd414..5c04cdae8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ### Builds after release 0.12.0 +#### Build 2105171 + +- Always copy MQTT payloads to prevent non-0-terminated strings +- Updated ArduinoJson to 6.18.0 +- Added experimental support for `{"on":"t"}` to toggle on/off state via JSON + #### Build 2105120 - Fixed possibility of non-0-terminated MQTT payloads diff --git a/wled00/json.cpp b/wled00/json.cpp index 358253aa6..5bd76ec2e 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -166,6 +166,8 @@ bool deserializeState(JsonObject root) bool on = root["on"] | (bri > 0); if (!on != !bri) toggleOnOff(); + if (root["on"].is() && root["on"].as()[0] == 't') toggleOnOff(); + int tr = root[F("transition")] | -1; if (tr >= 0) { diff --git a/wled00/src/dependencies/json/ArduinoJson-v6.h b/wled00/src/dependencies/json/ArduinoJson-v6.h index 3913d7110..0dd590af4 100644 --- a/wled00/src/dependencies/json/ArduinoJson-v6.h +++ b/wled00/src/dependencies/json/ArduinoJson-v6.h @@ -1,5 +1,5 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2020 +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 // MIT License #pragma once @@ -64,6 +64,13 @@ #ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT #define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10 #endif +#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE +#if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 2 +#define ARDUINOJSON_SLOT_OFFSET_SIZE 1 +#else +#define ARDUINOJSON_SLOT_OFFSET_SIZE 2 +#endif +#endif #else // ARDUINOJSON_EMBEDDED_MODE #ifndef ARDUINOJSON_USE_DOUBLE #define ARDUINOJSON_USE_DOUBLE 1 @@ -84,6 +91,9 @@ #ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT #define ARDUINOJSON_DEFAULT_NESTING_LIMIT 50 #endif +#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE +#define ARDUINOJSON_SLOT_OFFSET_SIZE 4 +#endif #endif // ARDUINOJSON_EMBEDDED_MODE #ifdef ARDUINO #include @@ -108,7 +118,8 @@ #endif #endif // ARDUINO #ifndef ARDUINOJSON_ENABLE_PROGMEM -#ifdef PROGMEM +#if defined(PROGMEM) && defined(pgm_read_byte) && defined(pgm_read_dword) && \ + defined(pgm_read_ptr) && defined(pgm_read_float) #define ARDUINOJSON_ENABLE_PROGMEM 1 #else #define ARDUINOJSON_ENABLE_PROGMEM 0 @@ -175,7 +186,6 @@ #endif #endif #define ARDUINOJSON_EXPAND6(a, b, c, d, e, f) a, b, c, d, e, f -#define ARDUINOJSON_EXPAND7(a, b, c, d, e, f, g) a, b, c, d, e, f, g #define ARDUINOJSON_EXPAND9(a, b, c, d, e, f, g, h, i) a, b, c, d, e, f, g, h, i #define ARDUINOJSON_EXPAND18(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, \ q, r) \ @@ -202,9 +212,9 @@ #define ARDUINOJSON_HEX_DIGIT_1111() F #define ARDUINOJSON_HEX_DIGIT_(A, B, C, D) ARDUINOJSON_HEX_DIGIT_##A##B##C##D() #define ARDUINOJSON_HEX_DIGIT(A, B, C, D) ARDUINOJSON_HEX_DIGIT_(A, B, C, D) -#define ARDUINOJSON_VERSION "6.17.0" +#define ARDUINOJSON_VERSION "6.18.0" #define ARDUINOJSON_VERSION_MAJOR 6 -#define ARDUINOJSON_VERSION_MINOR 17 +#define ARDUINOJSON_VERSION_MINOR 18 #define ARDUINOJSON_VERSION_REVISION 0 #ifndef ARDUINOJSON_NAMESPACE #define ARDUINOJSON_NAMESPACE \ @@ -337,6 +347,20 @@ struct Max { } // namespace ARDUINOJSON_NAMESPACE #include namespace ARDUINOJSON_NAMESPACE { +template +struct int_t; +template <> +struct int_t<8> { + typedef int8_t type; +}; +template <> +struct int_t<16> { + typedef int16_t type; +}; +template <> +struct int_t<32> { + typedef int32_t type; +}; template struct conditional { typedef TrueType type; @@ -554,6 +578,38 @@ template struct remove_reference { typedef T type; }; +} // namespace ARDUINOJSON_NAMESPACE +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4310) +#endif +namespace ARDUINOJSON_NAMESPACE { +template +struct numeric_limits; +template +struct numeric_limits::value>::type> { + static T lowest() { + return 0; + } + static T highest() { + return T(-1); + } +}; +template +struct numeric_limits< + T, typename enable_if::value && is_signed::value>::type> { + static T lowest() { + return T(T(1) << (sizeof(T) * 8 - 1)); + } + static T highest() { + return T(~lowest()); + } +}; +} // namespace ARDUINOJSON_NAMESPACE +#ifdef _MSC_VER +#pragma warning(pop) +#endif +namespace ARDUINOJSON_NAMESPACE { namespace storage_policies { struct store_by_address {}; struct store_by_copy {}; @@ -584,20 +640,21 @@ typedef unsigned long UInt; namespace ARDUINOJSON_NAMESPACE { enum { VALUE_MASK = 0x7F, - VALUE_IS_OWNED = 0x01, + 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, VALUE_IS_BOOLEAN = 0x06, - VALUE_IS_POSITIVE_INTEGER = 0x08, - VALUE_IS_NEGATIVE_INTEGER = 0x0A, + 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, - KEY_IS_OWNED = 0x80 + OWNED_KEY_BIT = 0x80 }; struct RawData { const char *data; @@ -605,7 +662,9 @@ struct RawData { }; union VariantContent { Float asFloat; - UInt asInteger; + bool asBoolean; + UInt asUnsignedInteger; + Integer asSignedInteger; CollectionData asCollection; const char *asString; struct { @@ -613,7 +672,7 @@ union VariantContent { size_t size; } asRaw; }; -typedef conditional::type VariantSlotDiff; +typedef int_t::type VariantSlotDiff; class VariantSlot { VariantContent _content; uint8_t _flags; @@ -645,15 +704,23 @@ class VariantSlot { return const_cast(this)->next(distance); } void setNext(VariantSlot* slot) { + ARDUINOJSON_ASSERT(!slot || slot - this >= + numeric_limits::lowest()); + ARDUINOJSON_ASSERT(!slot || slot - this <= + numeric_limits::highest()); _next = VariantSlotDiff(slot ? slot - this : 0); } void setNextNotNull(VariantSlot* slot) { ARDUINOJSON_ASSERT(slot != 0); + ARDUINOJSON_ASSERT(slot - this >= + numeric_limits::lowest()); + ARDUINOJSON_ASSERT(slot - this <= + numeric_limits::highest()); _next = VariantSlotDiff(slot - this); } void setKey(const char* k, storage_policies::store_by_copy) { ARDUINOJSON_ASSERT(k != NULL); - _flags |= KEY_IS_OWNED; + _flags |= OWNED_KEY_BIT; _key = k; } void setKey(const char* k, storage_policies::store_by_address) { @@ -665,7 +732,7 @@ class VariantSlot { return _key; } bool ownsKey() const { - return (_flags & KEY_IS_OWNED) != 0; + return (_flags & OWNED_KEY_BIT) != 0; } void clear() { _next = 0; @@ -673,9 +740,9 @@ class VariantSlot { _key = 0; } void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { - if (_flags & KEY_IS_OWNED) + if (_flags & OWNED_KEY_BIT) _key += stringDistance; - if (_flags & VALUE_IS_OWNED) + if (_flags & OWNED_VALUE_BIT) _content.asString += stringDistance; if (_flags & COLLECTION_MASK) _content.asCollection.movePointers(stringDistance, variantDistance); @@ -1241,323 +1308,64 @@ inline SerializedValue serialized(TChar* p, size_t n) { #endif #pragma GCC diagnostic ignored "-Wconversion" #endif -#include -namespace ARDUINOJSON_NAMESPACE { -#ifndef isnan -template -bool isnan(T x) { - return x != x; -} -#endif -#ifndef isinf -template -bool isinf(T x) { - return x != 0.0 && x * 2 == x; -} -#endif -template -struct alias_cast_t { - union { - F raw; - T data; - }; -}; -template -T alias_cast(F raw_data) { - alias_cast_t ac; - ac.raw = raw_data; - return ac.data; -} -} // namespace ARDUINOJSON_NAMESPACE -#if ARDUINOJSON_ENABLE_PROGMEM -namespace ARDUINOJSON_NAMESPACE { -template -typename enable_if::value, T>::type pgm_read(const void* p) { - return reinterpret_cast(pgm_read_ptr(p)); -} -template -typename enable_if::value && - sizeof(T) == sizeof(float), // on AVR sizeof(double) == - T>::type -pgm_read(const void* p) { - return pgm_read_float(p); -} -template -typename enable_if::value, T>::type pgm_read( - const void* p) { - return pgm_read_dword(p); -} -} // namespace ARDUINOJSON_NAMESPACE -#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY -#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ - static type const name[] PROGMEM = value; -#endif -#ifndef ARDUINOJSON_READ_STATIC_ARRAY -#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) \ - pgm_read(name + index) -#endif -#else // i.e. ARDUINOJSON_ENABLE_PROGMEM == 0 -#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY -#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ - static type const name[] = value; -#endif -#ifndef ARDUINOJSON_READ_STATIC_ARRAY -#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) name[index] -#endif -#endif -namespace ARDUINOJSON_NAMESPACE { -template -struct FloatTraits {}; -template -struct FloatTraits { - typedef uint64_t mantissa_type; - static const short mantissa_bits = 52; - static const mantissa_type mantissa_max = - (mantissa_type(1) << mantissa_bits) - 1; - typedef int16_t exponent_type; - static const exponent_type exponent_max = 308; - template - static T make_float(T m, TExponent e) { - if (e > 0) { - for (uint8_t index = 0; e != 0; index++) { - if (e & 1) - m *= positiveBinaryPowerOfTen(index); - e >>= 1; - } - } else { - e = TExponent(-e); - for (uint8_t index = 0; e != 0; index++) { - if (e & 1) - m *= negativeBinaryPowerOfTen(index); - e >>= 1; - } - } - return m; - } - static T positiveBinaryPowerOfTen(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( // - uint32_t, factors, - ARDUINOJSON_EXPAND18({ - 0x40240000, 0x00000000, // 1e1 - 0x40590000, 0x00000000, // 1e2 - 0x40C38800, 0x00000000, // 1e4 - 0x4197D784, 0x00000000, // 1e8 - 0x4341C379, 0x37E08000, // 1e16 - 0x4693B8B5, 0xB5056E17, // 1e32 - 0x4D384F03, 0xE93FF9F5, // 1e64 - 0x5A827748, 0xF9301D32, // 1e128 - 0x75154FDD, 0x7F73BF3C // 1e256 - })); - return forge( - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); - } - static T negativeBinaryPowerOfTen(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( // - uint32_t, factors, - ARDUINOJSON_EXPAND18({ - 0x3FB99999, 0x9999999A, // 1e-1 - 0x3F847AE1, 0x47AE147B, // 1e-2 - 0x3F1A36E2, 0xEB1C432D, // 1e-4 - 0x3E45798E, 0xE2308C3A, // 1e-8 - 0x3C9CD2B2, 0x97D889BC, // 1e-16 - 0x3949F623, 0xD5A8A733, // 1e-32 - 0x32A50FFD, 0x44F4A73D, // 1e-64 - 0x255BBA08, 0xCF8C979D, // 1e-128 - 0x0AC80628, 0x64AC6F43 // 1e-256 - })); - return forge( - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); - } - static T negativeBinaryPowerOfTenPlusOne(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( // - uint32_t, factors, - ARDUINOJSON_EXPAND18({ - 0x3FF00000, 0x00000000, // 1e0 - 0x3FB99999, 0x9999999A, // 1e-1 - 0x3F50624D, 0xD2F1A9FC, // 1e-3 - 0x3E7AD7F2, 0x9ABCAF48, // 1e-7 - 0x3CD203AF, 0x9EE75616, // 1e-15 - 0x398039D6, 0x65896880, // 1e-31 - 0x32DA53FC, 0x9631D10D, // 1e-63 - 0x25915445, 0x81B7DEC2, // 1e-127 - 0x0AFE07B2, 0x7DD78B14 // 1e-255 - })); - return forge( - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); - } - static T nan() { - return forge(0x7ff80000, 0x00000000); - } - static T inf() { - return forge(0x7ff00000, 0x00000000); - } - static T highest() { - return forge(0x7FEFFFFF, 0xFFFFFFFF); - } - static T lowest() { - return forge(0xFFEFFFFF, 0xFFFFFFFF); - } - static T forge(uint32_t msb, uint32_t lsb) { - return alias_cast((uint64_t(msb) << 32) | lsb); - } -}; -template -struct FloatTraits { - typedef uint32_t mantissa_type; - static const short mantissa_bits = 23; - static const mantissa_type mantissa_max = - (mantissa_type(1) << mantissa_bits) - 1; - typedef int8_t exponent_type; - static const exponent_type exponent_max = 38; - template - static T make_float(T m, TExponent e) { - if (e > 0) { - for (uint8_t index = 0; e != 0; index++) { - if (e & 1) - m *= positiveBinaryPowerOfTen(index); - e >>= 1; - } - } else { - e = -e; - for (uint8_t index = 0; e != 0; index++) { - if (e & 1) - m *= negativeBinaryPowerOfTen(index); - e >>= 1; - } - } - return m; - } - static T positiveBinaryPowerOfTen(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( - T, factors, - ARDUINOJSON_EXPAND6({1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f})); - return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); - } - static T negativeBinaryPowerOfTen(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( - T, factors, - ARDUINOJSON_EXPAND6({1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f})); - return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); - } - static T negativeBinaryPowerOfTenPlusOne(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( - T, factors, - ARDUINOJSON_EXPAND6({1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f})); - return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); - } - static T forge(uint32_t bits) { - return alias_cast(bits); - } - static T nan() { - return forge(0x7fc00000); - } - static T inf() { - return forge(0x7f800000); - } - static T highest() { - return forge(0x7f7fffff); - } - static T lowest() { - return forge(0xFf7fffff); - } -}; -} // namespace ARDUINOJSON_NAMESPACE -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4310) -#endif -namespace ARDUINOJSON_NAMESPACE { -template -struct numeric_limits; -template -struct numeric_limits::value>::type> { - static T lowest() { - return 0; - } - static T highest() { - return T(-1); - } -}; -template -struct numeric_limits< - T, typename enable_if::value && is_signed::value>::type> { - static T lowest() { - return T(T(1) << (sizeof(T) * 8 - 1)); - } - static T highest() { - return T(~lowest()); - } -}; -} // namespace ARDUINOJSON_NAMESPACE -#ifdef _MSC_VER -#pragma warning(pop) -#endif namespace ARDUINOJSON_NAMESPACE { template -typename enable_if::value && sizeof(TOut) <= sizeof(TIn), +typename enable_if::value && is_unsigned::value && + is_integral::value && sizeof(TOut) <= sizeof(TIn), bool>::type -canStorePositiveInteger(TIn value) { +canConvertNumber(TIn value) { return value <= TIn(numeric_limits::highest()); } template -typename enable_if::value && sizeof(TIn) < sizeof(TOut), +typename enable_if::value && is_unsigned::value && + is_integral::value && sizeof(TIn) < sizeof(TOut), bool>::type -canStorePositiveInteger(TIn) { +canConvertNumber(TIn) { return true; } template -typename enable_if::value, bool>::type -canStorePositiveInteger(TIn) { +typename enable_if::value && is_floating_point::value, + bool>::type +canConvertNumber(TIn) { return true; } template -typename enable_if::value, bool>::type -canStoreNegativeInteger(TIn) { +typename enable_if::value && is_signed::value && + is_integral::value && is_signed::value && + sizeof(TOut) < sizeof(TIn), + bool>::type +canConvertNumber(TIn value) { + return value >= TIn(numeric_limits::lowest()) && + value <= TIn(numeric_limits::highest()); +} +template +typename enable_if::value && is_signed::value && + is_integral::value && is_signed::value && + sizeof(TIn) <= sizeof(TOut), + bool>::type +canConvertNumber(TIn) { return true; } template -typename enable_if::value && is_signed::value && - sizeof(TOut) <= sizeof(TIn), +typename enable_if::value && is_signed::value && + is_integral::value && is_unsigned::value, bool>::type -canStoreNegativeInteger(TIn value) { - return value <= TIn(numeric_limits::highest()) + 1; +canConvertNumber(TIn value) { + if (value < 0) + return false; + return value <= TIn(numeric_limits::highest()); } template -typename enable_if::value && is_signed::value && - sizeof(TIn) < sizeof(TOut), +typename enable_if::value && + !is_floating_point::value, bool>::type -canStoreNegativeInteger(TIn) { - return true; -} -template -typename enable_if::value && is_unsigned::value, - bool>::type -canStoreNegativeInteger(TIn) { - return false; -} -template -TOut convertPositiveInteger(TIn value) { - return canStorePositiveInteger(value) ? TOut(value) : 0; -} -template -TOut convertNegativeInteger(TIn value) { - return canStoreNegativeInteger(value) ? TOut(~value + 1) : 0; -} -template -typename enable_if::value, TOut>::type convertFloat( - TIn value) { - return TOut(value); -} -template -typename enable_if::value, TOut>::type convertFloat( - TIn value) { +canConvertNumber(TIn value) { return value >= numeric_limits::lowest() && - value <= numeric_limits::highest() - ? TOut(value) - : 0; + value <= numeric_limits::highest(); +} +template +TOut convertNumber(TIn value) { + return canConvertNumber(value) ? TOut(value) : 0; } } // namespace ARDUINOJSON_NAMESPACE #if defined(__clang__) @@ -1597,12 +1405,12 @@ class VariantData { case VALUE_IS_OWNED_RAW: case VALUE_IS_LINKED_RAW: return visitor.visitRawJson(_content.asRaw.data, _content.asRaw.size); - case VALUE_IS_NEGATIVE_INTEGER: - return visitor.visitNegativeInteger(_content.asInteger); - case VALUE_IS_POSITIVE_INTEGER: - return visitor.visitPositiveInteger(_content.asInteger); + 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.asInteger != 0); + return visitor.visitBoolean(_content.asBoolean != 0); default: return visitor.visitNull(); } @@ -1654,17 +1462,16 @@ class VariantData { template bool isInteger() const { switch (type()) { - case VALUE_IS_POSITIVE_INTEGER: - return canStorePositiveInteger(_content.asInteger); - case VALUE_IS_NEGATIVE_INTEGER: - return canStoreNegativeInteger(_content.asInteger); + case VALUE_IS_UNSIGNED_INTEGER: + return canConvertNumber(_content.asUnsignedInteger); + case VALUE_IS_SIGNED_INTEGER: + return canConvertNumber(_content.asSignedInteger); default: return false; } } bool isFloat() const { - return type() == VALUE_IS_FLOAT || type() == VALUE_IS_POSITIVE_INTEGER || - type() == VALUE_IS_NEGATIVE_INTEGER; + return (_flags & NUMBER_BIT) != 0; } bool isString() const { return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING; @@ -1689,7 +1496,7 @@ class VariantData { } void setBoolean(bool value) { setType(VALUE_IS_BOOLEAN); - _content.asInteger = static_cast(value); + _content.asBoolean = value; } void setFloat(Float value) { setType(VALUE_IS_FLOAT); @@ -1719,78 +1526,30 @@ class VariantData { } template typename enable_if::value>::type setInteger(T value) { - setUnsignedInteger(value); + setType(VALUE_IS_UNSIGNED_INTEGER); + _content.asUnsignedInteger = static_cast(value); } template typename enable_if::value>::type setInteger(T value) { - setSignedInteger(value); - } - template - void setSignedInteger(T value) { - if (value >= 0) { - setPositiveInteger(static_cast(value)); - } else { - setNegativeInteger(~static_cast(value) + 1); - } - } - void setUnsignedInteger(UInt value) { - setType(VALUE_IS_POSITIVE_INTEGER); - _content.asInteger = static_cast(value); - } - void setPositiveInteger(UInt value) { - setType(VALUE_IS_POSITIVE_INTEGER); - _content.asInteger = value; - } - void setNegativeInteger(UInt value) { - setType(VALUE_IS_NEGATIVE_INTEGER); - _content.asInteger = 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 bool setString(TAdaptedString value, MemoryPool *pool) { - return setString(value, pool, typename TAdaptedString::storage_policy()); - } - template - inline bool setString(TAdaptedString value, MemoryPool *pool, - storage_policies::decide_at_runtime) { - if (value.isStatic()) - return setString(value, pool, storage_policies::store_by_address()); - else - return setString(value, pool, storage_policies::store_by_copy()); - } - template - inline bool setString(TAdaptedString value, MemoryPool *, - storage_policies::store_by_address) { - if (value.isNull()) - setNull(); - else - setStringPointer(value.data(), storage_policies::store_by_address()); - return true; - } - template - inline bool setString(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; + return storeString(value, pool, typename TAdaptedString::storage_policy()); } CollectionData &toArray() { setType(VALUE_IS_ARRAY); @@ -1851,7 +1610,7 @@ class VariantData { return _content.asCollection.getOrAddMember(key, pool); } void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { - if (_flags & VALUE_IS_OWNED) + if (_flags & OWNED_VALUE_BIT) _content.asString += stringDistance; if (_flags & COLLECTION_MASK) _content.asCollection.movePointers(stringDistance, variantDistance); @@ -1861,9 +1620,41 @@ class VariantData { } private: void setType(uint8_t t) { - _flags &= KEY_IS_OWNED; + _flags &= OWNED_KEY_BIT; _flags |= t; } + template + 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 + 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 + 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__) @@ -1915,125 +1706,37 @@ inline size_t slotSize(const VariantSlot* var) { inline VariantData* slotData(VariantSlot* slot) { return reinterpret_cast(slot); } -template -struct Visitor { - typedef TResult result_type; -}; struct Visitable { }; template struct IsVisitable : is_base_of {}; template -struct IsVisitable : IsVisitable {}; -} // namespace ARDUINOJSON_NAMESPACE -#if ARDUINOJSON_ENABLE_ARDUINO_STRING -#endif -#if ARDUINOJSON_ENABLE_STD_STRING -#endif -namespace ARDUINOJSON_NAMESPACE { -template -struct IsWriteableString : false_type {}; -#if ARDUINOJSON_ENABLE_ARDUINO_STRING -template <> -struct IsWriteableString< ::String> : true_type {}; -#endif -#if ARDUINOJSON_ENABLE_STD_STRING -template -struct IsWriteableString > - : true_type {}; -#endif -class ArrayRef; -class ArrayConstRef; -class ObjectRef; -class ObjectConstRef; -class VariantRef; -class VariantConstRef; -template -struct VariantAs { - typedef T type; -}; -template <> -struct VariantAs { - typedef const char* type; -}; -template -struct VariantConstAs { - typedef typename VariantAs::type type; -}; -template <> -struct VariantConstAs { - typedef VariantConstRef type; -}; -template <> -struct VariantConstAs { - typedef ObjectConstRef type; -}; -template <> -struct VariantConstAs { - typedef ArrayConstRef type; -}; -template -inline typename enable_if::value && !is_same::value, - T>::type -variantAs(const VariantData* data) { - ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); - return data != 0 ? data->asIntegral() : T(0); -} -template -inline typename enable_if::value, T>::type variantAs( - const VariantData* data) { - return data != 0 ? static_cast(data->asIntegral()) : T(); -} -template -inline typename enable_if::value, T>::type variantAs( - const VariantData* data) { - return data != 0 ? data->asBoolean() : false; -} -template -inline typename enable_if::value, T>::type variantAs( - const VariantData* data) { - return data != 0 ? data->asFloat() : T(0); -} -template -inline typename enable_if::value || - is_same::value, - const char*>::type -variantAs(const VariantData* data) { - return data != 0 ? data->asString() : 0; -} -template -T variantAs(VariantData* data, MemoryPool*) { - return variantAs(data); -} -template -inline typename enable_if::value, T>::type variantAs( - const VariantData* data); -template -inline typename enable_if::value, T>::type variantAs( - const VariantData* data); -template -inline typename enable_if::value, T>::type -variantAs(const VariantData* data); -template -inline typename enable_if::value, T>::type variantAs( - const VariantData* data); +struct IsVisitable : IsVisitable {}; +template +struct Converter; } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER // Visual Studio #define FORCE_INLINE // __forceinline causes C4714 when returning std::string #define NO_INLINE __declspec(noinline) -#define DEPRECATED(msg) __declspec(deprecated(msg)) +#ifndef ARDUINOJSON_DEPRECATED +#define ARDUINOJSON_DEPRECATED(msg) __declspec(deprecated(msg)) +#endif #elif defined(__GNUC__) // GCC or Clang #define FORCE_INLINE __attribute__((always_inline)) #define NO_INLINE __attribute__((noinline)) +#ifndef ARDUINOJSON_DEPRECATED #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) -#define DEPRECATED(msg) __attribute__((deprecated(msg))) +#define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated(msg))) #else -#define DEPRECATED(msg) __attribute__((deprecated)) +#define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated)) +#endif #endif #else // Other compilers #define FORCE_INLINE #define NO_INLINE -#define DEPRECATED(msg) +#ifndef ARDUINOJSON_DEPRECATED +#define ARDUINOJSON_DEPRECATED(msg) +#endif #endif #if __cplusplus >= 201103L #define NOEXCEPT noexcept @@ -2078,52 +1781,6 @@ inline bool variantCopyFrom(VariantData *dst, const VariantData *src, return dst->copyFrom(*src, pool); } inline int variantCompare(const VariantData *a, const VariantData *b); -inline bool variantIsArray(const VariantData *var) { - return var && var->isArray(); -} -inline bool variantIsBoolean(const VariantData *var) { - return var && var->isBoolean(); -} -template -inline bool variantIsInteger(const VariantData *var) { - return var && var->isInteger(); -} -inline bool variantIsFloat(const VariantData *var) { - return var && var->isFloat(); -} -inline bool variantIsString(const VariantData *var) { - return var && var->isString(); -} -inline bool variantIsObject(const VariantData *var) { - return var && var->isObject(); -} -inline bool variantIsNull(const VariantData *var) { - return var == 0 || var->isNull(); -} -inline bool variantSetBoolean(VariantData *var, bool value) { - if (!var) - return false; - var->setBoolean(value); - return true; -} -inline bool variantSetFloat(VariantData *var, Float value) { - if (!var) - return false; - var->setFloat(value); - return true; -} -inline bool variantSetLinkedRaw(VariantData *var, - SerializedValue value) { - if (!var) - return false; - var->setLinkedRaw(value); - return true; -} -template -inline bool variantSetOwnedRaw(VariantData *var, SerializedValue value, - MemoryPool *pool) { - return var != 0 && var->setOwnedRaw(value, pool); -} inline void variantSetNull(VariantData *var) { if (!var) return; @@ -2136,14 +1793,6 @@ inline bool variantSetString(VariantData *var, TAdaptedString value, return false; return var->setString(value, pool); } -template -inline bool variantSetInteger(VariantData *var, T value) { - ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); - if (!var) - return false; - var->setInteger(value); - return true; -} inline size_t variantSize(const VariantData *var) { return var != 0 ? var->size() : 0; } @@ -2177,6 +1826,9 @@ NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, MemoryPool *pool) { return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; } +inline bool variantIsNull(const VariantData *var) { + return var == 0 || var->isNull(); +} enum CompareResult { COMPARE_RESULT_DIFFER = 0, COMPARE_RESULT_EQUAL = 1, @@ -2272,23 +1924,36 @@ CompareResult arithmeticCompareNegateRight( return COMPARE_RESULT_GREATER; return arithmeticCompare(static_cast(rhs), -lhs); } +struct VariantTag {}; +template +struct IsVariant : is_base_of {}; template CompareResult compare(const T1 &lhs, const T2 &rhs); // VariantCompare.cpp template struct VariantOperators { template - friend typename enable_if::value, T>::type operator|( - const TVariant &variant, const T &defaultValue) { + friend + typename enable_if::value && !is_array::value, T>::type + operator|(const TVariant &variant, const T &defaultValue) { if (variant.template is()) return variant.template as(); else return defaultValue; } + friend const char *operator|(const TVariant &variant, + const char *defaultValue) { + if (variant.template is()) + return variant.template as(); + else + return defaultValue; + } template - friend typename enable_if::value, T>::type operator|( - const TVariant &variant, T defaultValue) { - const char *value = variant.template as(); - return value ? value : defaultValue; + friend typename enable_if::value, typename T::variant_type>::type + operator|(const TVariant &variant, T defaultValue) { + if (variant) + return variant; + else + return defaultValue; } template friend bool operator==(T *lhs, TVariant rhs) { @@ -2393,6 +2058,8 @@ struct VariantOperators { return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; } }; +class ArrayRef; +class ObjectRef; template class ElementProxy; template @@ -2459,60 +2126,9 @@ class VariantShortcuts : public ObjectShortcuts, }; class ArrayRef; class ObjectRef; -template -class MemberProxy; template -class VariantRefBase { +class VariantRefBase : public VariantTag { public: - template - FORCE_INLINE - typename enable_if::value && !is_same::value, - bool>::type - is() const { - return variantIsInteger(_data); - } - template - FORCE_INLINE typename enable_if::value, bool>::type is() - const { - return variantIsFloat(_data); - } - template - FORCE_INLINE typename enable_if::value, bool>::type is() - const { - return variantIsBoolean(_data); - } - template - FORCE_INLINE typename enable_if::value || - is_same::value || - IsWriteableString::value, - bool>::type - is() const { - return variantIsString(_data); - } - template - FORCE_INLINE typename enable_if< - is_same::type, ArrayRef>::value, bool>::type - is() const { - return variantIsArray(_data); - } - template - FORCE_INLINE typename enable_if< - is_same::type, ObjectRef>::value, bool>::type - is() const { - return variantIsObject(_data); - } -#if ARDUINOJSON_HAS_NULLPTR - template - FORCE_INLINE - typename enable_if::value, bool>::type - is() const { - return variantIsNull(_data); - } -#endif - template - FORCE_INLINE typename enable_if::value, bool>::type is() const { - return variantIsInteger(_data); - } FORCE_INLINE bool isNull() const { return variantIsNull(_data); } @@ -2531,6 +2147,9 @@ class VariantRefBase { protected: VariantRefBase(TData *data) : _data(data) {} TData *_data; + friend TData *getData(const VariantRefBase &variant) { + return variant._data; + } }; class VariantRef : public VariantRefBase, public VariantOperators, @@ -2546,63 +2165,61 @@ class VariantRef : public VariantRefBase, return variantSetNull(_data); } template - FORCE_INLINE bool set( - T value, typename enable_if::value>::type * = 0) const { - return variantSetBoolean(_data, value); + FORCE_INLINE bool set(const T &value) const { + return Converter::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(value); } template - FORCE_INLINE bool set( - T value, - typename enable_if::value>::type * = 0) const { - return variantSetFloat(_data, static_cast(value)); + FORCE_INLINE bool set(T *value) const { + return Converter::toJson(value, *this); } template - FORCE_INLINE bool set( - T value, typename enable_if::value && - !is_same::value>::type * = 0) const { - return variantSetInteger(_data, value); - } - FORCE_INLINE bool set(SerializedValue value) const { - return variantSetLinkedRaw(_data, value); + FORCE_INLINE + typename enable_if::value && !is_same::value, + T>::type + as() const { + return Converter::fromJson(*this); } template - FORCE_INLINE bool set( - SerializedValue value, - typename enable_if::value>::type * = 0) const { - return variantSetOwnedRaw(_data, value, _pool); + FORCE_INLINE typename enable_if::value, const char *>::type + ARDUINOJSON_DEPRECATED("Replace as() with as()") + as() const { + return as(); } template - FORCE_INLINE bool set( - const T &value, - typename enable_if::value>::type * = 0) const { - return variantSetString(_data, adaptString(value), _pool); + FORCE_INLINE typename enable_if::value, char>::type + ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + as() const { + return as(); } template - FORCE_INLINE bool set( - T *value, typename enable_if::value>::type * = 0) const { - return variantSetString(_data, adaptString(value), _pool); + FORCE_INLINE + typename enable_if::value && !is_same::value, + bool>::type + is() const { + return Converter::checkJson(*this); } - template - typename enable_if::value, bool>::type set( - const TVariant &value) const; template - FORCE_INLINE bool set( - T value, typename enable_if::value>::type * = 0) const { - return variantSetInteger(_data, static_cast(value)); + FORCE_INLINE typename enable_if::value, bool>::type + ARDUINOJSON_DEPRECATED("Replace is() with is()") + is() const { + return is(); } -#if ARDUINOJSON_HAS_NULLPTR - FORCE_INLINE bool set(decltype(nullptr)) const { - variantSetNull(_data); - return true; - } -#endif template - FORCE_INLINE typename VariantAs::type as() const { - return variantAs::type>(_data, _pool); + FORCE_INLINE typename enable_if::value, bool>::type + ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + is() const { + return is(); } template FORCE_INLINE operator T() const { - return variantAs(_data, _pool); + return as(); } template typename TVisitor::result_type accept(TVisitor &visitor) const { @@ -2645,7 +2262,10 @@ class VariantRef : public VariantRefBase, } private: MemoryPool *_pool; -}; // namespace ARDUINOJSON_NAMESPACE + friend MemoryPool *getPool(const VariantRef &variant) { + return variant._pool; + } +}; class VariantConstRef : public VariantRefBase, public VariantOperators, public VariantShortcuts, @@ -2661,12 +2281,48 @@ class VariantConstRef : public VariantRefBase, return variantAccept(_data, visitor); } template - FORCE_INLINE typename VariantConstAs::type as() const { - return variantAs::type>(_data); + FORCE_INLINE + typename enable_if::value && !is_same::value, + T>::type + as() const { + return Converter::fromJson(*this); + } + template + FORCE_INLINE typename enable_if::value, const char *>::type + ARDUINOJSON_DEPRECATED("Replace as() with as()") + as() const { + return as(); + } + template + FORCE_INLINE typename enable_if::value, char>::type + ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + as() const { + return as(); + } + template + FORCE_INLINE + typename enable_if::value && !is_same::value, + bool>::type + is() const { + return Converter::checkJson(*this); + } + template + FORCE_INLINE typename enable_if::value, bool>::type + ARDUINOJSON_DEPRECATED("Replace is() with is()") + is() const { + return is(); + } + template + FORCE_INLINE typename enable_if::value, bool>::type + ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + is() const { + return is(); } template FORCE_INLINE operator T() const { - return variantAs(_data); + return as(); } FORCE_INLINE VariantConstRef getElement(size_t) const; FORCE_INLINE VariantConstRef operator[](size_t index) const { @@ -2695,6 +2351,35 @@ class VariantConstRef : public VariantRefBase, return getMember(key); } }; +template <> +struct Converter { + 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 { + 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; + } +}; class VariantPtr { public: VariantPtr(MemoryPool *pool, VariantData *data) : _variant(pool, data) {} @@ -2898,6 +2583,37 @@ class ArrayRef : public ArrayRefBase, private: MemoryPool* _pool; }; +template <> +struct Converter { + static bool toJson(VariantConstRef src, VariantRef dst) { + return variantCopyFrom(getData(dst), getData(src), getPool(dst)); + } + static ArrayConstRef fromJson(VariantConstRef src) { + return ArrayConstRef(variantAsArray(getData(src))); + } + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isArray(); + } +}; +template <> +struct Converter { + static bool toJson(VariantConstRef src, VariantRef dst) { + return variantCopyFrom(getData(dst), getData(src), getPool(dst)); + } + static ArrayRef fromJson(VariantRef src) { + VariantData* data = getData(src); + MemoryPool* pool = getPool(src); + return ArrayRef(pool, data != 0 ? data->asArray() : 0); + } + static bool checkJson(VariantConstRef) { + return false; + } + static bool checkJson(VariantRef src) { + VariantData* data = getData(src); + return data && data->isArray(); + } +}; template typename TVisitor::result_type objectAccept(const CollectionData *obj, TVisitor &visitor) { @@ -3265,6 +2981,37 @@ class ObjectRef : public ObjectRefBase, private: MemoryPool* _pool; }; +template <> +struct Converter { + static bool toJson(VariantConstRef src, VariantRef dst) { + return variantCopyFrom(getData(dst), getData(src), getPool(dst)); + } + static ObjectConstRef fromJson(VariantConstRef src) { + return ObjectConstRef(variantAsObject(getData(src))); + } + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isObject(); + } +}; +template <> +struct Converter { + static bool toJson(VariantConstRef src, VariantRef dst) { + return variantCopyFrom(getData(dst), getData(src), getPool(dst)); + } + static ObjectRef fromJson(VariantRef src) { + VariantData* data = getData(src); + MemoryPool* pool = getPool(src); + return ObjectRef(pool, data != 0 ? data->asObject() : 0); + } + static bool checkJson(VariantConstRef) { + return false; + } + static bool checkJson(VariantRef src) { + VariantData* data = getData(src); + return data && data->isObject(); + } +}; class ArrayRef; class ObjectRef; class VariantRef; @@ -3291,9 +3038,11 @@ namespace ARDUINOJSON_NAMESPACE { template class ElementProxy : public VariantOperators >, public VariantShortcuts >, - public Visitable { + public Visitable, + public VariantTag { typedef ElementProxy this_type; public: + typedef VariantRef variant_type; FORCE_INLINE ElementProxy(TArray array, size_t index) : _array(array), _index(index) {} FORCE_INLINE ElementProxy(const ElementProxy& src) @@ -3319,10 +3068,17 @@ class ElementProxy : public VariantOperators >, return getUpstreamElement().isNull(); } template - FORCE_INLINE typename VariantAs::type as() const { + FORCE_INLINE typename enable_if::value, T>::type as() + const { return getUpstreamElement().template as(); } template + FORCE_INLINE typename enable_if::value, const char*>::type + ARDUINOJSON_DEPRECATED("Replace as() with as()") + as() const { + return as(); + } + template FORCE_INLINE operator T() const { return getUpstreamElement(); } @@ -3394,6 +3150,9 @@ class ElementProxy : public VariantOperators >, FORCE_INLINE VariantRef getOrAddUpstreamElement() const { return _array.getOrAddElement(_index); } + friend bool convertToJson(const this_type& src, VariantRef dst) { + return dst.set(src.getUpstreamElement()); + } TArray _array; const size_t _index; }; @@ -3409,9 +3168,11 @@ namespace ARDUINOJSON_NAMESPACE { template class MemberProxy : public VariantOperators >, public VariantShortcuts >, - public Visitable { + public Visitable, + public VariantTag { typedef MemberProxy this_type; public: + typedef VariantRef variant_type; FORCE_INLINE MemberProxy(TObject variant, TStringRef key) : _object(variant), _key(key) {} FORCE_INLINE MemberProxy(const MemberProxy &src) @@ -3440,9 +3201,16 @@ class MemberProxy : public VariantOperators >, FORCE_INLINE bool isNull() const { return getUpstreamMember().isNull(); } - template - FORCE_INLINE typename VariantAs::type as() const { - return getUpstreamMember().template as(); + template + FORCE_INLINE typename enable_if::value, T>::type as() + const { + return getUpstreamMember().template as(); + } + template + FORCE_INLINE typename enable_if::value, const char *>::type + ARDUINOJSON_DEPRECATED("Replace as() with as()") + as() const { + return as(); } template FORCE_INLINE operator T() const { @@ -3516,6 +3284,9 @@ class MemberProxy : public VariantOperators >, FORCE_INLINE VariantRef getOrAddUpstreamMember() const { return _object.getOrAddMember(_key); } + friend bool convertToJson(const this_type &src, VariantRef dst) { + return dst.set(src.getUpstreamMember()); + } TObject _object; TStringRef _key; }; @@ -3531,11 +3302,11 @@ class JsonDocument : public Visitable { return getVariant().accept(visitor); } template - typename VariantAs::type as() { + T as() { return getVariant().template as(); } template - typename VariantConstAs::type as() const { + T as() const { return getVariant().template as(); } void clear() { @@ -3543,6 +3314,10 @@ class JsonDocument : public Visitable { _data.setNull(); } template + bool is() { + return getVariant().template is(); + } + template bool is() const { return getVariant().template is(); } @@ -3565,7 +3340,7 @@ class JsonDocument : public Visitable { return _data.size(); } bool set(const JsonDocument& src) { - return to().set(src.as()); + return to().set(src.as()); } template typename enable_if::value, bool>::type set( @@ -3722,6 +3497,7 @@ class JsonDocument : public Visitable { JsonDocument(char* buf, size_t capa) : _pool(buf, capa) { _data.setNull(); } + ~JsonDocument() {} void replacePool(MemoryPool pool) { _pool = pool; } @@ -3737,6 +3513,9 @@ class JsonDocument : public Visitable { JsonDocument(const JsonDocument&); JsonDocument& operator=(const JsonDocument&); }; +inline bool convertToJson(const JsonDocument& src, VariantRef dst) { + return dst.set(src.as()); +} template class AllocatorOwner { public: @@ -3856,6 +3635,9 @@ class BasicJsonDocument : AllocatorOwner, public JsonDocument { src._pool = MemoryPool(0, 0); } }; +} // namespace ARDUINOJSON_NAMESPACE +#include +namespace ARDUINOJSON_NAMESPACE { struct DefaultAllocator { void* allocate(size_t size) { return malloc(size); @@ -3916,6 +3698,37 @@ inline ElementProxy ArrayShortcuts::operator[]( size_t index) const { return ElementProxy(*impl(), index); } +template +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(); + } +}; template inline typename enable_if::value && !is_base_of::value, @@ -3968,35 +3781,12 @@ class ArrayCopier1D : public Visitor { size_t size = 0; VariantSlot* slot = array.head(); while (slot != 0 && size < _capacity) { - _destination[size++] = variantAs(slot->data()); + _destination[size++] = + Converter::fromJson(VariantConstRef(slot->data())); slot = slot->next(); } return size; } - size_t visitObject(const CollectionData&) { - return 0; - } - size_t visitFloat(Float) { - return 0; - } - size_t visitString(const char*) { - return 0; - } - size_t visitRawJson(const char*, size_t) { - return 0; - } - size_t visitNegativeInteger(UInt) { - return 0; - } - size_t visitPositiveInteger(UInt) { - return 0; - } - size_t visitBoolean(bool) { - return 0; - } - size_t visitNull() { - return 0; - } private: T* _destination; size_t _capacity; @@ -4014,14 +3804,6 @@ class ArrayCopier2D : public Visitor { slot = slot->next(); } } - void visitObject(const CollectionData&) {} - void visitFloat(Float) {} - void visitString(const char*) {} - void visitRawJson(const char*, size_t) {} - void visitNegativeInteger(UInt) {} - void visitPositiveInteger(UInt) {} - void visitBoolean(bool) {} - void visitNull() {} private: T (*_destination)[N1][N2]; size_t _capacity1, _capacity2; @@ -4135,6 +3917,8 @@ inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const { return slot; } inline VariantSlot* CollectionData::getSlot(size_t index) const { + if (!_head) + return 0; return _head->next(index); } inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const { @@ -4271,83 +4055,245 @@ template template inline typename enable_if::value, MemberProxy >::type - ObjectShortcuts::operator[](TString* key) const { +ObjectShortcuts::operator[](TString* key) const { return MemberProxy(*impl(), key); } template template inline typename enable_if::value, MemberProxy >::type - ObjectShortcuts::operator[](const TString& key) const { +ObjectShortcuts::operator[](const TString& key) const { return MemberProxy(*impl(), key); } -template -inline typename enable_if::value, T>::type variantAs( - const VariantData* _data) { - return ArrayConstRef(variantAsArray(_data)); -} -template -inline typename enable_if::value, T>::type variantAs( - const VariantData* _data) { - return ObjectConstRef(variantAsObject(_data)); -} -template -inline typename enable_if::value, T>::type -variantAs(const VariantData* _data) { - return VariantConstRef(_data); -} -template -inline typename enable_if::value, T>::type variantAs( - const VariantData* _data) { - const char* cstr = _data != 0 ? _data->asString() : 0; - if (cstr) - return T(cstr); - T s; - serializeJson(VariantConstRef(_data), s); - return s; -} +} // namespace ARDUINOJSON_NAMESPACE +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +#endif +#if ARDUINOJSON_ENABLE_STD_STRING +#endif +namespace ARDUINOJSON_NAMESPACE { +template +struct IsWriteableString : false_type {}; +#if ARDUINOJSON_ENABLE_ARDUINO_STRING template <> -inline ArrayRef variantAs(VariantData* data, MemoryPool* pool) { - return ArrayRef(pool, data != 0 ? data->asArray() : 0); -} -template <> -inline ObjectRef variantAs(VariantData* data, MemoryPool* pool) { - return ObjectRef(pool, data != 0 ? data->asObject() : 0); -} -template <> -inline VariantRef variantAs(VariantData* data, MemoryPool* pool) { - return VariantRef(pool, data); -} -class CollectionData; -struct ComparerBase : Visitor { - CompareResult visitArray(const CollectionData &) { - return COMPARE_RESULT_DIFFER; +struct IsWriteableString< ::String> : true_type {}; +#endif +#if ARDUINOJSON_ENABLE_STD_STRING +template +struct IsWriteableString > + : true_type {}; +#endif +template +struct Converter { + static bool toJson(const T& src, VariantRef dst) { + return convertToJson(src, dst); // Error here? See https://arduinojson.org/v6/unsupported-set/ } - CompareResult visitBoolean(bool) { - return COMPARE_RESULT_DIFFER; + static T fromJson(VariantConstRef src) { + T result; // Error here? See https://arduinojson.org/v6/non-default-constructible/ + convertFromJson(src, result); // Error here? See https://arduinojson.org/v6/unsupported-as/ + return result; } - CompareResult visitFloat(Float) { - return COMPARE_RESULT_DIFFER; - } - CompareResult visitNegativeInteger(UInt) { - return COMPARE_RESULT_DIFFER; - } - CompareResult visitNull() { - return COMPARE_RESULT_DIFFER; - } - CompareResult visitObject(const CollectionData &) { - return COMPARE_RESULT_DIFFER; - } - CompareResult visitPositiveInteger(UInt) { - return COMPARE_RESULT_DIFFER; - } - CompareResult visitRawJson(const char *, size_t) { - return COMPARE_RESULT_DIFFER; - } - CompareResult visitString(const char *) { - return COMPARE_RESULT_DIFFER; + static bool checkJson(VariantConstRef src) { + T dummy; + return canConvertFromJson(src, dummy); // Error here? See https://arduinojson.org/v6/unsupported-is/ } }; +template +struct Converter< + T, typename enable_if::value && !is_same::value && + !is_same::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(); + } + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isInteger(); + } +}; +template +struct Converter::value>::type> { + static bool toJson(T src, VariantRef dst) { + return dst.set(static_cast(src)); + } + static T fromJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data ? static_cast(data->asIntegral()) : T(); + } + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isInteger(); + } +}; +template <> +struct Converter { + 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 +struct Converter::value>::type> { + static bool toJson(T src, VariantRef dst) { + VariantData* data = getData(dst); + if (!data) + return false; + data->setFloat(static_cast(src)); + return true; + } + static T fromJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data ? data->asFloat() : false; + } + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isFloat(); + } +}; +template <> +struct Converter { + 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 +inline typename enable_if::value, bool>::type convertToJson( + const T& src, VariantRef dst) { + VariantData* data = getData(dst); + MemoryPool* pool = getPool(dst); + return variantSetString(data, adaptString(src), pool); +} +template +inline typename enable_if::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 +inline typename enable_if::value, bool>::type +canConvertFromJson(VariantConstRef src, const T&) { + const VariantData* data = getData(src); + return data && data->isString(); +} +template <> +struct Converter > { + static bool toJson(SerializedValue src, VariantRef dst) { + VariantData* data = getData(dst); + if (!data) + return false; + data->setLinkedRaw(src); + return true; + } +}; +template +struct Converter, + typename enable_if::value>::type> { + static bool toJson(SerializedValue 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 { + 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 +class CollectionData; +struct ComparerBase : Visitor {}; template struct Comparer; template @@ -4380,14 +4326,14 @@ struct Comparer::value || CompareResult visitFloat(Float lhs) { return arithmeticCompare(lhs, rhs); } - CompareResult visitNegativeInteger(UInt lhs) { - return arithmeticCompareNegateLeft(lhs, rhs); + CompareResult visitSignedInteger(Integer lhs) { + return arithmeticCompare(lhs, rhs); } - CompareResult visitPositiveInteger(UInt lhs) { + CompareResult visitUnsignedInteger(UInt lhs) { return arithmeticCompare(lhs, rhs); } CompareResult visitBoolean(bool lhs) { - return visitPositiveInteger(static_cast(lhs)); + return visitUnsignedInteger(static_cast(lhs)); } }; struct NullComparer : ComparerBase { @@ -4411,22 +4357,6 @@ struct ArrayComparer : ComparerBase { return COMPARE_RESULT_DIFFER; } }; -struct NegativeIntegerComparer : ComparerBase { - UInt _rhs; - explicit NegativeIntegerComparer(UInt rhs) : _rhs(rhs) {} - CompareResult visitFloat(Float lhs) { - return arithmeticCompareNegateRight(lhs, _rhs); - } - CompareResult visitNegativeInteger(UInt lhs) { - return arithmeticCompare(_rhs, lhs); - } - CompareResult visitPositiveInteger(UInt) { - return COMPARE_RESULT_GREATER; - } - CompareResult visitBoolean(bool) { - return COMPARE_RESULT_GREATER; - } -}; struct ObjectComparer : ComparerBase { const CollectionData *_rhs; explicit ObjectComparer(const CollectionData &rhs) : _rhs(&rhs) {} @@ -4478,11 +4408,11 @@ struct Comparer::value>::type> RawComparer comparer(lhsData, lhsSize); return accept(comparer); } - CompareResult visitNegativeInteger(UInt lhs) { - NegativeIntegerComparer comparer(lhs); + CompareResult visitSignedInteger(Integer lhs) { + Comparer comparer(lhs); return accept(comparer); } - CompareResult visitPositiveInteger(UInt lhs) { + CompareResult visitUnsignedInteger(UInt lhs) { Comparer comparer(lhs); return accept(comparer); } @@ -4516,9 +4446,232 @@ CompareResult compare(const T1 &lhs, const T2 &rhs) { inline int variantCompare(const VariantData *a, const VariantData *b) { return compare(VariantConstRef(a), VariantConstRef(b)); } +#ifndef isnan +template +bool isnan(T x) { + return x != x; +} +#endif +#ifndef isinf +template +bool isinf(T x) { + return x != 0.0 && x * 2 == x; +} +#endif +template +struct alias_cast_t { + union { + F raw; + T data; + }; +}; +template +T alias_cast(F raw_data) { + alias_cast_t ac; + ac.raw = raw_data; + return ac.data; +} +} // namespace ARDUINOJSON_NAMESPACE +#if ARDUINOJSON_ENABLE_PROGMEM +namespace ARDUINOJSON_NAMESPACE { +template +typename enable_if::value, T>::type pgm_read(const void* p) { + return reinterpret_cast(pgm_read_ptr(p)); +} +template +typename enable_if::value && + sizeof(T) == sizeof(float), // on AVR sizeof(double) == + T>::type +pgm_read(const void* p) { + return pgm_read_float(p); +} +template +typename enable_if::value, T>::type pgm_read( + const void* p) { + return pgm_read_dword(p); +} +} // namespace ARDUINOJSON_NAMESPACE +#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY +#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ + static type const name[] PROGMEM = value; +#endif +#ifndef ARDUINOJSON_READ_STATIC_ARRAY +#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) \ + pgm_read(name + index) +#endif +#else // i.e. ARDUINOJSON_ENABLE_PROGMEM == 0 +#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY +#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ + static type const name[] = value; +#endif +#ifndef ARDUINOJSON_READ_STATIC_ARRAY +#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) name[index] +#endif +#endif +namespace ARDUINOJSON_NAMESPACE { +template +struct FloatTraits {}; +template +struct FloatTraits { + typedef uint64_t mantissa_type; + static const short mantissa_bits = 52; + static const mantissa_type mantissa_max = + (mantissa_type(1) << mantissa_bits) - 1; + typedef int16_t exponent_type; + static const exponent_type exponent_max = 308; + template + static T make_float(T m, TExponent e) { + if (e > 0) { + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) + m *= positiveBinaryPowerOfTen(index); + e >>= 1; + } + } else { + e = TExponent(-e); + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) + m *= negativeBinaryPowerOfTen(index); + e >>= 1; + } + } + return m; + } + static T positiveBinaryPowerOfTen(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, factors, + ARDUINOJSON_EXPAND18({ + 0x40240000, 0x00000000, // 1e1 + 0x40590000, 0x00000000, // 1e2 + 0x40C38800, 0x00000000, // 1e4 + 0x4197D784, 0x00000000, // 1e8 + 0x4341C379, 0x37E08000, // 1e16 + 0x4693B8B5, 0xB5056E17, // 1e32 + 0x4D384F03, 0xE93FF9F5, // 1e64 + 0x5A827748, 0xF9301D32, // 1e128 + 0x75154FDD, 0x7F73BF3C // 1e256 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); + } + static T negativeBinaryPowerOfTen(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, factors, + ARDUINOJSON_EXPAND18({ + 0x3FB99999, 0x9999999A, // 1e-1 + 0x3F847AE1, 0x47AE147B, // 1e-2 + 0x3F1A36E2, 0xEB1C432D, // 1e-4 + 0x3E45798E, 0xE2308C3A, // 1e-8 + 0x3C9CD2B2, 0x97D889BC, // 1e-16 + 0x3949F623, 0xD5A8A733, // 1e-32 + 0x32A50FFD, 0x44F4A73D, // 1e-64 + 0x255BBA08, 0xCF8C979D, // 1e-128 + 0x0AC80628, 0x64AC6F43 // 1e-256 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); + } + static T negativeBinaryPowerOfTenPlusOne(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, factors, + ARDUINOJSON_EXPAND18({ + 0x3FF00000, 0x00000000, // 1e0 + 0x3FB99999, 0x9999999A, // 1e-1 + 0x3F50624D, 0xD2F1A9FC, // 1e-3 + 0x3E7AD7F2, 0x9ABCAF48, // 1e-7 + 0x3CD203AF, 0x9EE75616, // 1e-15 + 0x398039D6, 0x65896880, // 1e-31 + 0x32DA53FC, 0x9631D10D, // 1e-63 + 0x25915445, 0x81B7DEC2, // 1e-127 + 0x0AFE07B2, 0x7DD78B14 // 1e-255 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); + } + static T nan() { + return forge(0x7ff80000, 0x00000000); + } + static T inf() { + return forge(0x7ff00000, 0x00000000); + } + static T highest() { + return forge(0x7FEFFFFF, 0xFFFFFFFF); + } + static T lowest() { + return forge(0xFFEFFFFF, 0xFFFFFFFF); + } + static T forge(uint32_t msb, uint32_t lsb) { + return alias_cast((uint64_t(msb) << 32) | lsb); + } +}; +template +struct FloatTraits { + typedef uint32_t mantissa_type; + static const short mantissa_bits = 23; + static const mantissa_type mantissa_max = + (mantissa_type(1) << mantissa_bits) - 1; + typedef int8_t exponent_type; + static const exponent_type exponent_max = 38; + template + static T make_float(T m, TExponent e) { + if (e > 0) { + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) + m *= positiveBinaryPowerOfTen(index); + e >>= 1; + } + } else { + e = -e; + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) + m *= negativeBinaryPowerOfTen(index); + e >>= 1; + } + } + return m; + } + static T positiveBinaryPowerOfTen(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( + T, factors, + ARDUINOJSON_EXPAND6({1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); + } + static T negativeBinaryPowerOfTen(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( + T, factors, + ARDUINOJSON_EXPAND6({1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); + } + static T negativeBinaryPowerOfTenPlusOne(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( + T, factors, + ARDUINOJSON_EXPAND6({1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); + } + static T forge(uint32_t bits) { + return alias_cast(bits); + } + static T nan() { + return forge(0x7fc00000); + } + static T inf() { + return forge(0x7f800000); + } + static T highest() { + return forge(0x7f7fffff); + } + static T lowest() { + return forge(0xFf7fffff); + } +}; +#ifndef isdigit inline bool isdigit(char c) { return '0' <= c && c <= '9'; } +#endif inline bool issign(char c) { return '-' == c || c == '+'; } @@ -4567,11 +4720,17 @@ inline bool parseNumber(const char* s, VariantData& result) { s++; } if (*s == '\0') { - if (is_negative) - result.setNegativeInteger(UInt(mantissa)); - else - result.setPositiveInteger(UInt(mantissa)); - return true; + if (is_negative) { + const mantissa_t sintMantissaMax = mantissa_t(1) + << (sizeof(Integer) * 8 - 1); + if (mantissa <= sintMantissaMax) { + result.setInteger(Integer(~mantissa + 1)); + return true; + } + } else { + result.setInteger(UInt(mantissa)); + return true; + } } while (mantissa > traits::mantissa_max) { mantissa /= 10; @@ -4628,31 +4787,33 @@ inline T parseNumber(const char* s) { VariantData value; value.init(); // VariantData is a POD, so it has no constructor parseNumber(s, value); - return variantAs(&value); + return Converter::fromJson(VariantConstRef(&value)); } template inline T VariantData::asIntegral() const { switch (type()) { - case VALUE_IS_POSITIVE_INTEGER: case VALUE_IS_BOOLEAN: - return convertPositiveInteger(_content.asInteger); - case VALUE_IS_NEGATIVE_INTEGER: - return convertNegativeInteger(_content.asInteger); + return _content.asBoolean; + case VALUE_IS_UNSIGNED_INTEGER: + return convertNumber(_content.asUnsignedInteger); + case VALUE_IS_SIGNED_INTEGER: + return convertNumber(_content.asSignedInteger); case VALUE_IS_LINKED_STRING: case VALUE_IS_OWNED_STRING: return parseNumber(_content.asString); case VALUE_IS_FLOAT: - return convertFloat(_content.asFloat); + return convertNumber(_content.asFloat); default: return 0; } } inline bool VariantData::asBoolean() const { switch (type()) { - case VALUE_IS_POSITIVE_INTEGER: case VALUE_IS_BOOLEAN: - case VALUE_IS_NEGATIVE_INTEGER: - return _content.asInteger != 0; + 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: @@ -4664,11 +4825,12 @@ inline bool VariantData::asBoolean() const { template inline T VariantData::asFloat() const { switch (type()) { - case VALUE_IS_POSITIVE_INTEGER: case VALUE_IS_BOOLEAN: - return static_cast(_content.asInteger); - case VALUE_IS_NEGATIVE_INTEGER: - return -static_cast(_content.asInteger); + return static_cast(_content.asBoolean); + case VALUE_IS_UNSIGNED_INTEGER: + return static_cast(_content.asUnsignedInteger); + case VALUE_IS_SIGNED_INTEGER: + return static_cast(_content.asSignedInteger); case VALUE_IS_LINKED_STRING: case VALUE_IS_OWNED_STRING: return parseNumber(_content.asString); @@ -4687,12 +4849,6 @@ inline const char *VariantData::asString() const { return 0; } } -template -typename enable_if::value, bool>::type VariantRef::set( - const TVariant &value) const { - VariantConstRef v = value; - return variantCopyFrom(_data, v._data, _pool); -} template inline typename enable_if::value, ArrayRef>::type VariantRef::to() const { @@ -4757,7 +4913,6 @@ class DeserializationError { IncompleteInput, InvalidInput, NoMemory, - NotSupported, TooDeep }; DeserializationError() {} @@ -4802,8 +4957,8 @@ class DeserializationError { } const char* c_str() const { static const char* messages[] = { - "Ok", "EmptyInput", "IncompleteInput", "InvalidInput", - "NoMemory", "NotSupported", "TooDeep"}; + "Ok", "EmptyInput", "IncompleteInput", + "InvalidInput", "NoMemory", "TooDeep"}; ARDUINOJSON_ASSERT(static_cast(_code) < sizeof(messages) / sizeof(messages[0])); return messages[_code]; @@ -4815,11 +4970,9 @@ class DeserializationError { ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s2, "IncompleteInput"); ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s3, "InvalidInput"); ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s4, "NoMemory"); - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s5, "NotSupported"); - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s6, "TooDeep"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s5, "TooDeep"); ARDUINOJSON_DEFINE_STATIC_ARRAY( - const char*, messages, - ARDUINOJSON_EXPAND7({s0, s1, s2, s3, s4, s5, s6})); + const char*, messages, ARDUINOJSON_EXPAND6({s0, s1, s2, s3, s4, s5})); return ARDUINOJSON_READ_STATIC_ARRAY(const __FlashStringHelper*, messages, _code); } @@ -4845,10 +4998,10 @@ class Filter { return _variant; } bool allowArray() const { - return _variant == true || _variant.is(); + return _variant == true || _variant.is(); } bool allowObject() const { - return _variant == true || _variant.is(); + return _variant == true || _variant.is(); } bool allowValue() const { return _variant == true; @@ -5357,7 +5510,6 @@ class JsonDeserializer { return _error; } private: - JsonDeserializer &operator=(const JsonDeserializer &); // non-copiable char current() { return _latch.current(); } @@ -5602,11 +5754,10 @@ class JsonDeserializer { return false; if (codepoint.append(codeunit)) Utf8::encodeCodepoint(codepoint.value(), _stringStorage); - continue; #else - _error = DeserializationError::NotSupported; - return false; + _stringStorage.append('\\'); #endif + continue; } c = EscapeSequence::unescapeChar(c); if (c == '\0') { @@ -6008,24 +6159,28 @@ class TextFormatter { } #endif FloatParts parts(value); - writePositiveInteger(parts.integral); + writeInteger(parts.integral); if (parts.decimalPlaces) writeDecimals(parts.decimal, parts.decimalPlaces); - if (parts.exponent < 0) { - writeRaw("e-"); - writePositiveInteger(-parts.exponent); - } - if (parts.exponent > 0) { + if (parts.exponent) { writeRaw('e'); - writePositiveInteger(parts.exponent); + writeInteger(parts.exponent); } } - void writeNegativeInteger(UInt value) { - writeRaw('-'); - writePositiveInteger(value); - } template - void writePositiveInteger(T value) { + typename enable_if::value>::type writeInteger(T value) { + typedef typename make_unsigned::type unsigned_type; + unsigned_type unsigned_value; + if (value < 0) { + writeRaw('-'); + unsigned_value = unsigned_type(unsigned_type(~value) + 1); + } else { + unsigned_value = unsigned_type(value); + } + writeInteger(unsigned_value); + } + template + typename enable_if::value>::type writeInteger(T value) { char buffer[22]; char *end = buffer + sizeof(buffer); char *begin = end; @@ -6099,14 +6254,11 @@ class Writer { }; class StaticStringWriter { public: - StaticStringWriter(char *buf, size_t size) : end(buf + size - 1), p(buf) { - *p = '\0'; - } + StaticStringWriter(char *buf, size_t size) : end(buf + size), p(buf) {} size_t write(uint8_t c) { if (p >= end) return 0; *p++ = static_cast(c); - *p = '\0'; return 1; } size_t write(const uint8_t *s, size_t n) { @@ -6115,7 +6267,6 @@ class StaticStringWriter { *p++ = static_cast(*s++); n--; } - *p = '\0'; return size_t(p - begin); } private: @@ -6241,10 +6392,20 @@ size_t serialize(const TSource &source, TDestination &destination) { return doSerialize(source, writer); } template