mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Implemented reference semantics for JsonVariant
				
					
				
			This commit is contained in:
		
							
								
								
									
										50
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								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 | ||||
| ----------- | ||||
|  | ||||
|   | ||||
| @@ -4,6 +4,8 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <stdlib.h>  // size_t | ||||
|  | ||||
| #include "JsonFloat.hpp" | ||||
| #include "JsonInteger.hpp" | ||||
|  | ||||
|   | ||||
							
								
								
									
										181
									
								
								src/ArduinoJson/Data/JsonVariantData.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								src/ArduinoJson/Data/JsonVariantData.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| @@ -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> {}; | ||||
| } | ||||
| } | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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 | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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
									
								
								src/ArduinoJson/JsonArrayIterator.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/ArduinoJson/JsonArrayIterator.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| @@ -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; | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|   } | ||||
|  | ||||
|   Internals::JsonObjectData* _data; | ||||
|   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; | ||||
|   } | ||||
|  | ||||
|   mutable Internals::JsonBuffer* _buffer; | ||||
|   mutable Internals::JsonObjectData* _data; | ||||
| }; | ||||
| }  // namespace ArduinoJson | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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
									
								
								src/ArduinoJson/JsonObjectIterator.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/ArduinoJson/JsonObjectIterator.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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); | ||||
