Просмотр исходного кода

Implemented reference semantics for `JsonVariant`

Benoit Blanchon 7 лет назад
Родитель
Сommit
9cbc891816
53 измененных файлов с 1197 добавлено и 840 удалено
  1. 50 0
      CHANGELOG.md
  2. 2 0
      src/ArduinoJson/Data/JsonVariantContent.hpp
  3. 181 0
      src/ArduinoJson/Data/JsonVariantData.hpp
  4. 0 23
      src/ArduinoJson/Data/JsonVariantDefault.hpp
  5. 4 4
      src/ArduinoJson/Data/JsonVariantType.hpp
  6. 3 8
      src/ArduinoJson/Data/List.hpp
  7. 0 53
      src/ArduinoJson/Data/ValueSaver.hpp
  8. 4 4
      src/ArduinoJson/Deserialization/deserialize.hpp
  9. 28 13
      src/ArduinoJson/DynamicJsonDocument.hpp
  10. 30 24
      src/ArduinoJson/Json/JsonDeserializer.hpp
  11. 4 4
      src/ArduinoJson/Json/JsonSerializer.hpp
  12. 22 30
      src/ArduinoJson/JsonArray.hpp
  13. 6 4
      src/ArduinoJson/JsonArrayData.hpp
  14. 2 2
      src/ArduinoJson/JsonArrayImpl.hpp
  15. 72 0
      src/ArduinoJson/JsonArrayIterator.hpp
  16. 1 1
      src/ArduinoJson/JsonArraySubscript.hpp
  17. 49 41
      src/ArduinoJson/JsonObject.hpp
  18. 7 3
      src/ArduinoJson/JsonObjectData.hpp
  19. 2 2
      src/ArduinoJson/JsonObjectImpl.hpp
  20. 72 0
      src/ArduinoJson/JsonObjectIterator.hpp
  21. 24 3
      src/ArduinoJson/JsonPair.hpp
  22. 135 132
      src/ArduinoJson/JsonVariant.hpp
  23. 2 0
      src/ArduinoJson/JsonVariantComparisons.hpp
  24. 26 90
      src/ArduinoJson/JsonVariantImpl.hpp
  25. 1 1
      src/ArduinoJson/Memory/JsonBufferAllocated.hpp
  26. 45 41
      src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp
  27. 4 4
      src/ArduinoJson/MsgPack/MsgPackSerializer.hpp
  28. 1 0
      src/ArduinoJson/Polyfills/type_traits/is_integral.hpp
  29. 27 12
      src/ArduinoJson/StaticJsonDocument.hpp
  30. 2 0
      src/ArduinoJson/Strings/FixedSizeRamString.hpp
  31. 1 0
      src/ArduinoJson/Strings/StlString.hpp
  32. 1 0
      test/CMakeLists.txt
  33. 0 4
      test/JsonArray/iterator.cpp
  34. 11 0
      test/JsonDocument/CMakeLists.txt
  35. 20 0
      test/JsonDocument/DynamicJsonDocument.cpp
  36. 20 0
      test/JsonDocument/StaticJsonDocument.cpp
  37. 17 25
      test/JsonObject/iterator.cpp
  38. 1 1
      test/JsonObject/remove.cpp
  39. 18 3
      test/JsonSerializer/JsonVariant.cpp
  40. 4 2
      test/JsonSerializer/std_stream.cpp
  41. 0 1
      test/JsonVariant/CMakeLists.txt
  42. 51 48
      test/JsonVariant/as.cpp
  43. 99 80
      test/JsonVariant/compare.cpp
  44. 0 65
      test/JsonVariant/copy.cpp
  45. 31 10
      test/JsonVariant/is.cpp
  46. 19 16
      test/JsonVariant/isnull.cpp
  47. 38 32
      test/JsonVariant/or.cpp
  48. 14 4
      test/JsonVariant/set_get.cpp
  49. 10 8
      test/JsonVariant/subscript.cpp
  50. 8 16
      test/Misc/unsigned_char.cpp
  51. 7 17
      test/Misc/vla.cpp
  52. 10 2
      test/MsgPackDeserializer/deserializeVariant.cpp
  53. 11 7
      test/MsgPackSerializer/serializeVariant.cpp

+ 50 - 0
CHANGELOG.md

@@ -1,6 +1,56 @@
 ArduinoJson: change log
 =======================
 
+HEAD
+----
+
+* Implemented reference semantics for `JsonVariant`
+* Replace `JsonPair`'s `key` and `value` with `key()` and `value()`
+
+> ### BREAKING CHANGES
+>
+> #### JsonVariant
+> 
+> `JsonVariant` now has a semantic similar to `JsonObject` and `JsonArray`.
+> It's a reference to a value stored in the `JsonDocument`.
+> As a consequence, a `JsonVariant` cannot be used as a standalone variable anymore.
+>
+> Old code:
+>
+> ```c++
+> JsonVariant myValue = 42;
+> ```
+>
+> New code:
+>
+> ```c++
+> DynamicJsonDocument doc;
+> JsonVariant myValue = doc.to<JsonVariant>();
+> myValue.set(42);
+> ```
+>
+> #### JsonPair
+>
+> Old code:
+>
+> ```c++
+> for(JsonPair p : myObject) {
+>   Serial.println(p.key);
+>   Serial.println(p.value.as<int>());
+> }
+> ```
+>
+> New code:
+>
+> ```c++
+> for(JsonPair p : myObject) {
+>   Serial.println(p.key());
+>   Serial.println(p.value().as<int>());
+> }
+> ```
+>
+> CAUTION: the key is now read only!
+
 v6.2.3-beta
 -----------
 

+ 2 - 0
src/ArduinoJson/Data/JsonVariantContent.hpp

@@ -4,6 +4,8 @@
 
 #pragma once
 
+#include <stdlib.h>  // size_t
+
 #include "JsonFloat.hpp"
 #include "JsonInteger.hpp"
 

+ 181 - 0
src/ArduinoJson/Data/JsonVariantData.hpp

@@ -0,0 +1,181 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Numbers/parseFloat.hpp"
+#include "../Numbers/parseInteger.hpp"
+#include "JsonVariantContent.hpp"
+#include "JsonVariantType.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+struct JsonVariantData {
+  JsonVariantType type;
+  JsonVariantContent content;
+
+  void setBoolean(bool value) {
+    type = JSON_BOOLEAN;
+    content.asInteger = static_cast<JsonUInt>(value);
+  }
+
+  void setFloat(JsonFloat value) {
+    type = JSON_FLOAT;
+    content.asFloat = value;
+  }
+
+  void setInteger(JsonInteger value) {
+    if (value > 0)
+      setPostiveInteger(static_cast<JsonUInt>(value));
+    else
+      setNegativeInteger(static_cast<JsonUInt>(-value));
+  }
+
+  void setNegativeInteger(JsonUInt value) {
+    type = JSON_NEGATIVE_INTEGER;
+    content.asInteger = value;
+  }
+
+  void setPostiveInteger(JsonUInt value) {
+    type = JSON_POSITIVE_INTEGER;
+    content.asInteger = value;
+  }
+
+  void setString(const char *value) {
+    type = JSON_STRING;
+    content.asString = value;
+  }
+
+  void setRaw(const char *data, size_t size) {
+    type = JSON_RAW;
+    content.asRaw.data = data;
+    content.asRaw.size = size;
+  }
+
+  void setNull() {
+    type = JSON_NULL;
+  }
+
+  void setArray(JsonArrayData &array) {
+    type = JSON_ARRAY;
+    content.asArray = &array;
+  }
+
+  void setObject(JsonObjectData &object) {
+    type = JSON_OBJECT;
+    content.asObject = &object;
+  }
+
+  JsonArrayData *asArray() const {
+    return type == JSON_ARRAY ? content.asArray : 0;
+  }
+
+  JsonObjectData *asObject() const {
+    return type == JSON_OBJECT ? content.asObject : 0;
+  }
+
+  template <typename T>
+  T asInteger() const {
+    switch (type) {
+      case JSON_NULL:
+      case JSON_RAW:
+        return 0;
+      case JSON_POSITIVE_INTEGER:
+      case JSON_BOOLEAN:
+        return T(content.asInteger);
+      case JSON_NEGATIVE_INTEGER:
+        return T(~content.asInteger + 1);
+      case JSON_STRING:
+        return parseInteger<T>(content.asString);
+      default:
+        return T(content.asFloat);
+    }
+  }
+
+  template <typename T>
+  T asFloat() const {
+    switch (type) {
+      case JSON_NULL:
+      case JSON_RAW:
+        return 0;
+      case JSON_POSITIVE_INTEGER:
+      case JSON_BOOLEAN:
+        return static_cast<T>(content.asInteger);
+      case JSON_NEGATIVE_INTEGER:
+        return -static_cast<T>(content.asInteger);
+      case JSON_STRING:
+        return parseFloat<T>(content.asString);
+      default:
+        return static_cast<T>(content.asFloat);
+    }
+  }
+
+  const char *asString() const {
+    return type == JSON_STRING ? content.asString : NULL;
+  }
+
+  bool isArray() const {
+    return type == Internals::JSON_ARRAY;
+  }
+
+  bool isBoolean() const {
+    return type == JSON_BOOLEAN;
+  }
+
+  bool isFloat() const {
+    return type == JSON_FLOAT || type == JSON_POSITIVE_INTEGER ||
+           type == JSON_NEGATIVE_INTEGER;
+  }
+
+  bool isInteger() const {
+    return type == JSON_POSITIVE_INTEGER || type == JSON_NEGATIVE_INTEGER;
+  }
+
+  bool isNull() const {
+    return type == JSON_NULL;
+  }
+
+  bool isObject() const {
+    return type == Internals::JSON_OBJECT;
+  }
+
+  bool isString() const {
+    return type == Internals::JSON_STRING;
+  }
+
+  template <typename Visitor>
+  void visit(Visitor &visitor) const {
+    switch (type) {
+      case JSON_FLOAT:
+        return visitor.acceptFloat(content.asFloat);
+
+      case JSON_ARRAY:
+        return visitor.acceptArray(*content.asArray);
+
+      case JSON_OBJECT:
+        return visitor.acceptObject(*content.asObject);
+
+      case JSON_STRING:
+        return visitor.acceptString(content.asString);
+
+      case JSON_RAW:
+        return visitor.acceptRawJson(content.asRaw.data, content.asRaw.size);
+
+      case JSON_NEGATIVE_INTEGER:
+        return visitor.acceptNegativeInteger(content.asInteger);
+
+      case JSON_POSITIVE_INTEGER:
+        return visitor.acceptPositiveInteger(content.asInteger);
+
+      case JSON_BOOLEAN:
+        return visitor.acceptBoolean(content.asInteger != 0);
+
+      default:
+        return visitor.acceptNull();
+    }
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 0 - 23
src/ArduinoJson/Data/JsonVariantDefault.hpp

@@ -1,23 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2018
-// MIT License
-
-#pragma once
-
-namespace ArduinoJson {
-namespace Internals {
-
-template <typename T>
-struct JsonVariantDefault {
-  static T get() {
-    return T();
-  }
-};
-
-template <typename T>
-struct JsonVariantDefault<const T> : JsonVariantDefault<T> {};
-
-template <typename T>
-struct JsonVariantDefault<T&> : JsonVariantDefault<T> {};
-}
-}

+ 4 - 4
src/ArduinoJson/Data/JsonVariantType.hpp

@@ -11,10 +11,10 @@ namespace Internals {
 // Enumerated type to know the current type of a JsonVariant.
 // The value determines which member of JsonVariantContent is used.
 enum JsonVariantType {
-  JSON_UNDEFINED,         // JsonVariant has not been initialized
-  JSON_UNPARSED,          // JsonVariant contains an unparsed string
-  JSON_STRING,            // JsonVariant stores a const char*
-  JSON_BOOLEAN,           // JsonVariant stores a bool
+  JSON_NULL,     // JsonVariant has not been initialized
+  JSON_RAW,      // JsonVariant contains a raw string that should not be escaped
+  JSON_STRING,   // JsonVariant stores a const char*
+  JSON_BOOLEAN,  // JsonVariant stores a bool
   JSON_POSITIVE_INTEGER,  // JsonVariant stores an JsonUInt
   JSON_NEGATIVE_INTEGER,  // JsonVariant stores an JsonUInt that must be negated
   JSON_ARRAY,             // JsonVariant stores a pointer to a JsonArrayData

+ 3 - 8
src/ArduinoJson/Data/List.hpp

@@ -22,7 +22,7 @@ class List {
   typedef ListIterator<T> iterator;
   typedef ListConstIterator<T> const_iterator;
 
-  explicit List(JsonBuffer *buf) : _buffer(buf), _firstNode(NULL) {}
+  List() : _firstNode(NULL) {}
 
   // Returns the numbers of elements in the list.
   // For a JsonObjectData, it would return the number of key-value pairs
@@ -32,8 +32,8 @@ class List {
     return nodeCount;
   }
 
-  iterator add() {
-    node_type *newNode = new (_buffer) node_type();
+  iterator add(JsonBuffer *buffer) {
+    node_type *newNode = new (buffer) node_type();
 
     if (_firstNode) {
       node_type *lastNode = _firstNode;
@@ -71,11 +71,6 @@ class List {
     }
   }
 
-  JsonBuffer &buffer() const {
-    return *_buffer;
-  }
-  JsonBuffer *_buffer;  // TODO!!
-
  protected:
   void clear() {
     _firstNode = 0;

+ 0 - 53
src/ArduinoJson/Data/ValueSaver.hpp

@@ -1,53 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2018
-// MIT License
-
-#pragma once
-
-#include "../JsonVariant.hpp"
-#include "../Memory/JsonBuffer.hpp"
-#include "../Polyfills/type_traits.hpp"
-#include "../Strings/StringTypes.hpp"
-
-namespace ArduinoJson {
-namespace Internals {
-
-template <typename Source, typename Enable = void>
-struct ValueSaver {
-  template <typename Destination>
-  static bool save(JsonBuffer*, Destination& destination, Source source) {
-    destination = source;
-    return true;
-  }
-};
-
-// We duplicate all strings except const char*
-template <typename TString>
-struct ValueSaver<
-    TString, typename enable_if<IsString<TString>::value &&
-                                !is_same<const char*, TString>::value>::type> {
-  template <typename Destination>
-  static bool save(JsonBuffer* buffer, Destination& dest, TString source) {
-    const char* dup = makeString(source).save(buffer);
-    if (!dup) return false;
-    dest = dup;
-    return true;
-  }
-};
-
-// We duplicate all SerializedValue<T> except SerializedValue<const char*>
-template <typename TString>
-struct ValueSaver<
-    const SerializedValue<TString>&,
-    typename enable_if<!is_same<const char*, TString>::value>::type> {
-  template <typename Destination>
-  static bool save(JsonBuffer* buffer, Destination& dest,
-                   const SerializedValue<TString>& source) {
-    const char* dup = makeString(source.data(), source.size()).save(buffer);
-    if (!dup) return false;
-    dest = SerializedValue<const char*>(dup, source.size());
-    return true;
-  }
-};
-}  // namespace Internals
-}  // namespace ArduinoJson

+ 4 - 4
src/ArduinoJson/Deserialization/deserialize.hpp

@@ -35,7 +35,7 @@ deserialize(TDocument &doc, const TString &input) {
   return makeDeserializer<TDeserializer>(&doc.buffer(), makeReader(input),
                                          makeStringStorage(doc.buffer(), input),
                                          doc.nestingLimit)
-      .parse(doc.template to<JsonVariant>());
+      .parse(doc.template to<JsonVariantData>());
 }
 //
 // DeserializationError deserialize(TDocument& doc, TChar* input);
@@ -48,7 +48,7 @@ DeserializationError deserialize(TDocument &doc, TChar *input) {
   return makeDeserializer<TDeserializer>(&doc.buffer(), makeReader(input),
                                          makeStringStorage(doc.buffer(), input),
                                          doc.nestingLimit)
-      .parse(doc.template to<JsonVariant>());
+      .parse(doc.template to<JsonVariantData>());
 }
 //
 // DeserializationError deserialize(TDocument& doc, TChar* input, size_t
@@ -63,7 +63,7 @@ DeserializationError deserialize(TDocument &doc, TChar *input,
   return makeDeserializer<TDeserializer>(
              &doc.buffer(), makeReader(input, inputSize),
              makeStringStorage(doc.buffer(), input), doc.nestingLimit)
-      .parse(doc.template to<JsonVariant>());
+      .parse(doc.template to<JsonVariantData>());
 }
 //
 // DeserializationError deserialize(TDocument& doc, TStream input);
@@ -76,7 +76,7 @@ DeserializationError deserialize(TDocument &doc, TStream &input) {
   return makeDeserializer<TDeserializer>(&doc.buffer(), makeReader(input),
                                          makeStringStorage(doc.buffer(), input),
                                          doc.nestingLimit)
-      .parse(doc.template to<JsonVariant>());
+      .parse(doc.template to<JsonVariantData>());
 }
 }  // namespace Internals
 }  // namespace ArduinoJson

+ 28 - 13
src/ArduinoJson/DynamicJsonDocument.hpp

@@ -12,24 +12,21 @@
 namespace ArduinoJson {
 
 class DynamicJsonDocument {
-  Internals::DynamicJsonBuffer _buffer;
-  JsonVariant _root;
-
  public:
   uint8_t nestingLimit;
 
   DynamicJsonDocument() : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
   DynamicJsonDocument(size_t capacity)
-      : _buffer(capacity), nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
+      : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), _buffer(capacity) {}
 
   template <typename T>
   bool is() const {
-    return _root.is<T>();
+    return getVariant().is<T>();
   }
 
   template <typename T>
   typename Internals::JsonVariantAs<T>::type as() const {
-    return _root.as<T>();
+    return getVariant().as<T>();
   }
 
   // JsonObject to<JsonObject>()
@@ -39,7 +36,7 @@ class DynamicJsonDocument {
   to() {
     clear();
     JsonObject object(&_buffer);
-    _root = object;
+    getVariant().set(object);
     return object;
   }
 
@@ -50,17 +47,27 @@ class DynamicJsonDocument {
   to() {
     clear();
     JsonArray array(&_buffer);
-    _root = array;
+    getVariant().set(array);
     return array;
   }
 
-  // JsonVariant& to<JsonVariant>()
+  // JsonVariant to<JsonVariant>()
   template <typename T>
   typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
-                                T&>::type
+                                JsonVariant>::type
   to() {
     clear();
-    return _root;
+    return getVariant();
+  }
+
+  // JsonVariantData& to<JsonVariantData>()
+  template <typename T>
+  typename Internals::enable_if<
+      Internals::is_same<T, Internals::JsonVariantData>::value,
+      Internals::JsonVariantData&>::type
+  to() {
+    clear();
+    return _rootData;
   }
 
   Internals::DynamicJsonBuffer& buffer() {
@@ -69,7 +76,7 @@ class DynamicJsonDocument {
 
   void clear() {
     _buffer.clear();
-    _root = JsonVariant();
+    _rootData.setNull();
   }
 
   size_t memoryUsage() const {
@@ -78,7 +85,15 @@ class DynamicJsonDocument {
 
   template <typename Visitor>
   void visit(Visitor& visitor) const {
-    return _root.visit(visitor);
+    return _rootData.visit(visitor);
+  }
+
+ private:
+  JsonVariant getVariant() const {
+    return JsonVariant(&_buffer, &_rootData);
   }
+
+  mutable Internals::DynamicJsonBuffer _buffer;
+  mutable Internals::JsonVariantData _rootData;
 };
 }  // namespace ArduinoJson

+ 30 - 24
src/ArduinoJson/Json/JsonDeserializer.hpp

@@ -7,6 +7,8 @@
 #include "../Deserialization/deserialize.hpp"
 #include "../JsonVariant.hpp"
 #include "../Memory/JsonBuffer.hpp"
+#include "../Numbers/isFloat.hpp"
+#include "../Numbers/isInteger.hpp"
 #include "../Polyfills/type_traits.hpp"
 #include "./EscapeSequence.hpp"
 
@@ -23,7 +25,7 @@ class JsonDeserializer {
         _stringStorage(stringStorage),
         _nestingLimit(nestingLimit),
         _loaded(false) {}
-  DeserializationError parse(JsonVariant &variant) {
+  DeserializationError parse(JsonVariantData &variant) {
     DeserializationError err = skipSpacesAndComments();
     if (err) return err;
 
@@ -63,12 +65,12 @@ class JsonDeserializer {
     return true;
   }
 
-  DeserializationError parseArray(JsonVariant &variant) {
+  DeserializationError parseArray(JsonVariantData &variant) {
     if (_nestingLimit == 0) return DeserializationError::TooDeep;
 
-    JsonArray array(_buffer);
-    if (array.isNull()) return DeserializationError::NoMemory;
-    variant = array;
+    JsonArrayData *array = new (_buffer) JsonArrayData;
+    if (!array) return DeserializationError::NoMemory;
+    variant.setArray(*array);
 
     // Check opening braket
     if (!eat('[')) return DeserializationError::InvalidInput;
@@ -82,13 +84,15 @@ class JsonDeserializer {
 
     // Read each value
     for (;;) {
+      // Allocate slot in array
+      JsonVariantData *value = array->addSlot(_buffer);
+      if (!value) return DeserializationError::NoMemory;
+
       // 1 - Parse value
-      JsonVariant value;
       _nestingLimit--;
-      err = parse(value);
+      err = parse(*value);
       _nestingLimit++;
       if (err) return err;
-      if (!array.add(value)) return DeserializationError::NoMemory;
 
       // 2 - Skip spaces
       err = skipSpacesAndComments();
@@ -100,12 +104,12 @@ class JsonDeserializer {
     }
   }
 
-  DeserializationError parseObject(JsonVariant &variant) {
+  DeserializationError parseObject(JsonVariantData &variant) {
     if (_nestingLimit == 0) return DeserializationError::TooDeep;
 
-    JsonObject object(_buffer);
-    if (object.isNull()) return DeserializationError::NoMemory;
-    variant = object;
+    JsonObjectData *object = new (_buffer) JsonObjectData;
+    if (!object) return DeserializationError::NoMemory;
+    variant.setObject(*object);
 
     // Check opening brace
     if (!eat('{')) return DeserializationError::InvalidInput;
@@ -129,13 +133,15 @@ class JsonDeserializer {
       if (err) return err;  // Colon
       if (!eat(':')) return DeserializationError::InvalidInput;
 
+      // Allocate slot in object
+      JsonVariantData *value = object->addSlot(_buffer, key);
+      if (!value) return DeserializationError::NoMemory;
+
       // Parse value
-      JsonVariant value;
       _nestingLimit--;
-      err = parse(value);
+      err = parse(*value);
       _nestingLimit++;
       if (err) return err;
-      if (!object.set(key, value)) return DeserializationError::NoMemory;
 
       // Skip spaces
       err = skipSpacesAndComments();
@@ -151,7 +157,7 @@ class JsonDeserializer {
     }
   }
 
-  DeserializationError parseValue(JsonVariant &variant) {
+  DeserializationError parseValue(JsonVariantData &variant) {
     if (isQuote(current())) {
       return parseStringValue(variant);
     } else {
@@ -167,11 +173,11 @@ class JsonDeserializer {
     }
   }
 
-  DeserializationError parseStringValue(JsonVariant &variant) {
+  DeserializationError parseStringValue(JsonVariantData &variant) {
     const char *value;
     DeserializationError err = parseQuotedString(&value);
     if (err) return err;
-    variant = value;
+    variant.setString(value);
     return DeserializationError::Ok;
   }
 
@@ -229,7 +235,7 @@ class JsonDeserializer {
     return DeserializationError::Ok;
   }
 
-  DeserializationError parseNumericValue(JsonVariant &result) {
+  DeserializationError parseNumericValue(JsonVariantData &result) {
     char buffer[64];
     uint8_t n = 0;
 
@@ -242,15 +248,15 @@ class JsonDeserializer {
     buffer[n] = 0;
 
     if (isInteger(buffer)) {
-      result = parseInteger<JsonInteger>(buffer);
+      result.setInteger(parseInteger<JsonInteger>(buffer));
     } else if (isFloat(buffer)) {
-      result = parseFloat<JsonFloat>(buffer);
+      result.setFloat(parseFloat<JsonFloat>(buffer));
     } else if (!strcmp(buffer, "true")) {
-      result = true;
+      result.setBoolean(true);
     } else if (!strcmp(buffer, "false")) {
-      result = false;
+      result.setBoolean(false);
     } else if (!strcmp(buffer, "null")) {
-      result = static_cast<const char *>(0);
+      result.setNull();
     } else {
       return DeserializationError::InvalidInput;
     }

+ 4 - 4
src/ArduinoJson/Json/JsonSerializer.hpp

@@ -20,10 +20,10 @@ class JsonSerializer {
     _writer.writeFloat(value);
   }
 
-  void acceptArray(const JsonArray &array) {
+  void acceptArray(const JsonArrayData &array) {
     _writer.beginArray();
 
-    JsonArray::const_iterator it = array.begin();
+    JsonArrayData::const_iterator it = array.begin();
     while (it != array.end()) {
       it->visit(*this);
 
@@ -36,10 +36,10 @@ class JsonSerializer {
     _writer.endArray();
   }
 
-  void acceptObject(const JsonObject &object) {
+  void acceptObject(const JsonObjectData &object) {
     _writer.beginObject();
 
-    JsonObject::const_iterator it = object.begin();
+    JsonObjectData::const_iterator it = object.begin();
     while (it != object.end()) {
       _writer.writeString(it->key);
       _writer.writeColon();

+ 22 - 30
src/ArduinoJson/JsonArray.hpp

@@ -4,7 +4,8 @@
 
 #pragma once
 
-#include "./JsonArrayData.hpp"
+#include "JsonArrayData.hpp"
+#include "JsonArrayIterator.hpp"
 
 namespace ArduinoJson {
 
@@ -18,13 +19,13 @@ class JsonArray {
   friend class JsonVariant;
 
  public:
-  typedef Internals::JsonArrayData::iterator iterator;
-  typedef Internals::JsonArrayData::const_iterator const_iterator;
+  typedef JsonArrayIterator iterator;
 
-  JsonArray() : _data(0) {}
-  JsonArray(Internals::JsonArrayData* arr) : _data(arr) {}
-  JsonArray(Internals::JsonBuffer* buf)
-      : _data(new (buf) Internals::JsonArrayData(buf)) {}
+  JsonArray() : _buffer(0), _data(0) {}
+  explicit JsonArray(Internals::JsonBuffer* buf, Internals::JsonArrayData* arr)
+      : _buffer(buf), _data(arr) {}
+  explicit JsonArray(Internals::JsonBuffer* buf)
+      : _buffer(buf), _data(new (buf) Internals::JsonArrayData()) {}
 
   // Adds the specified value at the end of the array.
   //
@@ -43,24 +44,15 @@ class JsonArray {
     return add_impl<T*>(value);
   }
 
-  iterator begin() {
+  iterator begin() const {
     if (!_data) return iterator();
-    return _data->begin();
+    return iterator(_buffer, _data->begin());
   }
 
-  const_iterator begin() const {
-    if (!_data) return const_iterator();
-    return _data->begin();
-  }
-
-  iterator end() {
+  iterator end() const {
     return iterator();
   }
 
-  const_iterator end() const {
-    return const_iterator();
-  }
-
   // Imports a 1D array
   template <typename T, size_t N>
   bool copyFrom(T (&array)[N]) {
@@ -100,8 +92,7 @@ class JsonArray {
   template <typename T>
   size_t copyTo(T* array, size_t len) const {
     size_t i = 0;
-    for (const_iterator it = begin(); it != end() && i < len; ++it)
-      array[i++] = *it;
+    for (iterator it = begin(); it != end() && i < len; ++it) array[i++] = *it;
     return i;
   }
 
@@ -110,7 +101,7 @@ class JsonArray {
   void copyTo(T (&array)[N1][N2]) const {
     if (!_data) return;
     size_t i = 0;
-    for (const_iterator it = begin(); it != end() && i < N1; ++it) {
+    for (iterator it = begin(); it != end() && i < N1; ++it) {
       it->as<JsonArray>().copyTo(array[i++]);
     }
   }
@@ -129,21 +120,21 @@ class JsonArray {
   // Gets the value at the specified index.
   template <typename T>
   typename Internals::JsonVariantAs<T>::type get(size_t index) const {
-    const_iterator it = begin() += index;
-    return it != end() ? it->as<T>() : Internals::JsonVariantDefault<T>::get();
+    iterator it = begin() += index;
+    return it != end() ? it->as<T>() : T();
   }
 
   // Check the type of the value at specified index.
   template <typename T>
   bool is(size_t index) const {
-    const_iterator it = begin() += index;
+    iterator it = begin() += index;
     return it != end() ? it->is<T>() : false;
   }
 
   // Removes element at specified position.
   void remove(iterator it) {
     if (!_data) return;
-    _data->remove(it);
+    _data->remove(it.internal());
   }
 
   // Removes element at specified index.
@@ -182,7 +173,7 @@ class JsonArray {
   template <typename Visitor>
   void visit(Visitor& visitor) const {
     if (_data)
-      return visitor.acceptArray(*this);
+      visitor.acceptArray(*_data);
     else
       visitor.acceptNull();
   }
@@ -192,17 +183,18 @@ class JsonArray {
   bool set_impl(size_t index, TValueRef value) {
     iterator it = begin() += index;
     if (it == end()) return false;
-    return Internals::ValueSaver<TValueRef>::save(_data->_buffer, *it, value);
+    return it->set(value);
   }
 
   template <typename TValueRef>
   bool add_impl(TValueRef value) {
     if (!_data) return false;
-    iterator it = _data->add();
+    iterator it = iterator(_buffer, _data->add(_buffer));
     if (it == end()) return false;
-    return Internals::ValueSaver<TValueRef>::save(_data->_buffer, *it, value);
+    return it->set(value);
   }
 
+  Internals::JsonBuffer* _buffer;
   Internals::JsonArrayData* _data;
 };
 }  // namespace ArduinoJson

+ 6 - 4
src/ArduinoJson/JsonArrayData.hpp

@@ -4,9 +4,8 @@
 
 #pragma once
 
+#include "Data/JsonVariantData.hpp"
 #include "Data/List.hpp"
-#include "Data/ValueSaver.hpp"
-#include "JsonVariant.hpp"
 #include "Memory/JsonBufferAllocated.hpp"
 #include "Polyfills/type_traits.hpp"
 
@@ -19,8 +18,11 @@
 
 namespace ArduinoJson {
 namespace Internals {
-struct JsonArrayData : List<JsonVariant>, JsonBufferAllocated {
-  explicit JsonArrayData(JsonBuffer *buf) throw() : List<JsonVariant>(buf) {}
+struct JsonArrayData : List<JsonVariantData>, JsonBufferAllocated {
+  JsonVariantData* addSlot(JsonBuffer* buffer) {
+    iterator it = add(buffer);
+    return it != end() ? &*it : 0;
+  }
 };
 }  // namespace Internals
 }  // namespace ArduinoJson

+ 2 - 2
src/ArduinoJson/JsonArrayImpl.hpp

@@ -11,14 +11,14 @@ namespace ArduinoJson {
 
 inline JsonArray JsonArray::createNestedArray() {
   if (!_data) return JsonArray();
-  JsonArray array(_data->_buffer);
+  JsonArray array(_buffer);
   if (!array.isNull()) add(array);
   return array;
 }
 
 inline JsonObject JsonArray::createNestedObject() {
   if (!_data) return JsonObject();
-  JsonObject object(_data->_buffer);
+  JsonObject object(_buffer);
   if (!object.isNull()) add(object);
   return object;
 }

+ 72 - 0
src/ArduinoJson/JsonArrayIterator.hpp

@@ -0,0 +1,72 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Data/ListIterator.hpp"
+#include "JsonVariant.hpp"
+
+namespace ArduinoJson {
+
+class JsonVariantPtr {
+ public:
+  JsonVariantPtr(Internals::JsonBuffer *buffer,
+                 Internals::JsonVariantData *data)
+      : _variant(buffer, data) {}
+
+  JsonVariant *operator->() {
+    return &_variant;
+  }
+
+  JsonVariant &operator*() {
+    return _variant;
+  }
+
+ private:
+  JsonVariant _variant;
+};
+
+class JsonArrayIterator {
+  typedef Internals::ListIterator<Internals::JsonVariantData> internal_iterator;
+
+ public:
+  JsonArrayIterator() {}
+  explicit JsonArrayIterator(Internals::JsonBuffer *buffer,
+                             internal_iterator iterator)
+      : _iterator(iterator), _buffer(buffer) {}
+
+  JsonVariant operator*() const {
+    return JsonVariant(_buffer, &*_iterator);
+  }
+  JsonVariantPtr operator->() {
+    return JsonVariantPtr(_buffer, &*_iterator);
+  }
+
+  bool operator==(const JsonArrayIterator &other) const {
+    return _iterator == other._iterator;
+  }
+
+  bool operator!=(const JsonArrayIterator &other) const {
+    return _iterator != other._iterator;
+  }
+
+  JsonArrayIterator &operator++() {
+    ++_iterator;
+    return *this;
+  }
+
+  JsonArrayIterator &operator+=(size_t distance) {
+    _iterator += distance;
+    return *this;
+  }
+
+  internal_iterator internal() {
+    return _iterator;
+  }
+
+ private:
+  internal_iterator _iterator;
+  Internals::JsonBuffer *_buffer;
+};
+}  // namespace ArduinoJson

+ 1 - 1
src/ArduinoJson/JsonArraySubscript.hpp

@@ -20,7 +20,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
       : _array(array), _index(index) {}
 
   FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& src) {
-    _array.set(_index, src);
+    _array.set(_index, src.as<JsonVariant>());
     return *this;
   }
 

+ 49 - 41
src/ArduinoJson/JsonObject.hpp

@@ -5,29 +5,27 @@
 #pragma once
 
 #include "./JsonObjectData.hpp"
+#include "./JsonObjectIterator.hpp"
 
 namespace ArduinoJson {
 
 class JsonObject {
   friend class JsonVariant;
+  typedef Internals::JsonObjectData::iterator internal_iterator;
 
  public:
-  typedef Internals::JsonObjectData::iterator iterator;
-  typedef Internals::JsonObjectData::const_iterator const_iterator;
+  typedef JsonObjectIterator iterator;
 
-  JsonObject() : _data(0) {}
-  JsonObject(Internals::JsonObjectData* object) : _data(object) {}
-  JsonObject(Internals::JsonBuffer* buf)
-      : _data(new (buf) Internals::JsonObjectData(buf)) {}
+  JsonObject() : _buffer(0), _data(0) {}
+  explicit JsonObject(Internals::JsonBuffer* buf,
+                      Internals::JsonObjectData* object)
+      : _buffer(buf), _data(object) {}
+  explicit JsonObject(Internals::JsonBuffer* buf)
+      : _buffer(buf), _data(new (buf) Internals::JsonObjectData()) {}
 
-  iterator begin() {
+  iterator begin() const {
     if (!_data) return iterator();
-    return _data->begin();
-  }
-
-  const_iterator begin() const {
-    if (!_data) return const_iterator();
-    return _data->begin();
+    return iterator(_buffer, _data->begin());
   }
 
   // Tells weither the specified key is present and associated with a value.
@@ -46,14 +44,10 @@ class JsonObject {
     return containsKey_impl<TString*>(key);
   }
 
-  iterator end() {
+  iterator end() const {
     return iterator();
   }
 
-  const_iterator end() const {
-    return const_iterator();
-  }
-
   // Creates and adds a JsonArray.
   //
   // JsonArray createNestedArray(TKey);
@@ -165,7 +159,7 @@ class JsonObject {
 
   void remove(iterator it) {
     if (!_data) return;
-    _data->remove(it);
+    _data->remove(it.internal());
   }
 
   // Removes the specified key and the associated value.
@@ -232,15 +226,15 @@ class JsonObject {
   template <typename Visitor>
   void visit(Visitor& visitor) const {
     if (_data)
-      visitor.acceptObject(*this);
+      visitor.acceptObject(*_data);
     else
-      return visitor.acceptNull();
+      visitor.acceptNull();
   }
 
  private:
   template <typename TStringRef>
   bool containsKey_impl(TStringRef key) const {
-    return findKey<TStringRef>(key) != end();
+    return findKey<TStringRef>(key) != _data->end();
   }
 
   template <typename TStringRef>
@@ -251,30 +245,32 @@ class JsonObject {
 
   // Returns the list node that matches the specified key.
   template <typename TStringRef>
-  iterator findKey(TStringRef key) {
-    iterator it;
-    for (it = begin(); it != end(); ++it) {
+  internal_iterator findKey(TStringRef key) {
+    if (!_data) return internal_iterator();
+    internal_iterator it;
+    for (it = _data->begin(); it != _data->end(); ++it) {
       if (Internals::makeString(key).equals(it->key)) break;
     }
     return it;
   }
   template <typename TStringRef>
-  const_iterator findKey(TStringRef key) const {
+  internal_iterator findKey(TStringRef key) const {
     return const_cast<JsonObject*>(this)->findKey<TStringRef>(key);
   }
 
   template <typename TStringRef, typename TValue>
   typename Internals::JsonVariantAs<TValue>::type get_impl(
       TStringRef key) const {
-    const_iterator it = findKey<TStringRef>(key);
-    return it != end() ? it->value.as<TValue>()
-                       : Internals::JsonVariantDefault<TValue>::get();
+    internal_iterator it = findKey<TStringRef>(key);
+    return it != _data->end() ? JsonVariant(_buffer, &it->value).as<TValue>()
+                              : TValue();
   }
 
   template <typename TStringRef, typename TValue>
   bool is_impl(TStringRef key) const {
-    const_iterator it = findKey<TStringRef>(key);
-    return it != end() ? it->value.is<TValue>() : false;
+    internal_iterator it = findKey<TStringRef>(key);
+    return it != _data->end() ? JsonVariant(_buffer, &it->value).is<TValue>()
+                              : false;
   }
 
   template <typename TStringRef>
@@ -291,21 +287,33 @@ class JsonObject {
     if (Internals::makeString(key).is_null()) return false;
 
     // search a matching key
-    iterator it = findKey<TStringRef>(key);
-    if (it == end()) {
+    internal_iterator it = findKey<TStringRef>(key);
+    if (it == _data->end()) {
       // add the key
-      it = _data->add();
-      if (it == end()) return false;
-      bool key_ok =
-          Internals::ValueSaver<TStringRef>::save(_data->_buffer, it->key, key);
-      if (!key_ok) return false;
+      // TODO: use JsonPairData directly, we don't need an iterator
+      it = _data->add(_buffer);
+      if (it == _data->end()) return false;
+      if (!set_key(it, key)) return false;
     }
 
     // save the value
-    return Internals::ValueSaver<TValueRef>::save(_data->_buffer, it->value,
-                                                  value);
+    return JsonVariant(_buffer, &it->value).set(value);
+  }
+
+  bool set_key(internal_iterator& it, const char* key) {
+    it->key = key;
+    return true;
+  }
+
+  template <typename T>
+  bool set_key(internal_iterator& it, const T& key) {
+    const char* dup = Internals::makeString(key).save(_buffer);
+    if (!dup) return false;
+    it->key = dup;
+    return true;
   }
 
-  Internals::JsonObjectData* _data;
+  mutable Internals::JsonBuffer* _buffer;
+  mutable Internals::JsonObjectData* _data;
 };
 }  // namespace ArduinoJson

+ 7 - 3
src/ArduinoJson/JsonObjectData.hpp

@@ -5,7 +5,6 @@
 #pragma once
 
 #include "Data/List.hpp"
-#include "Data/ValueSaver.hpp"
 #include "JsonPair.hpp"
 #include "Memory/JsonBufferAllocated.hpp"
 #include "Polyfills/type_traits.hpp"
@@ -19,8 +18,13 @@
 
 namespace ArduinoJson {
 namespace Internals {
-struct JsonObjectData : List<JsonPair>, JsonBufferAllocated {
-  explicit JsonObjectData(JsonBuffer* buf) throw() : List<JsonPair>(buf) {}
+struct JsonObjectData : List<JsonPairData>, JsonBufferAllocated {
+  JsonVariantData* addSlot(JsonBuffer* buffer, const char* key) {
+    iterator it = add(buffer);
+    if (it == end()) return 0;
+    it->key = key;
+    return &it->value;
+  }
 };
 }  // namespace Internals
 }  // namespace ArduinoJson

+ 2 - 2
src/ArduinoJson/JsonObjectImpl.hpp

@@ -22,7 +22,7 @@ inline JsonArray JsonObject::createNestedArray(TString* key) {
 template <typename TStringRef>
 inline JsonArray JsonObject::createNestedArray_impl(TStringRef key) {
   if (!_data) return JsonArray();
-  JsonArray array(_data->_buffer);
+  JsonArray array(_buffer);
   if (!array.isNull()) set(key, array);
   return array;
 }
@@ -30,7 +30,7 @@ inline JsonArray JsonObject::createNestedArray_impl(TStringRef key) {
 template <typename TStringRef>
 inline JsonObject JsonObject::createNestedObject_impl(TStringRef key) {
   if (!_data) return JsonObject();
-  JsonObject object(_data->_buffer);
+  JsonObject object(_buffer);
   if (!object.isNull()) set(key, object);
   return object;
 }

+ 72 - 0
src/ArduinoJson/JsonObjectIterator.hpp

@@ -0,0 +1,72 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Data/ListIterator.hpp"
+#include "JsonPair.hpp"
+
+namespace ArduinoJson {
+
+class JsonPairPtr {
+ public:
+  JsonPairPtr(Internals::JsonBuffer *buffer, Internals::JsonPairData *data)
+      : _pair(buffer, data) {}
+
+  const JsonPair *operator->() const {
+    return &_pair;
+  }
+
+  const JsonPair &operator*() const {
+    return _pair;
+  }
+
+ private:
+  JsonPair _pair;
+};
+
+// A read-write forward iterator for JsonArray
+class JsonObjectIterator {
+  typedef Internals::ListIterator<Internals::JsonPairData> internal_iterator;
+
+ public:
+  JsonObjectIterator() {}
+  explicit JsonObjectIterator(Internals::JsonBuffer *buffer,
+                              internal_iterator iterator)
+      : _buffer(buffer), _iterator(iterator) {}
+
+  JsonPair operator*() const {
+    return JsonPair(_buffer, &*_iterator);
+  }
+  JsonPairPtr operator->() {
+    return JsonPairPtr(_buffer, &*_iterator);
+  }
+
+  bool operator==(const JsonObjectIterator &other) const {
+    return _iterator == other._iterator;
+  }
+
+  bool operator!=(const JsonObjectIterator &other) const {
+    return _iterator != other._iterator;
+  }
+
+  JsonObjectIterator &operator++() {
+    ++_iterator;
+    return *this;
+  }
+
+  JsonObjectIterator &operator+=(size_t distance) {
+    _iterator += distance;
+    return *this;
+  }
+
+  internal_iterator internal() {
+    return _iterator;
+  }
+
+ private:
+  Internals::JsonBuffer *_buffer;
+  internal_iterator _iterator;
+};
+}  // namespace ArduinoJson

+ 24 - 3
src/ArduinoJson/JsonPair.hpp

@@ -8,9 +8,30 @@
 
 namespace ArduinoJson {
 
-// A key value pair for JsonObjectData.
-struct JsonPair {
+namespace Internals {
+
+struct JsonPairData {
   const char* key;
-  JsonVariant value;
+  JsonVariantData value;
+};
+}  // namespace Internals
+
+// A key value pair for JsonObjectData.
+class JsonPair {
+ public:
+  JsonPair(Internals::JsonBuffer* buffer, Internals::JsonPairData* data)
+      : _key(data->key), _value(buffer, &data->value) {}
+
+  const char* key() const {
+    return _key;
+  }
+
+  JsonVariant value() const {
+    return _value;
+  }
+
+ private:
+  const char* _key;
+  JsonVariant _value;
 };
 }  // namespace ArduinoJson

+ 135 - 132
src/ArduinoJson/JsonVariant.hpp

@@ -7,10 +7,10 @@
 #include <stddef.h>
 #include <stdint.h>  // for uint8_t
 
-#include "Data/JsonVariantContent.hpp"
-#include "Data/JsonVariantDefault.hpp"
-#include "Data/JsonVariantType.hpp"
+#include "Data/JsonVariantData.hpp"
+#include "JsonVariant.hpp"
 #include "JsonVariantBase.hpp"
+#include "Memory/JsonBuffer.hpp"
 #include "Polyfills/type_traits.hpp"
 #include "Serialization/DynamicStringWriter.hpp"
 #include "SerializedValue.hpp"
@@ -30,84 +30,135 @@ class JsonObject;
 // - a reference to a JsonArray or JsonObject
 class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
  public:
+  // Intenal use only
+  explicit JsonVariant(Internals::JsonBuffer *buffer,
+                       Internals::JsonVariantData *data)
+      : _buffer(buffer), _data(data) {}
+
   // Creates an uninitialized JsonVariant
-  JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
+  JsonVariant() : _buffer(0), _data(0) {}
 
-  // Create a JsonVariant containing a boolean value.
-  // It will be serialized as "true" or "false" in JSON.
-  JsonVariant(bool value) {
-    using namespace Internals;
-    _type = JSON_BOOLEAN;
-    _content.asInteger = static_cast<JsonUInt>(value);
+  // set(bool value)
+  bool set(bool value) {
+    if (!_data) return false;
+    _data->setBoolean(value);
+    return true;
   }
 
-  // Create a JsonVariant containing a floating point value.
-  // JsonVariant(double value);
-  // JsonVariant(float value);
+  // set(double value);
+  // set(float value);
   template <typename T>
-  JsonVariant(T value,
-              typename Internals::enable_if<
-                  Internals::is_floating_point<T>::value>::type * = 0) {
-    using namespace Internals;
-    _type = JSON_FLOAT;
-    _content.asFloat = static_cast<JsonFloat>(value);
+  bool set(T value, typename Internals::enable_if<
+                        Internals::is_floating_point<T>::value>::type * = 0) {
+    if (!_data) return false;
+    _data->setFloat(static_cast<Internals::JsonFloat>(value));
+    return true;
   }
 
-  // Create a JsonVariant containing an integer value.
-  // JsonVariant(char)
-  // JsonVariant(signed short)
-  // JsonVariant(signed int)
-  // JsonVariant(signed long)
-  // JsonVariant(signed char)
+  // set(char)
+  // set(signed short)
+  // set(signed int)
+  // set(signed long)
+  // set(signed char)
   template <typename T>
-  JsonVariant(
-      T value,
-      typename Internals::enable_if<Internals::is_integral<T>::value &&
-                                    Internals::is_signed<T>::value>::type * =
-          0) {
-    using namespace Internals;
-    if (value >= 0) {
-      _type = JSON_POSITIVE_INTEGER;
-      _content.asInteger = static_cast<JsonUInt>(value);
-    } else {
-      _type = JSON_NEGATIVE_INTEGER;
-      _content.asInteger = ~static_cast<JsonUInt>(value) + 1;
-    }
+  bool set(T value,
+           typename Internals::enable_if<Internals::is_integral<T>::value &&
+                                         Internals::is_signed<T>::value>::type
+               * = 0) {
+    if (!_data) return false;
+    if (value >= 0)
+      _data->setPostiveInteger(static_cast<Internals::JsonUInt>(value));
+    else
+      _data->setNegativeInteger(~static_cast<Internals::JsonUInt>(value) + 1);
+    return true;
+  }
+
+  // set(unsigned short)
+  // set(unsigned int)
+  // set(unsigned long)
+  template <typename T>
+  bool set(T value,
+           typename Internals::enable_if<Internals::is_integral<T>::value &&
+                                         Internals::is_unsigned<T>::value>::type
+               * = 0) {
+    if (!_data) return false;
+    _data->setPostiveInteger(static_cast<Internals::JsonUInt>(value));
+    return true;
+  }
+
+  // set(SerializedValue<const char *>)
+  bool set(Internals::SerializedValue<const char *> value) {
+    if (!_data) return false;
+    _data->setRaw(value.data(), value.size());
+    return true;
   }
-  // JsonVariant(unsigned short)
-  // JsonVariant(unsigned int)
-  // JsonVariant(unsigned long)
+
+  // set(SerializedValue<std::string>)
+  // set(SerializedValue<String>)
+  // set(SerializedValue<const __FlashStringHelper*>)
+  template <typename T>
+  bool set(Internals::SerializedValue<T> value,
+           typename Internals::enable_if<
+               !Internals::is_same<const char *, T>::value>::type * = 0) {
+    if (!_data) return false;
+    const char *dup =
+        Internals::makeString(value.data(), value.size()).save(_buffer);
+    if (dup)
+      _data->setRaw(dup, value.size());
+    else
+      _data->setNull();
+    return true;
+  }
+
+  // set(const std::string&)
+  // set(const String&)
   template <typename T>
-  JsonVariant(
-      T value,
-      typename Internals::enable_if<Internals::is_integral<T>::value &&
-                                    Internals::is_unsigned<T>::value>::type * =
-          0) {
-    using namespace Internals;
-    _type = JSON_POSITIVE_INTEGER;
-    _content.asInteger = static_cast<JsonUInt>(value);
+  bool set(const T &value,
+           typename Internals::enable_if<Internals::IsString<T>::value>::type
+               * = 0) {
+    if (!_data) return false;
+    const char *dup = Internals::makeString(value).save(_buffer);
+    if (dup) {
+      _data->setString(dup);
+      return true;
+    } else {
+      _data->setNull();
+      return false;
+    }
   }
 
-  // Create a JsonVariant containing a string.
-  // JsonVariant(const char*);
-  // JsonVariant(const signed char*);
-  // JsonVariant(const unsigned char*);
-  template <typename TChar>
-  JsonVariant(const TChar *value,
-              typename Internals::enable_if<sizeof(TChar) == 1>::type * = 0) {
-    _type = Internals::JSON_STRING;
-    _content.asString = reinterpret_cast<const char *>(value);
+  // set(const char*);
+  // set(const char[n]); // VLA
+  bool set(const char *value) {
+    if (!_data) return false;
+    _data->setString(value);
+    return true;
+  }
+  // set(const unsigned char*);
+  // set(const unsigned char[n]); // VLA
+  bool set(const unsigned char *value) {
+    return set(reinterpret_cast<const char *>(value));
+  }
+  // set(const signed char*);
+  // set(const signed char[n]); // VLA
+  bool set(const signed char *value) {
+    return set(reinterpret_cast<const char *>(value));
   }
 
-  // Create a JsonVariant containing an unparsed string
-  JsonVariant(Internals::SerializedValue<const char *> value) {
-    _type = Internals::JSON_UNPARSED;
-    _content.asRaw.data = value.data();
-    _content.asRaw.size = value.size();
+  bool set(const JsonVariant &value) {
+    if (!_data) return false;
+    if (value._data)
+      *_data = *value._data;
+    else
+      _data->setNull();
+    return true;
   }
 
-  JsonVariant(JsonArray array);
-  JsonVariant(JsonObject object);
+  bool set(const JsonArray &array);
+  bool set(const Internals::JsonArraySubscript &);
+  bool set(const JsonObject &object);
+  template <typename TString>
+  bool set(const Internals::JsonObjectSubscript<TString> &);
 
   // Get the variant as the specified type.
   //
@@ -123,14 +174,14 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
   template <typename T>
   const typename Internals::enable_if<Internals::is_integral<T>::value, T>::type
   as() const {
-    return variantAsInteger<T>();
+    return _data ? _data->asInteger<T>() : T();
   }
   // bool as<bool>() const
   template <typename T>
   const typename Internals::enable_if<Internals::is_same<T, bool>::value,
                                       T>::type
   as() const {
-    return variantAsInteger<int>() != 0;
+    return _data && _data->asInteger<int>() != 0;
   }
   //
   // double as<double>() const;
@@ -139,7 +190,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
   const typename Internals::enable_if<Internals::is_floating_point<T>::value,
                                       T>::type
   as() const {
-    return variantAsFloat<T>();
+    return _data ? _data->asFloat<T>() : 0;
   }
   //
   // const char* as<const char*>() const;
@@ -149,7 +200,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
                                     Internals::is_same<T, char *>::value,
                                 const char *>::type
   as() const {
-    return variantAsString();
+    return _data ? _data->asString() : 0;
   }
   //
   // std::string as<std::string>() const;
@@ -157,7 +208,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
   template <typename T>
   typename Internals::enable_if<Internals::IsWriteableString<T>::value, T>::type
   as() const {
-    const char *cstr = variantAsString();
+    const char *cstr = _data ? _data->asString() : 0;
     if (cstr) return T(cstr);
     T s;
     serializeJson(*this, s);
@@ -205,7 +256,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
   template <typename T>
   typename Internals::enable_if<Internals::is_integral<T>::value, bool>::type
   is() const {
-    return variantIsInteger();
+    return _data && _data->isInteger();
   }
   //
   // bool is<double>() const;
@@ -214,14 +265,14 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
   typename Internals::enable_if<Internals::is_floating_point<T>::value,
                                 bool>::type
   is() const {
-    return variantIsFloat();
+    return _data && _data->isFloat();
   }
   //
   // bool is<bool>() const
   template <typename T>
   typename Internals::enable_if<Internals::is_same<T, bool>::value, bool>::type
   is() const {
-    return variantIsBoolean();
+    return _data && _data->isBoolean();
   }
   //
   // bool is<const char*>() const;
@@ -231,7 +282,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
                                     Internals::is_same<T, char *>::value,
                                 bool>::type
   is() const {
-    return variantIsString();
+    return _data && _data->isString();
   }
   //
   // bool is<JsonArray> const;
@@ -242,7 +293,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
                          JsonArray>::value,
       bool>::type
   is() const {
-    return variantIsArray();
+    return _data && _data->isArray();
   }
   //
   // bool is<JsonObject> const;
@@ -253,72 +304,24 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
                          JsonObject>::value,
       bool>::type
   is() const {
-    return variantIsObject();
+    return _data && _data->isObject();
   }
 
   // Returns true if the variant has a value
   bool isNull() const {
-    return _type == Internals::JSON_UNDEFINED;
+    return _data == 0 || _data->isNull();
   }
 
   template <typename Visitor>
   void visit(Visitor &visitor) const {
-    using namespace Internals;
-    switch (_type) {
-      case JSON_FLOAT:
-        return visitor.acceptFloat(_content.asFloat);
-
-      case JSON_ARRAY:
-        return visitor.acceptArray(_content.asArray);
-
-      case JSON_OBJECT:
-        return visitor.acceptObject(_content.asObject);
-
-      case JSON_STRING:
-        return visitor.acceptString(_content.asString);
-
-      case JSON_UNPARSED:
-        return visitor.acceptRawJson(_content.asRaw.data, _content.asRaw.size);
-
-      case JSON_NEGATIVE_INTEGER:
-        return visitor.acceptNegativeInteger(_content.asInteger);
-
-      case JSON_POSITIVE_INTEGER:
-        return visitor.acceptPositiveInteger(_content.asInteger);
-
-      case JSON_BOOLEAN:
-        return visitor.acceptBoolean(_content.asInteger != 0);
-
-      default:  // JSON_UNDEFINED
-        return visitor.acceptNull();
-    }
+    if (_data)
+      _data->visit(visitor);
+    else
+      visitor.acceptNull();
   }
 
  private:
-  JsonArray variantAsArray() const;
-  JsonObject variantAsObject() const;
-  const char *variantAsString() const;
-  template <typename T>
-  T variantAsFloat() const;
-  template <typename T>
-  T variantAsInteger() const;
-  bool variantIsBoolean() const;
-  bool variantIsFloat() const;
-  bool variantIsInteger() const;
-  bool variantIsArray() const {
-    return _type == Internals::JSON_ARRAY;
-  }
-  bool variantIsObject() const {
-    return _type == Internals::JSON_OBJECT;
-  }
-  bool variantIsString() const {
-    return _type == Internals::JSON_STRING;
-  }
-
-  // The current type of the variant
-  Internals::JsonVariantType _type;
-
-  // The various alternatives for the value of the variant.
-  Internals::JsonVariantContent _content;
-};
+  Internals::JsonBuffer *_buffer;
+  Internals::JsonVariantData *_data;
+};  // namespace ArduinoJson
 }  // namespace ArduinoJson

+ 2 - 0
src/ArduinoJson/JsonVariantComparisons.hpp

@@ -5,6 +5,8 @@
 #pragma once
 
 #include "Data/IsVariant.hpp"
+#include "Data/JsonFloat.hpp"
+#include "Data/JsonInteger.hpp"
 #include "Polyfills/type_traits.hpp"
 #include "Strings/StringTypes.hpp"
 

+ 26 - 90
src/ArduinoJson/JsonVariantImpl.hpp

@@ -8,8 +8,6 @@
 #include "JsonArrayData.hpp"
 #include "JsonObjectData.hpp"
 #include "JsonVariant.hpp"
-#include "Numbers/isFloat.hpp"
-#include "Numbers/isInteger.hpp"
 #include "Numbers/parseFloat.hpp"
 #include "Numbers/parseInteger.hpp"
 
@@ -17,22 +15,32 @@
 
 namespace ArduinoJson {
 
-inline JsonVariant::JsonVariant(JsonArray array) {
-  if (!array.isNull()) {
-    _type = Internals::JSON_ARRAY;
-    _content.asArray = array._data;
-  } else {
-    _type = Internals::JSON_UNDEFINED;
-  }
+inline bool JsonVariant::set(const JsonArray& array) {
+  if (!_data) return false;
+  if (array._data)
+    _data->setArray(*array._data);
+  else
+    _data->setNull();
+  return true;
 }
 
-inline JsonVariant::JsonVariant(JsonObject object) {
-  if (!object.isNull()) {
-    _type = Internals::JSON_OBJECT;
-    _content.asObject = object._data;
-  } else {
-    _type = Internals::JSON_UNDEFINED;
-  }
+inline bool JsonVariant::set(const Internals::JsonArraySubscript& value) {
+  return set(value.as<JsonVariant>());
+}
+
+inline bool JsonVariant::set(const JsonObject& object) {
+  if (!_data) return false;
+  if (object._data)
+    _data->setObject(*object._data);
+  else
+    _data->setNull();
+  return true;
+}
+
+template <typename TString>
+inline bool JsonVariant::set(
+    const Internals::JsonObjectSubscript<TString>& value) {
+  return set(value.template as<JsonVariant>());
 }
 
 template <typename T>
@@ -41,7 +49,7 @@ inline typename Internals::enable_if<
                        JsonArray>::value,
     JsonArray>::type
 JsonVariant::as() const {
-  return variantAsArray();
+  return _data ? JsonArray(_buffer, _data->asArray()) : JsonArray();
 }
 
 template <typename T>
@@ -50,78 +58,6 @@ inline typename Internals::enable_if<
                        JsonObject>::value,
     T>::type
 JsonVariant::as() const {
-  return variantAsObject();
-}
-
-inline JsonArray JsonVariant::variantAsArray() const {
-  if (_type == Internals::JSON_ARRAY) return _content.asArray;
-  return JsonArray();
-}
-
-inline JsonObject JsonVariant::variantAsObject() const {
-  if (_type == Internals::JSON_OBJECT) return _content.asObject;
-  return JsonObject();
-}
-
-template <typename T>
-inline T JsonVariant::variantAsInteger() const {
-  using namespace Internals;
-  switch (_type) {
-    case JSON_UNDEFINED:
-    case JSON_UNPARSED:
-      return 0;
-    case JSON_POSITIVE_INTEGER:
-    case JSON_BOOLEAN:
-      return T(_content.asInteger);
-    case JSON_NEGATIVE_INTEGER:
-      return T(~_content.asInteger + 1);
-    case JSON_STRING:
-      return parseInteger<T>(_content.asString);
-    default:
-      return T(_content.asFloat);
-  }
-}
-
-inline const char *JsonVariant::variantAsString() const {
-  using namespace Internals;
-  return _type == JSON_STRING ? _content.asString : NULL;
+  return _data ? JsonObject(_buffer, _data->asObject()) : JsonObject();
 }
-
-template <typename T>
-inline T JsonVariant::variantAsFloat() const {
-  using namespace Internals;
-  switch (_type) {
-    case JSON_UNDEFINED:
-    case JSON_UNPARSED:
-      return 0;
-    case JSON_POSITIVE_INTEGER:
-    case JSON_BOOLEAN:
-      return static_cast<T>(_content.asInteger);
-    case JSON_NEGATIVE_INTEGER:
-      return -static_cast<T>(_content.asInteger);
-    case JSON_STRING:
-      return parseFloat<T>(_content.asString);
-    default:
-      return static_cast<T>(_content.asFloat);
-  }
-}
-
-inline bool JsonVariant::variantIsBoolean() const {
-  using namespace Internals;
-  return _type == JSON_BOOLEAN;
-}
-
-inline bool JsonVariant::variantIsInteger() const {
-  using namespace Internals;
-
-  return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER;
-}
-
-inline bool JsonVariant::variantIsFloat() const {
-  using namespace Internals;
-
-  return _type == JSON_FLOAT || _type == JSON_POSITIVE_INTEGER ||
-         _type == JSON_NEGATIVE_INTEGER;
-}
-
 }  // namespace ArduinoJson

+ 1 - 1
src/ArduinoJson/Memory/JsonBufferAllocated.hpp

@@ -16,7 +16,7 @@ class JsonBufferAllocated {
     return jsonBuffer->alloc(n);
   }
 
-  void operator delete(void *, JsonBuffer *)throw();
+  void operator delete(void *, JsonBuffer *)throw() {}
 };
 }  // namespace Internals
 }  // namespace ArduinoJson

+ 45 - 41
src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp

@@ -24,17 +24,17 @@ class MsgPackDeserializer {
         _stringStorage(stringStorage),
         _nestingLimit(nestingLimit) {}
 
-  DeserializationError parse(JsonVariant &variant) {
+  DeserializationError parse(JsonVariantData &variant) {
     uint8_t code;
     if (!readByte(code)) return DeserializationError::IncompleteInput;
 
     if ((code & 0x80) == 0) {
-      variant = code;
+      variant.setInteger(code);
       return DeserializationError::Ok;
     }
 
     if ((code & 0xe0) == 0xe0) {
-      variant = static_cast<int8_t>(code);
+      variant.setInteger(static_cast<int8_t>(code));
       return DeserializationError::Ok;
     }
 
@@ -48,15 +48,15 @@ class MsgPackDeserializer {
 
     switch (code) {
       case 0xc0:
-        variant = static_cast<char *>(0);
+        variant.setNull();
         return DeserializationError::Ok;
 
       case 0xc2:
-        variant = false;
+        variant.setBoolean(false);
         return DeserializationError::Ok;
 
       case 0xc3:
-        variant = true;
+        variant.setBoolean(true);
         return DeserializationError::Ok;
 
       case 0xcc:
@@ -171,54 +171,54 @@ class MsgPackDeserializer {
   }
 
   template <typename T>
-  DeserializationError readInteger(JsonVariant &variant) {
+  DeserializationError readInteger(JsonVariantData &variant) {
     T value;
     if (!readInteger(value)) return DeserializationError::IncompleteInput;
-    variant = value;
+    variant.setInteger(value);
     return DeserializationError::Ok;
   }
 
   template <typename T>
   typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat(
-      JsonVariant &variant) {
+      JsonVariantData &variant) {
     T value;
     if (!readBytes(value)) return DeserializationError::IncompleteInput;
     fixEndianess(value);
-    variant = value;
+    variant.setFloat(value);
     return DeserializationError::Ok;
   }
 
   template <typename T>
   typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble(
-      JsonVariant &variant) {
+      JsonVariantData &variant) {
     T value;
     if (!readBytes(value)) return DeserializationError::IncompleteInput;
     fixEndianess(value);
-    variant = value;
+    variant.setFloat(value);
     return DeserializationError::Ok;
   }
 
   template <typename T>
   typename enable_if<sizeof(T) == 4, DeserializationError>::type readDouble(
-      JsonVariant &variant) {
+      JsonVariantData &variant) {
     uint8_t i[8];  // input is 8 bytes
     T value;       // output is 4 bytes
     uint8_t *o = reinterpret_cast<uint8_t *>(&value);
     if (!readBytes(i, 8)) return DeserializationError::IncompleteInput;
     doubleToFloat(i, o);
     fixEndianess(value);
-    variant = value;
+    variant.setFloat(value);
     return DeserializationError::Ok;
   }
 
   template <typename T>
-  DeserializationError readString(JsonVariant &variant) {
+  DeserializationError readString(JsonVariantData &variant) {
     T size;
     if (!readInteger(size)) return DeserializationError::IncompleteInput;
     return readString(variant, size);
   }
 
-  DeserializationError readString(JsonVariant &variant, size_t n) {
+  DeserializationError readString(JsonVariantData &variant, size_t n) {
     typename remove_reference<TStringStorage>::type::String str =
         _stringStorage.startString();
     for (; n; --n) {
@@ -228,64 +228,68 @@ class MsgPackDeserializer {
     }
     const char *s = str.c_str();
     if (s == NULL) return DeserializationError::NoMemory;
-    variant = s;
+    variant.setString(s);
     return DeserializationError::Ok;
   }
 
   template <typename TSize>
-  DeserializationError readArray(JsonVariant &variant) {
+  DeserializationError readArray(JsonVariantData &variant) {
     TSize size;
     if (!readInteger(size)) return DeserializationError::IncompleteInput;
     return readArray(variant, size);
   }
 
-  DeserializationError readArray(JsonVariant &variant, size_t n) {
-    JsonArray array(_buffer);
-    if (array.isNull()) return DeserializationError::NoMemory;
-    variant = array;
-    return readArray(array, n);
+  DeserializationError readArray(JsonVariantData &variant, size_t n) {
+    JsonArrayData *array = new (_buffer) JsonArrayData;
+    if (!array) return DeserializationError::NoMemory;
+
+    variant.setArray(*array);
+    return readArray(*array, n);
   }
 
-  DeserializationError readArray(JsonArray array, size_t n) {
+  DeserializationError readArray(JsonArrayData &array, size_t n) {
     if (_nestingLimit == 0) return DeserializationError::TooDeep;
     --_nestingLimit;
     for (; n; --n) {
-      JsonVariant variant;
-      DeserializationError err = parse(variant);
+      JsonVariantData *value = array.addSlot(_buffer);
+      if (!value) return DeserializationError::NoMemory;
+
+      DeserializationError err = parse(*value);
       if (err) return err;
-      if (!array.add(variant)) return DeserializationError::NoMemory;
     }
     ++_nestingLimit;
     return DeserializationError::Ok;
   }
 
   template <typename TSize>
-  DeserializationError readObject(JsonVariant &variant) {
+  DeserializationError readObject(JsonVariantData &variant) {
     TSize size;
     if (!readInteger(size)) return DeserializationError::IncompleteInput;
     return readObject(variant, size);
   }
 
-  DeserializationError readObject(JsonVariant &variant, size_t n) {
-    JsonObject object(_buffer);
-    if (object.isNull()) return DeserializationError::NoMemory;
-    variant = object;
-    return readObject(object, n);
+  DeserializationError readObject(JsonVariantData &variant, size_t n) {
+    JsonObjectData *object = new (_buffer) JsonObjectData;
+    if (!object) return DeserializationError::NoMemory;
+    variant.setObject(*object);
+
+    return readObject(*object, n);
   }
 
-  DeserializationError readObject(JsonObject object, size_t n) {
+  DeserializationError readObject(JsonObjectData &object, size_t n) {
     if (_nestingLimit == 0) return DeserializationError::TooDeep;
     --_nestingLimit;
     for (; n; --n) {
-      DeserializationError err;
-      JsonVariant variant;
-      err = parse(variant);
+      JsonVariantData key;
+      DeserializationError err = parse(key);
       if (err) return err;
-      const char *key = variant.as<char *>();
-      if (!key) return DeserializationError::NotSupported;
-      err = parse(variant);
+      if (!key.isString()) return DeserializationError::NotSupported;
+
+      JsonVariantData *value = object.addSlot(_buffer, key.asString());
+      if (!value) return DeserializationError::NoMemory;
+
+      err = parse(*value);
       if (err) return err;
-      if (!object.set(key, variant)) return DeserializationError::NoMemory;
     }
     ++_nestingLimit;
     return DeserializationError::Ok;

+ 4 - 4
src/ArduinoJson/MsgPack/MsgPackSerializer.hpp

@@ -36,7 +36,7 @@ class MsgPackSerializer {
     }
   }
 
-  void acceptArray(const JsonArray& array) {
+  void acceptArray(const JsonArrayData& array) {
     size_t n = array.size();
     if (n < 0x10) {
       writeByte(uint8_t(0x90 + array.size()));
@@ -47,13 +47,13 @@ class MsgPackSerializer {
       writeByte(0xDD);
       writeInteger(uint32_t(n));
     }
-    for (JsonArray::const_iterator it = array.begin(); it != array.end();
+    for (JsonArrayData::const_iterator it = array.begin(); it != array.end();
          ++it) {
       it->visit(*this);
     }
   }
 
-  void acceptObject(const JsonObject& object) {
+  void acceptObject(const JsonObjectData& object) {
     size_t n = object.size();
     if (n < 0x10) {
       writeByte(uint8_t(0x80 + n));
@@ -64,7 +64,7 @@ class MsgPackSerializer {
       writeByte(0xDF);
       writeInteger(uint32_t(n));
     }
-    for (JsonObject::const_iterator it = object.begin(); it != object.end();
+    for (JsonObjectData::const_iterator it = object.begin(); it != object.end();
          ++it) {
       acceptString(it->key);
       it->value.visit(*this);

+ 1 - 0
src/ArduinoJson/Polyfills/type_traits/is_integral.hpp

@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include "../../Configuration.hpp"
 #include "is_same.hpp"
 
 namespace ArduinoJson {

+ 27 - 12
src/ArduinoJson/StaticJsonDocument.hpp

@@ -9,11 +9,8 @@
 
 namespace ArduinoJson {
 
-template <size_t CAPACITY = sizeof(JsonVariant)>
+template <size_t CAPACITY>
 class StaticJsonDocument {
-  Internals::StaticJsonBuffer<CAPACITY> _buffer;
-  JsonVariant _root;
-
  public:
   uint8_t nestingLimit;
 
@@ -25,12 +22,12 @@ class StaticJsonDocument {
 
   template <typename T>
   bool is() const {
-    return _root.is<T>();
+    return getVariant().template is<T>();
   }
 
   template <typename T>
   typename Internals::JsonVariantAs<T>::type as() const {
-    return _root.as<T>();
+    return getVariant().template as<T>();
   }
 
   // JsonObject to<JsonObject>()
@@ -40,7 +37,7 @@ class StaticJsonDocument {
   to() {
     clear();
     JsonObject object(&_buffer);
-    _root = object;
+    getVariant().set(object);
     return object;
   }
 
@@ -51,22 +48,32 @@ class StaticJsonDocument {
   to() {
     clear();
     JsonArray array(&_buffer);
-    _root = array;
+    getVariant().set(array);
     return array;
   }
 
   // JsonVariant to<JsonVariant>()
   template <typename T>
   typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
-                                T&>::type
+                                JsonVariant>::type
   to() {
     clear();
-    return _root;
+    return getVariant();
+  }
+
+  // JsonVariantData& to<JsonVariantData>()
+  template <typename T>
+  typename Internals::enable_if<
+      Internals::is_same<T, Internals::JsonVariantData>::value,
+      Internals::JsonVariantData&>::type
+  to() {
+    clear();
+    return _rootData;
   }
 
   void clear() {
     _buffer.clear();
-    _root = JsonVariant();
+    _rootData.setNull();
   }
 
   size_t memoryUsage() const {
@@ -75,8 +82,16 @@ class StaticJsonDocument {
 
   template <typename Visitor>
   void visit(Visitor& visitor) const {
-    return _root.visit(visitor);
+    return getVariant().visit(visitor);
+  }
+
+ private:
+  JsonVariant getVariant() const {
+    return JsonVariant(&_buffer, &_rootData);
   }
+
+  mutable Internals::StaticJsonBuffer<CAPACITY> _buffer;
+  mutable Internals::JsonVariantData _rootData;
 };
 
 }  // namespace ArduinoJson

+ 2 - 0
src/ArduinoJson/Strings/FixedSizeRamString.hpp

@@ -4,6 +4,8 @@
 
 #pragma once
 
+#include <string.h>  // strcmp
+
 namespace ArduinoJson {
 namespace Internals {
 

+ 1 - 0
src/ArduinoJson/Strings/StlString.hpp

@@ -26,6 +26,7 @@ class StlString {
   }
 
   bool equals(const char* expected) const {
+    if (!expected) return false;
     return *_str == expected;
   }
 

+ 1 - 0
test/CMakeLists.txt

@@ -68,6 +68,7 @@ add_subdirectory(DynamicJsonBuffer)
 add_subdirectory(IntegrationTests)
 add_subdirectory(JsonArray)
 add_subdirectory(JsonDeserializer)
+add_subdirectory(JsonDocument)
 add_subdirectory(JsonObject)
 add_subdirectory(JsonSerializer)
 add_subdirectory(JsonVariant)

+ 0 - 4
test/JsonArray/iterator.cpp

@@ -30,8 +30,4 @@ TEST_CASE("JsonArray::begin()/end()") {
   SECTION("Mutable") {
     run_iterator_test<JsonArray::iterator>();
   }
-
-  SECTION("Const") {
-    run_iterator_test<JsonArray::const_iterator>();
-  }
 }

+ 11 - 0
test/JsonDocument/CMakeLists.txt

@@ -0,0 +1,11 @@
+# ArduinoJson - arduinojson.org
+# Copyright Benoit Blanchon 2014-2018
+# MIT License
+
+add_executable(JsonDocumentTests
+	DynamicJsonDocument.cpp
+	StaticJsonDocument.cpp
+)
+
+target_link_libraries(JsonDocumentTests catch)
+add_test(JsonDocument JsonDocumentTests)

+ 20 - 0
test/JsonDocument/DynamicJsonDocument.cpp

@@ -0,0 +1,20 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#include <ArduinoJson.h>
+#include <catch.hpp>
+
+TEST_CASE("DynamicJsonDocument") {
+  DynamicJsonDocument doc;
+
+  SECTION("serializeJson()") {
+    JsonObject obj = doc.to<JsonObject>();
+    obj["hello"] = "world";
+
+    std::string json;
+    serializeJson(doc, json);
+
+    REQUIRE(json == "{\"hello\":\"world\"}");
+  }
+}

+ 20 - 0
test/JsonDocument/StaticJsonDocument.cpp

@@ -0,0 +1,20 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#include <ArduinoJson.h>
+#include <catch.hpp>
+
+TEST_CASE("StaticJsonDocument") {
+  StaticJsonDocument<200> doc;
+
+  SECTION("serializeJson()") {
+    JsonObject obj = doc.to<JsonObject>();
+    obj["hello"] = "world";
+
+    std::string json;
+    serializeJson(doc, json);
+
+    REQUIRE(json == "{\"hello\":\"world\"}");
+  }
+}

+ 17 - 25
test/JsonObject/iterator.cpp

@@ -16,36 +16,28 @@ TEST_CASE("JsonObject::begin()/end()") {
   SECTION("NonConstIterator") {
     JsonObject::iterator it = obj.begin();
     REQUIRE(obj.end() != it);
-    REQUIRE_THAT(it->key, Equals("ab"));
-    REQUIRE(12 == it->value);
-    it->key = "a.b";
-    it->value = 1.2;
+    REQUIRE_THAT(it->key(), Equals("ab"));
+    REQUIRE(12 == it->value());
     ++it;
     REQUIRE(obj.end() != it);
-    REQUIRE_THAT(it->key, Equals("cd"));
-    REQUIRE(34 == it->value);
-    it->key = "c.d";
-    it->value = 3.4;
+    REQUIRE_THAT(it->key(), Equals("cd"));
+    REQUIRE(34 == it->value());
     ++it;
     REQUIRE(obj.end() == it);
-
-    REQUIRE(2 == obj.size());
-    REQUIRE(1.2 == obj["a.b"]);
-    REQUIRE(3.4 == obj["c.d"]);
   }
 
-  SECTION("ConstIterator") {
-    const JsonObject const_object = obj;
-    JsonObject::const_iterator it = const_object.begin();
+  // SECTION("ConstIterator") {
+  //   const JsonObject const_object = obj;
+  //   JsonObject::iterator it = const_object.begin();
 
-    REQUIRE(const_object.end() != it);
-    REQUIRE_THAT(it->key, Equals("ab"));
-    REQUIRE(12 == it->value);
-    ++it;
-    REQUIRE(const_object.end() != it);
-    REQUIRE_THAT(it->key, Equals("cd"));
-    REQUIRE(34 == it->value);
-    ++it;
-    REQUIRE(const_object.end() == it);
-  }
+  //   REQUIRE(const_object.end() != it);
+  //   REQUIRE_THAT(it->key(), Equals("ab"));
+  //   REQUIRE(12 == it->value());
+  //   ++it;
+  //   REQUIRE(const_object.end() != it);
+  //   REQUIRE_THAT(it->key(), Equals("cd"));
+  //   REQUIRE(34 == it->value());
+  //   ++it;
+  //   REQUIRE(const_object.end() == it);
+  // }
 }

+ 1 - 1
test/JsonObject/remove.cpp

@@ -32,7 +32,7 @@ TEST_CASE("JsonObject::remove()") {
     obj["c"] = 2;
 
     for (JsonObject::iterator it = obj.begin(); it != obj.end(); ++it) {
-      if (it->value == 1) obj.remove(it);
+      if (it->value() == 1) obj.remove(it);
     }
 
     std::string result;

+ 18 - 3
test/JsonSerializer/JsonVariant.cpp

@@ -6,9 +6,12 @@
 #include <catch.hpp>
 #include <limits>
 
-void check(JsonVariant variant, const std::string &expected) {
+template <typename T>
+void check(T value, const std::string &expected) {
+  DynamicJsonDocument doc;
+  doc.to<JsonVariant>().set(value);
   char buffer[256] = "";
-  size_t returnValue = serializeJson(variant, buffer, sizeof(buffer));
+  size_t returnValue = serializeJson(doc, buffer, sizeof(buffer));
   REQUIRE(expected == buffer);
   REQUIRE(expected.size() == returnValue);
 }
@@ -22,10 +25,22 @@ TEST_CASE("serializeJson(JsonVariant)") {
     check(static_cast<char *>(0), "null");
   }
 
-  SECTION("String") {
+  SECTION("const char*") {
     check("hello", "\"hello\"");
   }
 
+  SECTION("string") {
+    check(std::string("hello"), "\"hello\"");
+  }
+
+  SECTION("SerializedValue<const char*>") {
+    check(serialized("[1,2]"), "[1,2]");
+  }
+
+  SECTION("SerializedValue<std::string>") {
+    check(serialized(std::string("[1,2]")), "[1,2]");
+  }
+
   SECTION("Double") {
     check(3.1415927, "3.1415927");
   }

+ 4 - 2
test/JsonSerializer/std_stream.cpp

@@ -11,16 +11,18 @@ TEST_CASE("operator<<(std::ostream)") {
   std::ostringstream os;
 
   SECTION("JsonVariant containing false") {
-    JsonVariant variant = false;
+    JsonVariant variant = doc.to<JsonVariant>();
 
+    variant.set(false);
     os << variant;
 
     REQUIRE("false" == os.str());
   }
 
   SECTION("JsonVariant containing string") {
-    JsonVariant variant = "coucou";
+    JsonVariant variant = doc.to<JsonVariant>();
 
+    variant.set("coucou");
     os << variant;
 
     REQUIRE("\"coucou\"" == os.str());

+ 0 - 1
test/JsonVariant/CMakeLists.txt

@@ -5,7 +5,6 @@
 add_executable(JsonVariantTests
 	as.cpp
 	compare.cpp
-	copy.cpp
 	is.cpp
 	isnull.cpp
 	or.cpp

+ 51 - 48
test/JsonVariant/as.cpp

@@ -9,222 +9,225 @@
 static const char* null = 0;
 
 TEST_CASE("JsonVariant::as()") {
+  DynamicJsonDocument doc;
+  JsonVariant variant = doc.to<JsonVariant>();
+
   SECTION("DoubleAsBool") {
-    JsonVariant variant = 4.2;
+    variant.set(4.2);
     REQUIRE(variant.as<bool>());
   }
 
   SECTION("DoubleAsCstr") {
-    JsonVariant variant = 4.2;
+    variant.set(4.2);
     REQUIRE_FALSE(variant.as<const char*>());
   }
 
   SECTION("DoubleAsString") {
-    JsonVariant variant = 4.2;
+    variant.set(4.2);
     REQUIRE(std::string("4.2") == variant.as<std::string>());
   }
 
   SECTION("DoubleAsLong") {
-    JsonVariant variant = 4.2;
+    variant.set(4.2);
     REQUIRE(4L == variant.as<long>());
   }
 
   SECTION("DoubleAsUnsigned") {
-    JsonVariant variant = 4.2;
+    variant.set(4.2);
     REQUIRE(4U == variant.as<unsigned>());
   }
 
   SECTION("DoubleZeroAsBool") {
-    JsonVariant variant = 0.0;
+    variant.set(0.0);
     REQUIRE_FALSE(variant.as<bool>());
   }
 
   SECTION("DoubleZeroAsLong") {
-    JsonVariant variant = 0.0;
+    variant.set(0.0);
     REQUIRE(0L == variant.as<long>());
   }
 
   SECTION("FalseAsBool") {
-    JsonVariant variant = false;
+    variant.set(false);
     REQUIRE_FALSE(variant.as<bool>());
   }
 
   SECTION("FalseAsDouble") {
-    JsonVariant variant = false;
+    variant.set(false);
     REQUIRE(0.0 == variant.as<double>());
   }
 
   SECTION("FalseAsLong") {
-    JsonVariant variant = false;
+    variant.set(false);
     REQUIRE(0L == variant.as<long>());
   }
 
   SECTION("FalseAsString") {
-    JsonVariant variant = false;
+    variant.set(false);
     REQUIRE(std::string("false") == variant.as<std::string>());
   }
 
   SECTION("TrueAsBool") {
-    JsonVariant variant = true;
+    variant.set(true);
     REQUIRE(variant.as<bool>());
   }
 
   SECTION("TrueAsDouble") {
-    JsonVariant variant = true;
+    variant.set(true);
     REQUIRE(1.0 == variant.as<double>());
   }
 
   SECTION("TrueAsLong") {
-    JsonVariant variant = true;
+    variant.set(true);
     REQUIRE(1L == variant.as<long>());
   }
 
   SECTION("TrueAsString") {
-    JsonVariant variant = true;
+    variant.set(true);
     REQUIRE(std::string("true") == variant.as<std::string>());
   }
 
   SECTION("LongAsBool") {
-    JsonVariant variant = 42L;
+    variant.set(42L);
     REQUIRE(variant.as<bool>());
   }
 
   SECTION("LongZeroAsBool") {
-    JsonVariant variant = 0L;
+    variant.set(0L);
     REQUIRE_FALSE(variant.as<bool>());
   }
 
   SECTION("PositiveLongAsDouble") {
-    JsonVariant variant = 42L;
+    variant.set(42L);
     REQUIRE(42.0 == variant.as<double>());
   }
 
   SECTION("NegativeLongAsDouble") {
-    JsonVariant variant = -42L;
+    variant.set(-42L);
     REQUIRE(-42.0 == variant.as<double>());
   }
 
   SECTION("LongAsString") {
-    JsonVariant variant = 42L;
+    variant.set(42L);
     REQUIRE(std::string("42") == variant.as<std::string>());
   }
 
   SECTION("LongZeroAsDouble") {
-    JsonVariant variant = 0L;
+    variant.set(0L);
     REQUIRE(0.0 == variant.as<double>());
   }
 
   SECTION("NullAsBool") {
-    JsonVariant variant = null;
+    variant.set(null);
     REQUIRE_FALSE(variant.as<bool>());
   }
 
   SECTION("NullAsDouble") {
-    JsonVariant variant = null;
+    variant.set(null);
     REQUIRE(0.0 == variant.as<double>());
   }
 
   SECTION("NullAsLong") {
-    JsonVariant variant = null;
+    variant.set(null);
     REQUIRE(0L == variant.as<long>());
   }
 
   SECTION("NullAsString") {
-    JsonVariant variant = null;
+    variant.set(null);
     REQUIRE(std::string("null") == variant.as<std::string>());
   }
 
   SECTION("NumberStringAsBool") {
-    JsonVariant variant = "42";
+    variant.set("42");
     REQUIRE(variant.as<bool>());
   }
 
   SECTION("NumberStringAsLong") {
-    JsonVariant variant = "42";
+    variant.set("42");
     REQUIRE(42L == variant.as<long>());
   }
 
 #if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
   SECTION("NumberStringAsInt64Negative") {
-    JsonVariant variant = "-9223372036854775808";
+    variant.set("-9223372036854775808");
     REQUIRE(-9223372036854775807 - 1 == variant.as<long long>());
   }
 
   SECTION("NumberStringAsInt64Positive") {
-    JsonVariant variant = "9223372036854775807";
+    variant.set("9223372036854775807");
     REQUIRE(9223372036854775807 == variant.as<long long>());
   }
 #endif
 
   SECTION("RandomStringAsBool") {
-    JsonVariant variant = "hello";
+    variant.set("hello");
     REQUIRE_FALSE(variant.as<bool>());
   }
 
   SECTION("RandomStringAsLong") {
-    JsonVariant variant = "hello";
+    variant.set("hello");
     REQUIRE(0L == variant.as<long>());
   }
 
   SECTION("RandomStringAsConstCharPtr") {
-    JsonVariant variant = "hello";
+    variant.set("hello");
     REQUIRE(std::string("hello") == variant.as<const char*>());
   }
 
   SECTION("RandomStringAsCharPtr") {
-    JsonVariant variant = "hello";
+    variant.set("hello");
     REQUIRE(std::string("hello") == variant.as<char*>());
   }
 
   SECTION("RandomStringAsString") {
-    JsonVariant variant = "hello";
+    variant.set("hello");
     REQUIRE(std::string("hello") == variant.as<std::string>());
   }
 
   SECTION("TrueStringAsBool") {
-    JsonVariant variant = "true";
+    variant.set("true");
     REQUIRE(variant.as<bool>());
   }
 
   SECTION("TrueStringAsLong") {
-    JsonVariant variant = "true";
+    variant.set("true");
     REQUIRE(1L == variant.as<long>());
   }
 
   SECTION("ObjectAsString") {
-    DynamicJsonDocument doc;
-    JsonObject obj = doc.to<JsonObject>();
+    DynamicJsonDocument doc2;
+    JsonObject obj = doc2.to<JsonObject>();
 
     obj["key"] = "value";
 
-    JsonVariant variant = obj;
+    variant.set(obj);
     REQUIRE(std::string("{\"key\":\"value\"}") == variant.as<std::string>());
   }
 
   SECTION("ArrayAsString") {
-    DynamicJsonDocument doc;
-    JsonArray arr = doc.to<JsonArray>();
+    DynamicJsonDocument doc2;
+    JsonArray arr = doc2.to<JsonArray>();
     arr.add(4);
     arr.add(2);
 
-    JsonVariant variant = arr;
+    variant.set(arr);
     REQUIRE(std::string("[4,2]") == variant.as<std::string>());
   }
 
   SECTION("ArrayAsJsonArray") {
-    DynamicJsonDocument doc;
-    JsonArray arr = doc.to<JsonArray>();
+    DynamicJsonDocument doc2;
+    JsonArray arr = doc2.to<JsonArray>();
 
-    JsonVariant variant = arr;
+    variant.set(arr);
     REQUIRE(arr == variant.as<JsonArray>());
     REQUIRE(arr == variant.as<JsonArray>());  // <- shorthand
   }
 
   SECTION("ObjectAsJsonObject") {
-    DynamicJsonDocument doc;
-    JsonObject obj = doc.to<JsonObject>();
+    DynamicJsonDocument doc2;
+    JsonObject obj = doc2.to<JsonObject>();
 
-    JsonVariant variant = obj;
+    variant.set(obj);
     REQUIRE(obj == variant.as<JsonObject>());
     REQUIRE(obj == variant.as<JsonObject>());  // <- shorthand
   }

+ 99 - 80
test/JsonVariant/compare.cpp

@@ -8,46 +8,58 @@
 static const char* null = 0;
 
 template <typename T>
-void checkEquals(JsonVariant a, T b) {
-  REQUIRE(b == a);
-  REQUIRE(a == b);
-  REQUIRE(b <= a);
-  REQUIRE(a <= b);
-  REQUIRE(b >= a);
-  REQUIRE(a >= b);
-
-  REQUIRE_FALSE(b != a);
-  REQUIRE_FALSE(a != b);
-  REQUIRE_FALSE(b > a);
-  REQUIRE_FALSE(a > b);
-  REQUIRE_FALSE(b < a);
-  REQUIRE_FALSE(a < b);
+void checkEquals(T a, T b) {
+  DynamicJsonDocument doc;
+  JsonVariant variant = doc.to<JsonVariant>();
+  variant.set(a);
+
+  REQUIRE(b == variant);
+  REQUIRE(variant == b);
+  REQUIRE(b <= variant);
+  REQUIRE(variant <= b);
+  REQUIRE(b >= variant);
+  REQUIRE(variant >= b);
+
+  REQUIRE_FALSE(b != variant);
+  REQUIRE_FALSE(variant != b);
+  REQUIRE_FALSE(b > variant);
+  REQUIRE_FALSE(variant > b);
+  REQUIRE_FALSE(b < variant);
+  REQUIRE_FALSE(variant < b);
 }
 
 template <typename T>
-void checkGreater(JsonVariant a, T b) {
-  REQUIRE(a > b);
-  REQUIRE(b < a);
-  REQUIRE(a != b);
-  REQUIRE(b != a);
-
-  REQUIRE_FALSE(a < b);
-  REQUIRE_FALSE(b > a);
-  REQUIRE_FALSE(a == b);
-  REQUIRE_FALSE(b == a);
+void checkGreater(T a, T b) {
+  DynamicJsonDocument doc;
+  JsonVariant variant = doc.to<JsonVariant>();
+  variant.set(a);
+
+  REQUIRE(variant > b);
+  REQUIRE(b < variant);
+  REQUIRE(variant != b);
+  REQUIRE(b != variant);
+
+  REQUIRE_FALSE(variant < b);
+  REQUIRE_FALSE(b > variant);
+  REQUIRE_FALSE(variant == b);
+  REQUIRE_FALSE(b == variant);
 }
 
 template <typename T>
-void checkLower(JsonVariant a, T b) {
-  REQUIRE(a < b);
-  REQUIRE(b > a);
-  REQUIRE(a != b);
-  REQUIRE(b != a);
-
-  REQUIRE_FALSE(a > b);
-  REQUIRE_FALSE(b < a);
-  REQUIRE_FALSE(a == b);
-  REQUIRE_FALSE(b == a);
+void checkLower(T a, T b) {
+  DynamicJsonDocument doc;
+  JsonVariant variant = doc.to<JsonVariant>();
+  variant.set(a);
+
+  REQUIRE(variant < b);
+  REQUIRE(b > variant);
+  REQUIRE(variant != b);
+  REQUIRE(b != variant);
+
+  REQUIRE_FALSE(variant > b);
+  REQUIRE_FALSE(b < variant);
+  REQUIRE_FALSE(variant == b);
+  REQUIRE_FALSE(b == variant);
 }
 
 template <typename T>
@@ -99,7 +111,9 @@ TEST_CASE("JsonVariant comparisons") {
   }
 
   SECTION("null") {
-    JsonVariant variant = null;
+    DynamicJsonDocument doc;
+    JsonVariant variant = doc.to<JsonVariant>();
+    variant.set(null);
 
     REQUIRE(variant == variant);
     REQUIRE_FALSE(variant != variant);
@@ -139,7 +153,9 @@ TEST_CASE("JsonVariant comparisons") {
   }
 
   SECTION("String") {
-    JsonVariant variant = "hello";
+    DynamicJsonDocument doc;
+    JsonVariant variant = doc.to<JsonVariant>();
+    variant.set("hello");
 
     REQUIRE(variant == variant);
     REQUIRE_FALSE(variant != variant);
@@ -163,10 +179,15 @@ TEST_CASE("JsonVariant comparisons") {
     REQUIRE_FALSE(null == variant);
   }
 
+  DynamicJsonDocument doc1, doc2, doc3;
+  JsonVariant variant1 = doc1.to<JsonVariant>();
+  JsonVariant variant2 = doc2.to<JsonVariant>();
+  JsonVariant variant3 = doc3.to<JsonVariant>();
+
   SECTION("IntegerInVariant") {
-    JsonVariant variant1 = 42;
-    JsonVariant variant2 = 42;
-    JsonVariant variant3 = 666;
+    variant1.set(42);
+    variant2.set(42);
+    variant3.set(666);
 
     REQUIRE(variant1 == variant2);
     REQUIRE_FALSE(variant1 != variant2);
@@ -176,9 +197,9 @@ TEST_CASE("JsonVariant comparisons") {
   }
 
   SECTION("StringInVariant") {
-    JsonVariant variant1 = "0hello" + 1;  // make sure they have
-    JsonVariant variant2 = "1hello" + 1;  // different addresses
-    JsonVariant variant3 = "world";
+    variant1.set("0hello" + 1);  // make sure they have
+    variant2.set("1hello" + 1);  // different addresses
+    variant3.set("world");
 
     REQUIRE(variant1 == variant2);
     REQUIRE_FALSE(variant1 != variant2);
@@ -188,9 +209,9 @@ TEST_CASE("JsonVariant comparisons") {
   }
 
   SECTION("DoubleInVariant") {
-    JsonVariant variant1 = 42.0;
-    JsonVariant variant2 = 42.0;
-    JsonVariant variant3 = 666.0;
+    variant1.set(42.0);
+    variant2.set(42.0);
+    variant3.set(666.0);
 
     REQUIRE(variant1 == variant2);
     REQUIRE_FALSE(variant1 != variant2);
@@ -200,9 +221,9 @@ TEST_CASE("JsonVariant comparisons") {
   }
 
   SECTION("BoolInVariant") {
-    JsonVariant variant1 = true;
-    JsonVariant variant2 = true;
-    JsonVariant variant3 = false;
+    variant1.set(true);
+    variant2.set(true);
+    variant3.set(false);
 
     REQUIRE(variant1 == variant2);
     REQUIRE_FALSE(variant1 != variant2);
@@ -212,14 +233,13 @@ TEST_CASE("JsonVariant comparisons") {
   }
 
   SECTION("ArrayInVariant") {
-    DynamicJsonDocument doc1;
-    JsonArray array1 = doc1.to<JsonArray>();
-    DynamicJsonDocument doc2;
-    JsonArray array2 = doc2.to<JsonArray>();
+    DynamicJsonDocument docArr1, docArr2;
+    JsonArray array1 = docArr1.to<JsonArray>();
+    JsonArray array2 = docArr2.to<JsonArray>();
 
-    JsonVariant variant1 = array1;
-    JsonVariant variant2 = array1;
-    JsonVariant variant3 = array2;
+    variant1.set(array1);
+    variant2.set(array1);
+    variant3.set(array2);
 
     REQUIRE(variant1 == variant2);
     REQUIRE_FALSE(variant1 != variant2);
@@ -229,14 +249,13 @@ TEST_CASE("JsonVariant comparisons") {
   }
 
   SECTION("ObjectInVariant") {
-    DynamicJsonDocument doc1;
-    JsonObject obj1 = doc1.to<JsonObject>();
-    DynamicJsonDocument doc2;
-    JsonObject obj2 = doc2.to<JsonObject>();
+    DynamicJsonDocument docObj1, docObj2;
+    JsonObject obj1 = docObj1.to<JsonObject>();
+    JsonObject obj2 = docObj2.to<JsonObject>();
 
-    JsonVariant variant1 = obj1;
-    JsonVariant variant2 = obj1;
-    JsonVariant variant3 = obj2;
+    variant1.set(obj1);
+    variant2.set(obj1);
+    variant3.set(obj2);
 
     REQUIRE(variant1 == variant2);
     REQUIRE_FALSE(variant1 != variant2);
@@ -245,22 +264,22 @@ TEST_CASE("JsonVariant comparisons") {
     REQUIRE_FALSE(variant1 == variant3);
   }
 
-  SECTION("VariantsOfDifferentTypes") {
-    DynamicJsonDocument doc1;
-    JsonObject obj = doc1.to<JsonObject>();
-
-    DynamicJsonDocument doc2;
-    JsonArray arr = doc2.to<JsonArray>();
-    JsonVariant variants[] = {
-        true, 42, 666.667, "hello", arr, obj,
-    };
-    size_t n = sizeof(variants) / sizeof(variants[0]);
-
-    for (size_t i = 0; i < n; i++) {
-      for (size_t j = i + 1; j < n; j++) {
-        REQUIRE(variants[i] != variants[j]);
-        REQUIRE_FALSE(variants[i] == variants[j]);
-      }
-    }
-  }
+  // SECTION("VariantsOfDifferentTypes") {
+  //   DynamicJsonDocument doc1;
+  //   JsonObject obj = doc1.to<JsonObject>();
+
+  //   DynamicJsonDocument doc2;
+  //   JsonArray arr = doc2.to<JsonArray>();
+  //   JsonVariant variants[] = {
+  //       true, 42, 666.667, "hello", arr, obj,
+  //   };
+  //   size_t n = sizeof(variants) / sizeof(variants[0]);
+
+  //   for (size_t i = 0; i < n; i++) {
+  //     for (size_t j = i + 1; j < n; j++) {
+  //       REQUIRE(variants[i] != variants[j]);
+  //       REQUIRE_FALSE(variants[i] == variants[j]);
+  //     }
+  //   }
+  // }
 }

+ 0 - 65
test/JsonVariant/copy.cpp

@@ -1,65 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2018
-// MIT License
-
-#include <ArduinoJson.h>
-#include <catch.hpp>
-
-TEST_CASE("JsonVariant copy") {
-  JsonVariant _variant1;
-  JsonVariant _variant2;
-
-  SECTION("IntegersAreCopiedByValue") {
-    _variant1 = 123;
-    _variant2 = _variant1;
-    _variant1 = 456;
-
-    REQUIRE(123 == _variant2.as<int>());
-  }
-
-  SECTION("DoublesAreCopiedByValue") {
-    _variant1 = 123.45;
-    _variant2 = _variant1;
-    _variant1 = 456.78;
-
-    REQUIRE(123.45 == _variant2.as<double>());
-  }
-
-  SECTION("BooleansAreCopiedByValue") {
-    _variant1 = true;
-    _variant2 = _variant1;
-    _variant1 = false;
-
-    REQUIRE(_variant2.as<bool>());
-  }
-
-  SECTION("StringsAreCopiedByValue") {
-    _variant1 = "hello";
-    _variant2 = _variant1;
-    _variant1 = "world";
-
-    REQUIRE(std::string("hello") == _variant2.as<const char*>());
-  }
-
-  SECTION("ObjectsAreCopiedByReference") {
-    DynamicJsonDocument doc;
-    JsonObject object = doc.to<JsonObject>();
-
-    _variant1 = object;
-
-    object["hello"] = "world";
-
-    REQUIRE(1 == _variant1.as<JsonObject>().size());
-  }
-
-  SECTION("ArraysAreCopiedByReference") {
-    DynamicJsonDocument doc;
-    JsonArray array = doc.to<JsonArray>();
-
-    _variant1 = array;
-
-    array.add("world");
-
-    REQUIRE(1 == _variant1.as<JsonArray>().size());
-  }
-}

+ 31 - 10
test/JsonVariant/is.cpp

@@ -5,7 +5,11 @@
 #include <ArduinoJson.h>
 #include <catch.hpp>
 
-void checkIsArray(JsonVariant var) {
+void checkIsArray(JsonArray value) {
+  DynamicJsonDocument doc;
+  JsonVariant var = doc.to<JsonVariant>();
+  var.set(value);
+
   REQUIRE(var.is<JsonArray>());
   REQUIRE(var.is<JsonArray>());
   REQUIRE(var.is<const JsonArray>());
@@ -16,48 +20,65 @@ void checkIsArray(JsonVariant var) {
   REQUIRE_FALSE(var.is<float>());
   REQUIRE_FALSE(var.is<int>());
   REQUIRE_FALSE(var.is<long>());
-  REQUIRE_FALSE(var.is<const char*>());
+  REQUIRE_FALSE(var.is<const char *>());
   REQUIRE_FALSE(var.is<JsonObject>());
 }
 
-void checkIsBool(JsonVariant var) {
+void checkIsBool(bool value) {
+  DynamicJsonDocument doc;
+  JsonVariant var = doc.to<JsonVariant>();
+  var.set(value);
+
   REQUIRE(var.is<bool>());
 
   REQUIRE_FALSE(var.is<double>());
   REQUIRE_FALSE(var.is<float>());
   REQUIRE_FALSE(var.is<int>());
   REQUIRE_FALSE(var.is<long>());
-  REQUIRE_FALSE(var.is<const char*>());
+  REQUIRE_FALSE(var.is<const char *>());
   REQUIRE_FALSE(var.is<JsonArray>());
   REQUIRE_FALSE(var.is<JsonObject>());
 }
 
-void checkIsFloat(JsonVariant var) {
+void checkIsFloat(double value) {
+  DynamicJsonDocument doc;
+  JsonVariant var = doc.to<JsonVariant>();
+  var.set(value);
+
   REQUIRE(var.is<double>());
   REQUIRE(var.is<float>());
 
   REQUIRE_FALSE(var.is<bool>());
   REQUIRE_FALSE(var.is<int>());
   REQUIRE_FALSE(var.is<long>());
-  REQUIRE_FALSE(var.is<const char*>());
+  REQUIRE_FALSE(var.is<const char *>());
   REQUIRE_FALSE(var.is<JsonArray>());
   REQUIRE_FALSE(var.is<JsonObject>());
 }
 
-void checkIsInteger(JsonVariant var) {
+template <typename T>
+void checkIsInteger(T value) {
+  DynamicJsonDocument doc;
+  JsonVariant var = doc.to<JsonVariant>();
+  var.set(value);
+
   REQUIRE(var.is<long>());
   REQUIRE(var.is<int>());
   REQUIRE(var.is<float>());
   REQUIRE(var.is<double>());
 
   REQUIRE_FALSE(var.is<bool>());
-  REQUIRE_FALSE(var.is<const char*>());
+  REQUIRE_FALSE(var.is<const char *>());
   REQUIRE_FALSE(var.is<JsonArray>());
   REQUIRE_FALSE(var.is<JsonObject>());
 }
 
-void checkIsString(JsonVariant var) {
-  REQUIRE(var.is<const char*>());
+void checkIsString(const char *value) {
+  DynamicJsonDocument doc;
+  JsonVariant var = doc.to<JsonVariant>();
+  var.set(value);
+
+  REQUIRE(var.is<const char *>());
 
   REQUIRE_FALSE(var.is<bool>());
   REQUIRE_FALSE(var.is<int>());

+ 19 - 16
test/JsonVariant/isnull.cpp

@@ -6,39 +6,42 @@
 #include <catch.hpp>
 
 TEST_CASE("JsonVariant::isNull()") {
-  SECTION("ReturnsFalse_WhenUndefined") {
-    JsonVariant variant;
+  DynamicJsonDocument doc;
+  JsonVariant variant = doc.to<JsonVariant>();
+
+  SECTION("return true when Undefined") {
     REQUIRE(variant.isNull() == true);
   }
 
-  SECTION("ReturnsTrue_WhenInteger") {
-    JsonVariant variant = 0;
+  SECTION("return false when Integer") {
+    variant.set(42);
+
     REQUIRE(variant.isNull() == false);
   }
 
-  SECTION("ReturnsTrue_WhenEmptyArray") {
-    DynamicJsonDocument doc;
-    JsonArray array = doc.to<JsonArray>();
+  SECTION("return false when EmptyArray") {
+    DynamicJsonDocument doc2;
+    JsonArray array = doc2.to<JsonArray>();
 
-    JsonVariant variant = array;
+    variant.set(array);
     REQUIRE(variant.isNull() == false);
   }
 
-  SECTION("ReturnsTrue_WhenEmptyObject") {
-    DynamicJsonDocument doc;
-    JsonObject obj = doc.to<JsonObject>();
+  SECTION("return false when EmptyObject") {
+    DynamicJsonDocument doc2;
+    JsonObject obj = doc2.to<JsonObject>();
 
-    JsonVariant variant = obj;
+    variant.set(obj);
     REQUIRE(variant.isNull() == false);
   }
 
-  SECTION("ReturnsFalse_WhenInvalidArray") {
-    JsonVariant variant = JsonArray();
+  SECTION("return true when InvalidArray") {
+    variant.set(JsonArray());
     REQUIRE(variant.isNull() == true);
   }
 
-  SECTION("ReturnsFalse_WhenInvalidObject") {
-    JsonVariant variant = JsonObject();
+  SECTION("return true when InvalidObject") {
+    variant.set(JsonObject());
     REQUIRE(variant.isNull() == true);
   }
 }

+ 38 - 32
test/JsonVariant/or.cpp

@@ -5,78 +5,84 @@
 #include <ArduinoJson.h>
 #include <catch.hpp>
 
-static const JsonVariant undefined;
-static const JsonVariant null = static_cast<const char*>(0);
-
 TEST_CASE("JsonVariant::operator|()") {
-  SECTION("undefined | const char*") {
-    std::string result = undefined | "default";
-    REQUIRE(result == "default");
-  }
+  DynamicJsonDocument doc;
+  JsonVariant variant = doc.to<JsonVariant>();
 
-  SECTION("undefined | int") {
-    int result = undefined | 42;
-    REQUIRE(result == 42);
-  }
+  SECTION("undefined") {
+    SECTION("undefined | const char*") {
+      std::string result = variant | "default";
+      REQUIRE(result == "default");
+    }
 
-  SECTION("undefined | bool") {
-    bool result = undefined | true;
-    REQUIRE(result == true);
-  }
+    SECTION("undefined | int") {
+      int result = variant | 42;
+      REQUIRE(result == 42);
+    }
 
-  SECTION("null | const char*") {
-    std::string result = null | "default";
-    REQUIRE(result == "default");
+    SECTION("undefined | bool") {
+      bool result = variant | true;
+      REQUIRE(result == true);
+    }
   }
 
-  SECTION("null | int") {
-    int result = null | 42;
-    REQUIRE(result == 42);
-  }
+  SECTION("null") {
+    variant.set(static_cast<const char*>(0));
 
-  SECTION("null | bool") {
-    bool result = null | true;
-    REQUIRE(result == true);
+    SECTION("null | const char*") {
+      std::string result = variant | "default";
+      REQUIRE(result == "default");
+    }
+
+    SECTION("null | int") {
+      int result = variant | 42;
+      REQUIRE(result == 42);
+    }
+
+    SECTION("null | bool") {
+      bool result = variant | true;
+      REQUIRE(result == true);
+    }
   }
 
   SECTION("int | const char*") {
-    JsonVariant variant = 42;
+    variant.set(42);
     std::string result = variant | "default";
     REQUIRE(result == "default");
   }
 
   SECTION("int | int") {
-    JsonVariant variant = 0;
+    variant.set(0);
     int result = variant | 666;
     REQUIRE(result == 0);
   }
 
   SECTION("double | int") {
-    JsonVariant variant = 42.0;
+    variant.set(42.0);
     int result = variant | 666;
     REQUIRE(result == 42);
   }
 
   SECTION("bool | bool") {
-    JsonVariant variant = false;
+    variant.set(false);
     bool result = variant | true;
     REQUIRE(result == false);
   }
 
   SECTION("int | bool") {
-    JsonVariant variant = 0;
+    variant.set(0);
     bool result = variant | true;
     REQUIRE(result == true);
   }
 
   SECTION("const char* | const char*") {
-    JsonVariant variant = "not default";
+    variant.set("not default");
     std::string result = variant | "default";
     REQUIRE(result == "not default");
   }
 
   SECTION("const char* | int") {
-    JsonVariant variant = "not default";
+    variant.set("not default");
     int result = variant | 42;
     REQUIRE(result == 42);
   }

+ 14 - 4
test/JsonVariant/set_get.cpp

@@ -9,7 +9,10 @@
 
 template <typename T>
 void checkValue(T expected) {
-  JsonVariant variant = expected;
+  DynamicJsonDocument doc;
+  JsonVariant variant = doc.to<JsonVariant>();
+
+  variant.set(expected);
   REQUIRE(expected == variant.as<T>());
 }
 
@@ -21,11 +24,15 @@ void checkReference(T &expected) {
 
 template <typename T>
 void checkNumericType() {
+  DynamicJsonDocument docMin, docMax;
+  JsonVariant variantMin = docMin.to<JsonVariant>();
+  JsonVariant variantMax = docMax.to<JsonVariant>();
+
   T min = std::numeric_limits<T>::min();
   T max = std::numeric_limits<T>::max();
 
-  JsonVariant variantMin(min);
-  JsonVariant variantMax(max);
+  variantMin.set(min);
+  variantMax.set(max);
 
   REQUIRE(min == variantMin.as<T>());
   REQUIRE(max == variantMax.as<T>());
@@ -41,9 +48,12 @@ TEST_CASE("JsonVariant set()/get()") {
   SECTION("Null") {
     checkValue<const char *>(NULL);
   }
-  SECTION("String") {
+  SECTION("const char*") {
     checkValue<const char *>("hello");
   }
+  SECTION("std::string") {
+    checkValue<std::string>("hello");
+  }
 
   SECTION("False") {
     checkValue<bool>(false);

+ 10 - 8
test/JsonVariant/subscript.cpp

@@ -6,24 +6,26 @@
 #include <catch.hpp>
 
 TEST_CASE("JsonVariant::operator[]") {
+  DynamicJsonDocument doc;
+  JsonVariant var = doc.to<JsonVariant>();
+
   SECTION("The JsonVariant is undefined") {
-    JsonVariant var = JsonVariant();
     REQUIRE(0 == var.size());
     REQUIRE(var["0"].isNull());
     REQUIRE(var[0].isNull());
   }
 
   SECTION("The JsonVariant is a string") {
-    JsonVariant var = "hello world";
+    var.set("hello world");
     REQUIRE(0 == var.size());
     REQUIRE(var["0"].isNull());
     REQUIRE(var[0].isNull());
   }
 
   SECTION("The JsonVariant is a JsonArray") {
-    DynamicJsonDocument doc;
-    JsonArray array = doc.to<JsonArray>();
-    JsonVariant var = array;
+    DynamicJsonDocument doc2;
+    JsonArray array = doc2.to<JsonArray>();
+    var.set(array);
 
     SECTION("get value") {
       array.add("element at index 0");
@@ -60,9 +62,9 @@ TEST_CASE("JsonVariant::operator[]") {
   }
 
   SECTION("The JsonVariant is a JsonObject") {
-    DynamicJsonDocument doc;
-    JsonObject object = doc.to<JsonObject>();
-    JsonVariant var = object;
+    DynamicJsonDocument doc2;
+    JsonObject object = doc2.to<JsonObject>();
+    var.set(object);
 
     SECTION("get value") {
       object["a"] = "element at key \"a\"";

+ 8 - 16
test/Misc/unsigned_char.cpp

@@ -29,19 +29,13 @@ TEST_CASE("unsigned char[]") {
   }
 
   SECTION("JsonVariant") {
-    SECTION("constructor") {
-      unsigned char value[] = "42";
-
-      JsonVariant variant(value);
-
-      REQUIRE(42 == variant.as<int>());
-    }
+    DynamicJsonDocument doc;
 
-    SECTION("operator=") {
+    SECTION("set") {
       unsigned char value[] = "42";
 
-      JsonVariant variant(666);
-      variant = value;
+      JsonVariant variant = doc.to<JsonVariant>();
+      variant.set(value);
 
       REQUIRE(42 == variant.as<int>());
     }
@@ -50,7 +44,6 @@ TEST_CASE("unsigned char[]") {
     SECTION("operator[]") {
       unsigned char key[] = "hello";
 
-      DynamicJsonDocument doc;
       deserializeJson(doc, "{\"hello\":\"world\"}");
       JsonVariant variant = doc.as<JsonVariant>();
 
@@ -62,7 +55,6 @@ TEST_CASE("unsigned char[]") {
     SECTION("operator[] const") {
       unsigned char key[] = "hello";
 
-      DynamicJsonDocument doc;
       deserializeJson(doc, "{\"hello\":\"world\"}");
       const JsonVariant variant = doc.as<JsonVariant>();
 
@@ -73,8 +65,8 @@ TEST_CASE("unsigned char[]") {
     SECTION("operator==") {
       unsigned char comparand[] = "hello";
 
-      JsonVariant variant;
-      variant = "hello";
+      JsonVariant variant = doc.to<JsonVariant>();
+      variant.set("hello");
 
       REQUIRE(comparand == variant);
       REQUIRE(variant == comparand);
@@ -85,8 +77,8 @@ TEST_CASE("unsigned char[]") {
     SECTION("operator!=") {
       unsigned char comparand[] = "hello";
 
-      JsonVariant variant;
-      variant = "world";
+      JsonVariant variant = doc.to<JsonVariant>();
+      variant.set("world");
 
       REQUIRE(comparand != variant);
       REQUIRE(variant != comparand);

+ 7 - 17
test/Misc/vla.cpp

@@ -40,23 +40,15 @@ TEST_CASE("Variable Length Array") {
   }
 
   SECTION("JsonVariant") {
-    SECTION("constructor") {
-      int i = 16;
-      char vla[i];
-      strcpy(vla, "42");
-
-      JsonVariant variant(vla);
-
-      REQUIRE(42 == variant.as<int>());
-    }
+    DynamicJsonDocument doc;
 
-    SECTION("operator=") {
+    SECTION("set()") {
       int i = 16;
       char vla[i];
       strcpy(vla, "42");
 
-      JsonVariant variant(666);
-      variant = vla;
+      JsonVariant variant = doc.to<JsonVariant>();
+      variant.set(vla);
 
       REQUIRE(42 == variant.as<int>());
     }
@@ -67,7 +59,6 @@ TEST_CASE("Variable Length Array") {
       char vla[i];
       strcpy(vla, "hello");
 
-      DynamicJsonDocument doc;
       deserializeJson(doc, "{\"hello\":\"world\"}");
       JsonVariant variant = doc.as<JsonVariant>();
 
@@ -81,7 +72,6 @@ TEST_CASE("Variable Length Array") {
       char vla[i];
       strcpy(vla, "hello");
 
-      DynamicJsonDocument doc;
       deserializeJson(doc, "{\"hello\":\"world\"}");
       const JsonVariant variant = doc.as<JsonVariant>();
 
@@ -94,8 +84,8 @@ TEST_CASE("Variable Length Array") {
       char vla[i];
       strcpy(vla, "hello");
 
-      JsonVariant variant;
-      variant = "hello";
+      JsonVariant variant = doc.to<JsonVariant>();
+      variant.set("hello");
 
       REQUIRE((vla == variant));
       REQUIRE((variant == vla));
@@ -109,7 +99,7 @@ TEST_CASE("Variable Length Array") {
       strcpy(vla, "hello");
 
       JsonVariant variant;
-      variant = "world";
+      variant.set("world");
 
       REQUIRE((vla != variant));
       REQUIRE((variant != vla));

+ 10 - 2
test/MsgPackDeserializer/deserializeVariant.cpp

@@ -16,10 +16,18 @@ static void check(const char* input, U expected) {
   REQUIRE(variant.as<T>() == expected);
 }
 
+static void checkIsNull(const char* input) {
+  DynamicJsonDocument variant;
+
+  DeserializationError error = deserializeMsgPack(variant, input);
+
+  REQUIRE(error == DeserializationError::Ok);
+  REQUIRE(variant.as<JsonVariant>().isNull());
+}
+
 TEST_CASE("deserialize MsgPack value") {
   SECTION("nil") {
-    const char* nil = 0;  // ArduinoJson uses a string for null
-    check<const char*>("\xc0", nil);
+    checkIsNull("\xc0");
   }
 
   SECTION("bool") {

+ 11 - 7
test/MsgPackSerializer/serializeVariant.cpp

@@ -5,8 +5,11 @@
 #include <ArduinoJson.h>
 #include <catch.hpp>
 
-void check(JsonVariant variant, const char* expected_data,
-           size_t expected_len) {
+template <typename T>
+void check(T value, const char* expected_data, size_t expected_len) {
+  DynamicJsonDocument doc;
+  JsonVariant variant = doc.to<JsonVariant>();
+  variant.set(value);
   std::string expected(expected_data, expected_data + expected_len);
   std::string actual;
   size_t len = serializeMsgPack(variant, actual);
@@ -15,14 +18,15 @@ void check(JsonVariant variant, const char* expected_data,
   REQUIRE(actual == expected);
 }
 
-template <size_t N>
-void check(JsonVariant variant, const char (&expected_data)[N]) {
+template <typename T, size_t N>
+void check(T value, const char (&expected_data)[N]) {
   const size_t expected_len = N - 1;
-  check(variant, expected_data, expected_len);
+  check(value, expected_data, expected_len);
 }
 
-void check(JsonVariant variant, const std::string& expected) {
-  check(variant, expected.data(), expected.length());
+template <typename T>
+void check(T value, const std::string& expected) {
+  check(value, expected.data(), expected.length());
 }
 
 TEST_CASE("serialize MsgPack value") {