|   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; | ||||
|   } | ||||
|  | ||||
|   // 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> | ||||
|   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 { | ||||
|       _type = JSON_NEGATIVE_INTEGER; | ||||
|       _content.asInteger = ~static_cast<JsonUInt>(value) + 1; | ||||
|       _data->setNull(); | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|   // JsonVariant(unsigned short) | ||||
|   // JsonVariant(unsigned int) | ||||
|   // JsonVariant(unsigned long) | ||||
|   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); | ||||
|  | ||||
|   // 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 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); | ||||
|   bool set(const JsonVariant &value) { | ||||
|     if (!_data) return false; | ||||
|     if (value._data) | ||||
|       *_data = *value._data; | ||||
|     else | ||||
|       _data->setNull(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // 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(); | ||||
|   } | ||||
|  | ||||
|   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 | ||||
|   | ||||
| @@ -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" | ||||
|  | ||||
|   | ||||
| @@ -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(); | ||||
|   return _data ? JsonObject(_buffer, _data->asObject()) : JsonObject(); | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| 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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../../Configuration.hpp" | ||||
| #include "is_same.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -4,6 +4,8 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <string.h>  // strcmp | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
|   | ||||
| @@ -26,6 +26,7 @@ class StlString { | ||||
|   } | ||||
|  | ||||
|   bool equals(const char* expected) const { | ||||
|     if (!expected) return false; | ||||
|     return *_str == expected; | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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
									
								
								test/JsonDocument/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								test/JsonDocument/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								test/JsonDocument/DynamicJsonDocument.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								test/JsonDocument/DynamicJsonDocument.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								test/JsonDocument/StaticJsonDocument.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								test/JsonDocument/StaticJsonDocument.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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\"}"); | ||||
|   } | ||||
| } | ||||
| @@ -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); | ||||
|   // } | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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"); | ||||
|   } | ||||
|   | ||||
| @@ -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()); | ||||
|   | ||||
| @@ -5,7 +5,6 @@ | ||||
| add_executable(JsonVariantTests | ||||
| 	as.cpp | ||||
| 	compare.cpp | ||||
| 	copy.cpp | ||||
| 	is.cpp | ||||
| 	isnull.cpp | ||||
| 	or.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 | ||||
|   } | ||||
|   | ||||
| @@ -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); | ||||
| void checkEquals(T a, T b) { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonVariant variant = doc.to<JsonVariant>(); | ||||
|   variant.set(a); | ||||
|  | ||||
|   REQUIRE_FALSE(b != a); | ||||
|   REQUIRE_FALSE(a != b); | ||||
|   REQUIRE_FALSE(b > a); | ||||
|   REQUIRE_FALSE(a > b); | ||||
|   REQUIRE_FALSE(b < a); | ||||
|   REQUIRE_FALSE(a < b); | ||||
|   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); | ||||
| void checkGreater(T a, T b) { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonVariant variant = doc.to<JsonVariant>(); | ||||
|   variant.set(a); | ||||
|  | ||||
|   REQUIRE_FALSE(a < b); | ||||
|   REQUIRE_FALSE(b > a); | ||||
|   REQUIRE_FALSE(a == b); | ||||
|   REQUIRE_FALSE(b == 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); | ||||
| void checkLower(T a, T b) { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonVariant variant = doc.to<JsonVariant>(); | ||||
|   variant.set(a); | ||||
|  | ||||
|   REQUIRE_FALSE(a > b); | ||||
|   REQUIRE_FALSE(b < a); | ||||
|   REQUIRE_FALSE(a == b); | ||||
|   REQUIRE_FALSE(b == 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>(); | ||||
|   // 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]); | ||||
|   //   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]); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   //   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]); | ||||
|   //     } | ||||
|   //   } | ||||
|   // } | ||||
| } | ||||
|   | ||||
| @@ -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()); | ||||
|   } | ||||
| } | ||||
| @@ -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>()); | ||||
|   | ||||
| @@ -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); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -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") { | ||||
|     SECTION("undefined | const char*") { | ||||
|       std::string result = variant | "default"; | ||||
|       REQUIRE(result == "default"); | ||||
|     } | ||||
|  | ||||
|     SECTION("undefined | int") { | ||||
|       int result = variant | 42; | ||||
|       REQUIRE(result == 42); | ||||
|     } | ||||
|  | ||||
|     SECTION("undefined | bool") { | ||||
|       bool result = variant | true; | ||||
|       REQUIRE(result == true); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("undefined | int") { | ||||
|     int result = undefined | 42; | ||||
|     REQUIRE(result == 42); | ||||
|   } | ||||
|   SECTION("null") { | ||||
|     variant.set(static_cast<const char*>(0)); | ||||
|  | ||||
|   SECTION("undefined | bool") { | ||||
|     bool result = undefined | true; | ||||
|     REQUIRE(result == true); | ||||
|   } | ||||
|     SECTION("null | const char*") { | ||||
|       std::string result = variant | "default"; | ||||
|       REQUIRE(result == "default"); | ||||
|     } | ||||
|  | ||||
|   SECTION("null | const char*") { | ||||
|     std::string result = null | "default"; | ||||
|     REQUIRE(result == "default"); | ||||
|   } | ||||
|     SECTION("null | int") { | ||||
|       int result = variant | 42; | ||||
|       REQUIRE(result == 42); | ||||
|     } | ||||
|  | ||||
|   SECTION("null | int") { | ||||
|     int result = null | 42; | ||||
|     REQUIRE(result == 42); | ||||
|   } | ||||
|  | ||||
|   SECTION("null | bool") { | ||||
|     bool result = null | true; | ||||
|     REQUIRE(result == true); | ||||
|     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); | ||||
|   } | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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\""; | ||||
|   | ||||
| @@ -29,19 +29,13 @@ TEST_CASE("unsigned char[]") { | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonVariant") { | ||||
|     SECTION("constructor") { | ||||
|     DynamicJsonDocument doc; | ||||
|  | ||||
|     SECTION("set") { | ||||
|       unsigned char value[] = "42"; | ||||
|  | ||||
|       JsonVariant variant(value); | ||||
|  | ||||
|       REQUIRE(42 == variant.as<int>()); | ||||
|     } | ||||
|  | ||||
|     SECTION("operator=") { | ||||
|       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); | ||||
|   | ||||
| @@ -40,23 +40,15 @@ TEST_CASE("Variable Length Array") { | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonVariant") { | ||||
|     SECTION("constructor") { | ||||
|     DynamicJsonDocument doc; | ||||
|  | ||||
|     SECTION("set()") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "42"); | ||||
|  | ||||
|       JsonVariant variant(vla); | ||||
|  | ||||
|       REQUIRE(42 == variant.as<int>()); | ||||
|     } | ||||
|  | ||||
|     SECTION("operator=") { | ||||
|       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)); | ||||
|   | ||||
| @@ -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") { | ||||
|   | ||||
| @@ -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") { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user