JsonVariant automatically promotes to JsonObject or JsonArray on write

This commit is contained in:
Benoit Blanchon
2019-01-29 14:09:09 +01:00
parent 5aea1363cc
commit 6f55d1e58f
53 changed files with 1197 additions and 541 deletions

View File

@ -22,6 +22,12 @@ HEAD
* Added `JsonDocument::operator[]`
* Added `ARDUINOJSON_TAB` to configure the indentation character
* Reduced the size of the pretty JSON serializer
* Added `add()`, `createNestedArray()` and `createNestedObject()` to `JsonVariant`
* `JsonVariant` automatically promotes to `JsonObject` or `JsonArray` on write.
Calling `JsonVariant::to<T>()` is not required anymore.
* `JsonDocument` now support the same operations as `JsonVariant`.
Calling `JsonDocument::as<T>()` is not required anymore.
* Fixed example `JsonHttpClient.ino`
> ### BREAKING CHANGES
>

View File

@ -15,7 +15,11 @@
#include <SD.h>
#include <SPI.h>
// Configuration that we'll store on disk
// Our configuration structure.
//
// Never use a JsonDocument to store the configuration!
// A JsonDocument is *not* a permanent storage; it's only a temporary storage
// used during the serialization phase.
struct Config {
char hostname[64];
int port;
@ -29,9 +33,9 @@ void loadConfiguration(const char *filename, Config &config) {
// Open file for reading
File file = SD.open(filename);
// Allocate the document on the stack.
// Allocate a temporary JsonDocument
// Don't forget to change the capacity to match your requirements.
// Use arduinojson.org/assistant to compute the capacity.
// Use arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<512> doc;
// Deserialize the JSON document
@ -39,16 +43,13 @@ void loadConfiguration(const char *filename, Config &config) {
if (error)
Serial.println(F("Failed to read file, using default configuration"));
// Get the root object in the document
JsonObject root = doc.as<JsonObject>();
// Copy values from the JsonDocument to the Config
config.port = doc["port"] | 2731;
strlcpy(config.hostname, // <- destination
doc["hostname"] | "example.com", // <- source
sizeof(config.hostname)); // <- destination's capacity
// Copy values from the JsonObject to the Config
config.port = root["port"] | 2731;
strlcpy(config.hostname, // <- destination
root["hostname"] | "example.com", // <- source
sizeof(config.hostname)); // <- destination's capacity
// Close the file (File's destructor doesn't close the file)
// Close the file (Curiously, File's destructor doesn't close the file)
file.close();
}
@ -64,24 +65,21 @@ void saveConfiguration(const char *filename, const Config &config) {
return;
}
// Allocate the document on the stack.
// Allocate a temporary JsonDocument
// Don't forget to change the capacity to match your requirements.
// Use arduinojson.org/assistant to compute the capacity.
StaticJsonDocument<256> doc;
// Make our document contain an object
JsonObject root = doc.to<JsonObject>();
// Set the values in the object
root["hostname"] = config.hostname;
root["port"] = config.port;
// Set the values in the document
doc["hostname"] = config.hostname;
doc["port"] = config.port;
// Serialize JSON to file
if (serializeJson(doc, file) == 0) {
Serial.println(F("Failed to write to file"));
}
// Close the file (File's destructor doesn't close the file)
// Close the file
file.close();
}
@ -100,7 +98,7 @@ void printFile(const char *filename) {
}
Serial.println();
// Close the file (File's destructor doesn't close the file)
// Close the file
file.close();
}

View File

@ -15,7 +15,7 @@ void setup() {
//
// Inside the brackets, 200 is the RAM allocated to this document.
// Don't forget to change this value to match your requirement.
// Use arduinojson.org/assistant to compute the capacity.
// Use arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<200> doc;
// StaticJsonObject allocates memory on the stack, it can be
@ -23,30 +23,30 @@ void setup() {
//
// DynamicJsonDocument doc(200);
// Make our document be an object
JsonObject root = doc.to<JsonObject>();
// Add values in the object
// Add values in the document
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do root.set<long>("time", 1351824120);
root["sensor"] = "gps";
root["time"] = 1351824120;
doc["sensor"] = "gps";
doc["time"] = 1351824120;
// Add an array.
//
JsonArray data = root.createNestedArray("data");
JsonArray data = doc.createNestedArray("data");
data.add(48.756080);
data.add(2.302038);
// Generate the minified JSON and send it to the Serial port.
//
serializeJson(doc, Serial);
// This prints:
// The above line prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
// Start a new line
Serial.println();
// Generate the prettified JSON and send it to the Serial port.
//
serializeJsonPretty(doc, Serial);
// This prints:
// The above line prints:
// {
// "sensor": "gps",
// "time": 1351824120,

View File

@ -71,7 +71,7 @@ void setup() {
}
// Allocate the JSON document
// Use arduinojson.org/assistant to compute the capacity.
// Use arduinojson.org/v6/assistant to compute the capacity.
const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
DynamicJsonDocument doc(capacity);
@ -84,12 +84,11 @@ void setup() {
}
// Extract values
JsonObject root = doc.as<JsonObject>();
Serial.println(F("Response:"));
Serial.println(root["sensor"].as<char*>());
Serial.println(root["time"].as<char*>());
Serial.println(root["data"][0].as<char*>());
Serial.println(root["data"][1].as<char*>());
Serial.println(doc["sensor"].as<char*>());
Serial.println(doc["time"].as<long>());
Serial.println(doc["data"][0].as<float>(), 6);
Serial.println(doc["data"][1].as<float>(), 6);
// Disconnect
client.stop();

View File

@ -13,9 +13,9 @@ void setup() {
// Allocate the JSON document
//
// Inside the brackets, 200 is the size of the memory pool in bytes.
// Inside the brackets, 200 is the capacity of the memory pool in bytes.
// Don't forget to change this value to match your JSON document.
// Use arduinojson.org/assistant to compute the capacity.
// Use arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<200> doc;
// StaticJsonDocument<N> allocates memory on the stack, it can be
@ -25,9 +25,12 @@ void setup() {
// JSON input string.
//
// It's better to use a char[] as shown here.
// If you use a const char* or a String, ArduinoJson will
// have to make a copy of the input in the JsonBuffer.
// Using a char[], as shown here, enables the "zero-copy" mode. This mode uses
// the minimal amount of memory because the JsonDocument stores pointers to
// the input buffer.
// If you use another type of input, ArduinoJson must copy the strings from
// the input to the JsonDocument, so you need to increase the capacity of the
// JsonDocument.
char json[] =
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
@ -41,17 +44,14 @@ void setup() {
return;
}
// Get the root object in the document
JsonObject root = doc.as<JsonObject>();
// Fetch values.
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do root["time"].as<long>();
const char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
// In other case, you can do doc["time"].as<long>();
const char* sensor = doc["sensor"];
long time = doc["time"];
double latitude = doc["data"][0];
double longitude = doc["data"][1];
// Print values.
Serial.println(sensor);

View File

@ -2,15 +2,15 @@
// Copyright Benoit Blanchon 2014-2018
// MIT License
//
// This example shows how to implement an HTTP server that sends JSON document
// in the responses.
// This example shows how to implement an HTTP server that sends a JSON document
// in the response.
// It uses the Ethernet library but can be easily adapted for Wifi.
//
// It sends the value of the analog and digital pins.
// The JSON document looks like the following:
// The JSON document contains the values of the analog and digital pins.
// It looks like that:
// {
// "analog": [ 0, 1, 2, 3, 4, 5 ],
// "digital": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 ]
// "analog": [0, 76, 123, 158, 192, 205],
// "digital": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]
// }
#include <ArduinoJson.h>
@ -51,15 +51,12 @@ void loop() {
// Read the request (we ignore the content in this example)
while (client.available()) client.read();
// Allocate the JSON document
// Use arduinojson.org/assistant to compute the capacity.
// Allocate a temporary JsonDocument
// Use arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<500> doc;
// Make our document represent an object
JsonObject root = doc.to<JsonObject>();
// Create the "analog" array
JsonArray analogValues = root.createNestedArray("analog");
JsonArray analogValues = doc.createNestedArray("analog");
for (int pin = 0; pin < 6; pin++) {
// Read the analog input
int value = analogRead(pin);
@ -69,7 +66,7 @@ void loop() {
}
// Create the "digital" array
JsonArray digitalValues = root.createNestedArray("digital");
JsonArray digitalValues = doc.createNestedArray("digital");
for (int pin = 0; pin < 14; pin++) {
// Read the digital input
int value = digitalRead(pin);
@ -83,9 +80,11 @@ void loop() {
Serial.println();
// Write response headers
client.println("HTTP/1.0 200 OK");
client.println("Content-Type: application/json");
client.println("Connection: close");
client.println(F("HTTP/1.0 200 OK"));
client.println(F("Content-Type: application/json"));
client.println(F("Connection: close"));
client.print(F("Content-Length: "));
client.println(measureJsonPretty(doc));
client.println();
// Write JSON document

View File

@ -5,10 +5,10 @@
// This example shows how to send a JSON document to a UDP socket.
// At regular interval, it sends a UDP packet that contains the status of
// analog and digital pins.
// The JSON document looks like the following:
// It looks like that:
// {
// "analog": [ 0, 1, 2, 3, 4, 5 ],
// "digital": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 ]
// "analog": [0, 76, 123, 158, 192, 205],
// "digital": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]
// }
//
// If you want to test this program, you need to be able to receive the UDP
@ -43,15 +43,12 @@ void setup() {
}
void loop() {
// Allocate the JSON document
// Use arduinojson.org/assistant to compute the capacity.
// Allocate a temporary JsonDocument
// Use arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<500> doc;
// Make our document represent an object
JsonObject root = doc.to<JsonObject>();
// Create the "analog" array
JsonArray analogValues = root.createNestedArray("analog");
JsonArray analogValues = doc.createNestedArray("analog");
for (int pin = 0; pin < 6; pin++) {
// Read the analog input
int value = analogRead(pin);
@ -61,7 +58,7 @@ void loop() {
}
// Create the "digital" array
JsonArray digitalValues = root.createNestedArray("digital");
JsonArray digitalValues = doc.createNestedArray("digital");
for (int pin = 0; pin < 14; pin++) {
// Read the digital input
int value = digitalRead(pin);

View File

@ -14,9 +14,9 @@ void setup() {
// Allocate the JSON document
//
// Inside the brackets, 200 is the size of the memory pool in bytes.
// Inside the brackets, 200 is the capacity of the memory pool in bytes.
// Don't forget to change this value to match your JSON document.
// Use arduinojson.org/assistant to compute the capacity.
// Use arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<200> doc;
// StaticJsonObject allocates memory on the stack, it can be
@ -26,9 +26,12 @@ void setup() {
// MessagePack input string.
//
// It's better to use a char[] as shown here.
// If you use a const char* or a String, ArduinoJson will
// have to make a copy of the input in the JsonBuffer.
// Using a char[], as shown here, enables the "zero-copy" mode. This mode uses
// the minimal amount of memory because the JsonDocument stores pointers to
// the input buffer.
// If you use another type of input, ArduinoJson must copy the strings from
// the input to the JsonDocument, so you need to increase the capacity of the
// JsonDocument.
uint8_t input[] = {131, 166, 115, 101, 110, 115, 111, 114, 163, 103, 112, 115,
164, 116, 105, 109, 101, 206, 80, 147, 50, 248, 164, 100,
97, 116, 97, 146, 203, 64, 72, 96, 199, 58, 188, 148,
@ -40,31 +43,23 @@ void setup() {
// "data": [48.75608, 2.302038]
// }
// doc of the object tree.
//
// It's a reference to the JsonObject, the actual bytes are inside the
// JsonBuffer with all the other nodes of the object tree.
// Memory is freed when jsonBuffer goes out of scope.
DeserializationError error = deserializeMsgPack(doc, input);
// Test if parsing succeeds.
// Test if parsing succeeded.
if (error) {
Serial.print("deserializeMsgPack() failed: ");
Serial.println(error.c_str());
return;
}
// Get the root object in the document
JsonObject root = doc.as<JsonObject>();
// Fetch values.
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do root["time"].as<long>();
const char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
// In other case, you can do doc["time"].as<long>();
const char* sensor = doc["sensor"];
long time = doc["time"];
double latitude = doc["data"][0];
double longitude = doc["data"][1];
// Print values.
Serial.println(sensor);

View File

@ -6,7 +6,7 @@
// ArduinoJson.
//
// Use Flash strings sparingly, because ArduinoJson duplicates them in the
// JsonBuffer. Prefer plain old char*, as they are more efficient in term of
// JsonDocument. Prefer plain old char*, as they are more efficient in term of
// code size, speed, and memory usage.
#include <ArduinoJson.h>
@ -17,8 +17,7 @@ void setup() {
DynamicJsonDocument doc(1024);
// You can use a Flash String as your JSON input.
// WARNING: the content of the Flash String will be duplicated in the
// JsonBuffer.
// WARNING: the string in the input will be duplicated in the JsonDocument.
deserializeJson(doc, F("{\"sensor\":\"gps\",\"time\":1351824120,"
"\"data\":[48.756080,2.302038]}"));
JsonObject obj = doc.as<JsonObject>();
@ -29,12 +28,12 @@ void setup() {
// You can use a Flash String to set an element of a JsonObject
// WARNING: the content of the Flash String will be duplicated in the
// JsonBuffer.
// JsonDocument.
obj[F("time")] = time;
// You can set a Flash String to a JsonObject or JsonArray:
// WARNING: the content of the Flash String will be duplicated in the
// JsonBuffer.
// JsonDocument.
obj["sensor"] = F("gps");
// It works with serialized() too:

View File

@ -5,7 +5,7 @@
// This example shows the different ways you can use String with ArduinoJson.
//
// Use String objects sparingly, because ArduinoJson duplicates them in the
// JsonBuffer. Prefer plain old char[], as they are more efficient in term of
// JsonDocument. Prefer plain old char[], as they are more efficient in term of
// code size, speed, and memory usage.
#include <ArduinoJson.h>
@ -14,7 +14,7 @@ void setup() {
DynamicJsonDocument doc(1024);
// You can use a String as your JSON input.
// WARNING: the content of the String will be duplicated in the JsonBuffer.
// WARNING: the string in the input will be duplicated in the JsonDocument.
String input =
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
deserializeJson(doc, input);
@ -25,11 +25,11 @@ void setup() {
long time = obj[String("time")];
// You can use a String to set an element of a JsonObject
// WARNING: the content of the String will be duplicated in the JsonBuffer.
// WARNING: the content of the String will be duplicated in the JsonDocument.
obj[String("time")] = time;
// You can get a String from a JsonObject or JsonArray:
// No duplication is done, at least not in the JsonBuffer.
// No duplication is done, at least not in the JsonDocument.
String sensor = obj["sensor"];
// Unfortunately, the following doesn't work (issue #118):
@ -38,14 +38,14 @@ void setup() {
sensor = obj["sensor"].as<String>();
// You can set a String to a JsonObject or JsonArray:
// WARNING: the content of the String will be duplicated in the JsonBuffer.
// WARNING: the content of the String will be duplicated in the JsonDocument.
obj["sensor"] = sensor;
// It works with serialized() too:
obj["sensor"] = serialized(sensor);
// You can also concatenate strings
// WARNING: the content of the String will be duplicated in the JsonBuffer.
// WARNING: the content of the String will be duplicated in the JsonDocument.
obj[String("sen") + "sor"] = String("gp") + "s";
// You can compare the content of a JsonObject with a String

View File

@ -14,10 +14,10 @@
#include "ArduinoJson/Document/StaticJsonDocument.hpp"
#include "ArduinoJson/Array/ArrayImpl.hpp"
#include "ArduinoJson/Array/ArraySubscript.hpp"
#include "ArduinoJson/Array/ElementProxy.hpp"
#include "ArduinoJson/Collection/CollectionImpl.hpp"
#include "ArduinoJson/Object/MemberProxy.hpp"
#include "ArduinoJson/Object/ObjectImpl.hpp"
#include "ArduinoJson/Object/ObjectSubscript.hpp"
#include "ArduinoJson/Variant/VariantAsImpl.hpp"
#include "ArduinoJson/Variant/VariantImpl.hpp"

View File

@ -9,11 +9,14 @@
namespace ARDUINOJSON_NAMESPACE {
inline ArrayRef ArrayRef::createNestedArray() const {
return add().to<ArrayRef>();
template <typename TArray>
inline ArrayRef ArrayShortcuts<TArray>::createNestedArray() const {
return impl()->add().template to<ArrayRef>();
}
inline ObjectRef ArrayRef::createNestedObject() const {
return add().to<ObjectRef>();
template <typename TArray>
inline ObjectRef ArrayShortcuts<TArray>::createNestedObject() const {
return impl()->add().template to<ObjectRef>();
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -16,11 +16,16 @@
namespace ARDUINOJSON_NAMESPACE {
class ObjectRef;
class ArraySubscript;
template <typename>
class ElementProxy;
template <typename TData>
class ArrayRefBase {
public:
operator VariantConstRef() const {
return VariantConstRef(reinterpret_cast<const VariantData*>(_data));
}
template <typename Visitor>
FORCE_INLINE void accept(Visitor& visitor) const {
arrayAccept(_data, visitor);
@ -30,10 +35,6 @@ class ArrayRefBase {
return _data == 0;
}
FORCE_INLINE VariantConstRef operator[](size_t index) const {
return VariantConstRef(_data ? _data->get(index) : 0);
}
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
}
@ -74,9 +75,15 @@ class ArrayConstRef : public ArrayRefBase<const CollectionData>,
FORCE_INLINE bool operator==(ArrayConstRef rhs) const {
return arrayEquals(_data, rhs._data);
}
FORCE_INLINE VariantConstRef operator[](size_t index) const {
return VariantConstRef(_data ? _data->get(index) : 0);
}
};
class ArrayRef : public ArrayRefBase<CollectionData>, public Visitable {
class ArrayRef : public ArrayRefBase<CollectionData>,
public ArrayShortcuts<ArrayRef>,
public Visitable {
typedef ArrayRefBase<CollectionData> base_type;
public:
@ -94,27 +101,7 @@ class ArrayRef : public ArrayRefBase<CollectionData>, public Visitable {
return ArrayConstRef(_data);
}
// Adds the specified value at the end of the array.
//
// bool add(TValue);
// TValue = bool, long, int, short, float, double, serialized, VariantRef,
// std::string, String, ObjectRef
template <typename T>
FORCE_INLINE bool add(const T& value) const {
return add().set(value);
}
// Adds the specified value at the end of the array.
FORCE_INLINE bool add(ArrayConstRef value) const {
return add().set(value);
}
//
// bool add(TValue);
// TValue = char*, const char*, const __FlashStringHelper*
template <typename T>
FORCE_INLINE bool add(T* value) const {
return add().set(value);
}
using ArrayShortcuts::add;
VariantRef add() const {
return VariantRef(_pool, arrayAdd(_data, _pool));
}
@ -187,11 +174,6 @@ class ArrayRef : public ArrayRefBase<CollectionData>, public Visitable {
}
}
FORCE_INLINE ArrayRef createNestedArray() const;
FORCE_INLINE ObjectRef createNestedObject() const;
FORCE_INLINE ArraySubscript operator[](size_t index) const;
FORCE_INLINE bool operator==(ArrayRef rhs) const {
return arrayEquals(_data, rhs._data);
}

View File

@ -0,0 +1,47 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Polyfills/attributes.hpp"
#include "../Polyfills/type_traits.hpp"
namespace ARDUINOJSON_NAMESPACE {
// Forward declarations.
template <typename>
class ElementProxy;
template <typename TArray>
class ArrayShortcuts {
public:
// Returns the element at specified index if the variant is an array.
FORCE_INLINE ElementProxy<const TArray &> operator[](size_t index) const;
FORCE_INLINE ObjectRef createNestedObject() const;
FORCE_INLINE ArrayRef createNestedArray() const;
// Adds the specified value at the end of the array.
//
// bool add(TValue);
// TValue = bool, long, int, short, float, double, serialized, VariantRef,
// std::string, String, ObjectRef
template <typename T>
FORCE_INLINE bool add(const T &value) const {
return impl()->add().set(value);
}
//
// bool add(TValue);
// TValue = char*, const char*, const __FlashStringHelper*
template <typename T>
FORCE_INLINE bool add(T *value) const {
return impl()->add().set(value);
}
private:
const TArray *impl() const {
return static_cast<const TArray *>(this);
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -13,14 +13,18 @@
#endif
namespace ARDUINOJSON_NAMESPACE {
class ArraySubscript : public VariantOperators<ArraySubscript>,
public Visitable {
template <typename TArray>
class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
public Visitable {
typedef ElementProxy<TArray> this_type;
public:
FORCE_INLINE ArraySubscript(ArrayRef array, size_t index)
FORCE_INLINE ElementProxy(TArray array, size_t index)
: _array(array), _index(index) {}
FORCE_INLINE ArraySubscript& operator=(const ArraySubscript& src) {
get_impl().set(src.as<VariantConstRef>());
FORCE_INLINE this_type& operator=(const this_type& src) {
getElement().set(src.as<VariantConstRef>());
return *this;
}
@ -30,36 +34,36 @@ class ArraySubscript : public VariantOperators<ArraySubscript>,
// TValue = bool, long, int, short, float, double, serialized, VariantRef,
// std::string, String, ArrayRef, ObjectRef
template <typename T>
FORCE_INLINE ArraySubscript& operator=(const T& src) {
get_impl().set(src);
FORCE_INLINE this_type& operator=(const T& src) {
getElement().set(src);
return *this;
}
//
// operator=(TValue)
// TValue = char*, const char*, const __FlashStringHelper*
template <typename T>
FORCE_INLINE ArraySubscript& operator=(T* src) {
get_impl().set(src);
FORCE_INLINE this_type& operator=(T* src) {
getElement().set(src);
return *this;
}
FORCE_INLINE bool isNull() const {
return get_impl().isNull();
return getElement().isNull();
}
template <typename T>
FORCE_INLINE typename VariantAs<T>::type as() const {
return get_impl().as<T>();
return getElement().template as<T>();
}
template <typename T>
FORCE_INLINE bool is() const {
return get_impl().is<T>();
return getElement().template is<T>();
}
template <typename T>
FORCE_INLINE typename VariantTo<T>::type to() const {
return get_impl().to<T>();
return getElement().template to<T>();
}
// Replaces the value
@ -69,42 +73,65 @@ class ArraySubscript : public VariantOperators<ArraySubscript>,
// std::string, String, ArrayRef, ObjectRef
template <typename TValue>
FORCE_INLINE bool set(const TValue& value) const {
return get_impl().set(value);
return getElement().set(value);
}
//
// bool set(TValue)
// TValue = char*, const char*, const __FlashStringHelper*
template <typename TValue>
FORCE_INLINE bool set(TValue* value) const {
return get_impl().set(value);
return getElement().set(value);
}
template <typename Visitor>
void accept(Visitor& visitor) const {
return get_impl().accept(visitor);
return getElement().accept(visitor);
}
FORCE_INLINE size_t size() const {
return get_impl().size();
return getElement().size();
}
template <typename TNestedKey>
VariantRef get(TNestedKey* key) const {
return getElement().get(key);
}
template <typename TNestedKey>
VariantRef get(const TNestedKey& key) const {
return getElement().get(key);
}
template <typename TNestedKey>
VariantRef getOrCreate(TNestedKey* key) const {
return getElement().getOrCreate(key);
}
template <typename TNestedKey>
VariantRef getOrCreate(const TNestedKey& key) const {
return getElement().getOrCreate(key);
}
using ArrayShortcuts<ElementProxy>::add;
VariantRef add() const {
return getElement().add();
}
private:
FORCE_INLINE VariantRef get_impl() const {
FORCE_INLINE VariantRef getElement() const {
return _array.get(_index);
}
ArrayRef _array;
TArray _array;
const size_t _index;
};
template <typename TImpl>
inline ArraySubscript VariantSubscripts<TImpl>::operator[](size_t index) const {
return impl()->template as<ArrayRef>()[index];
template <typename TArray>
inline ElementProxy<const TArray&> ArrayShortcuts<TArray>::operator[](
size_t index) const {
return ElementProxy<const TArray&>(*impl(), index);
}
inline ArraySubscript ArrayRef::operator[](size_t index) const {
return ArraySubscript(*this, index);
}
} // namespace ARDUINOJSON_NAMESPACE
#ifdef _MSC_VER

View File

@ -9,7 +9,8 @@
#include "../Variant/VariantRef.hpp"
#include "../Variant/VariantTo.hpp"
#include "../Array/ArraySubscript.hpp"
#include "../Array/ElementProxy.hpp"
#include "../Object/MemberProxy.hpp"
namespace ARDUINOJSON_NAMESPACE {
@ -81,22 +82,51 @@ class JsonDocument : public Visitable {
return _data;
}
// ObjectSubscript operator[](TKey)
// TKey = const std::string&, const String&
template <typename TKey>
FORCE_INLINE typename enable_if<IsString<TKey>::value,
ObjectSubscript<const TKey&> >::type
operator[](const TKey& key) {
return getVariant()[key];
ArrayRef createNestedArray() {
return add().to<ArrayRef>();
}
// ObjectSubscript operator[](TKey);
// TKey = const char*, const char[N], const __FlashStringHelper*
template <typename TKey>
ArrayRef createNestedArray(TKey* key) {
return getOrCreate(key).template to<ArrayRef>();
}
template <typename TKey>
ArrayRef createNestedArray(const TKey& key) {
return getOrCreate(key).template to<ArrayRef>();
}
ObjectRef createNestedObject() {
return add().to<ObjectRef>();
}
template <typename TKey>
ObjectRef createNestedObject(TKey* key) {
return getOrCreate(key).template to<ObjectRef>();
}
template <typename TKey>
ObjectRef createNestedObject(const TKey& key) {
return getOrCreate(key).template to<ObjectRef>();
}
// MemberProxy operator[](TKey)
// TKey = const std::string&, const String&
template <typename TKey>
FORCE_INLINE
typename enable_if<IsString<TKey*>::value, ObjectSubscript<TKey*> >::type
operator[](TKey* key) {
return getVariant()[key];
typename enable_if<IsString<TKey>::value,
MemberProxy<JsonDocument&, const TKey&> >::type
operator[](const TKey& key) {
return MemberProxy<JsonDocument&, const TKey&>(*this, key);
}
// MemberProxy operator[](TKey);
// TKey = const char*, const char[N], const __FlashStringHelper*
template <typename TKey>
FORCE_INLINE typename enable_if<IsString<TKey*>::value,
MemberProxy<JsonDocument&, TKey*> >::type
operator[](TKey* key) {
return MemberProxy<JsonDocument&, TKey*>(*this, key);
}
// VariantConstRef operator[](TKey) const
@ -115,12 +145,56 @@ class JsonDocument : public Visitable {
return getVariant()[key];
}
FORCE_INLINE ArraySubscript operator[](size_t index) {
return getVariant()[index];
FORCE_INLINE ElementProxy<JsonDocument&> operator[](size_t index) {
return ElementProxy<JsonDocument&>(*this, index);
}
FORCE_INLINE VariantConstRef operator[](size_t index) const {
return getVariant()[index];
return VariantConstRef(_data.get(index));
}
FORCE_INLINE VariantRef get(size_t index) {
return VariantRef(&_pool, _data.get(index));
}
template <typename TKey>
FORCE_INLINE VariantRef get(TKey* key) {
return VariantRef(&_pool, _data.get(wrapString(key)));
}
template <typename TKey>
FORCE_INLINE typename enable_if<IsString<TKey>::value, VariantRef>::type get(
const TKey& key) {
return VariantRef(&_pool, _data.get(wrapString(key)));
}
template <typename TKey>
FORCE_INLINE VariantRef getOrCreate(TKey* key) {
return VariantRef(&_pool, _data.getOrCreate(wrapString(key), &_pool));
}
template <typename TKey>
FORCE_INLINE VariantRef getOrCreate(const TKey& key) {
return VariantRef(&_pool, _data.getOrCreate(wrapString(key), &_pool));
}
FORCE_INLINE VariantRef add() {
return VariantRef(&_pool, _data.add(&_pool));
}
//
// bool add(TValue);
// TValue = bool, long, int, short, float, double, serialized, VariantRef,
// std::string, String, ObjectRef
template <typename T>
FORCE_INLINE bool add(const T& value) {
return add().set(value);
}
//
// bool add(TValue);
// TValue = char*, const char*, const __FlashStringHelper*
template <typename T>
FORCE_INLINE bool add(T* value) {
return add().set(value);
}
protected:

View File

@ -15,4 +15,7 @@ struct Visitable {
template <typename T>
struct IsVisitable : is_base_of<Visitable, T> {};
template <typename T>
struct IsVisitable<T&> : IsVisitable<T> {};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -15,21 +15,21 @@
namespace ARDUINOJSON_NAMESPACE {
template <typename TStringRef>
class ObjectSubscript : public VariantOperators<ObjectSubscript<TStringRef> >,
public Visitable {
typedef ObjectSubscript<TStringRef> this_type;
template <typename TObject, typename TString>
class MemberProxy : public VariantOperators<MemberProxy<TObject, TString> >,
public Visitable {
typedef MemberProxy<TObject, TString> this_type;
public:
FORCE_INLINE ObjectSubscript(ObjectRef object, TStringRef key)
: _object(object), _key(key) {}
FORCE_INLINE MemberProxy(TObject variant, TString key)
: _object(variant), _key(key) {}
operator VariantConstRef() const {
return get_impl();
FORCE_INLINE operator VariantConstRef() const {
return getMember();
}
FORCE_INLINE this_type &operator=(const this_type &src) {
set_impl().set(src);
getOrCreateMember().set(src);
return *this;
}
@ -41,7 +41,7 @@ class ObjectSubscript : public VariantOperators<ObjectSubscript<TStringRef> >,
template <typename TValue>
FORCE_INLINE typename enable_if<!is_array<TValue>::value, this_type &>::type
operator=(const TValue &src) {
set_impl().set(src);
getOrCreateMember().set(src);
return *this;
}
//
@ -49,27 +49,27 @@ class ObjectSubscript : public VariantOperators<ObjectSubscript<TStringRef> >,
// TValue = char*, const char*, const __FlashStringHelper*
template <typename TValue>
FORCE_INLINE this_type &operator=(TValue *src) {
set_impl().set(src);
getOrCreateMember().set(src);
return *this;
}
FORCE_INLINE bool isNull() const {
return get_impl().isNull();
return getMember().isNull();
}
template <typename TValue>
FORCE_INLINE typename VariantAs<TValue>::type as() const {
return get_impl().template as<TValue>();
return getMember().template as<TValue>();
}
template <typename TValue>
FORCE_INLINE bool is() const {
return get_impl().template is<TValue>();
return getMember().template is<TValue>();
}
template <typename TValue>
FORCE_INLINE typename VariantTo<TValue>::type to() {
return set_impl().template to<TValue>();
return getOrCreateMember().template to<TValue>();
}
// Sets the specified value.
@ -81,48 +81,73 @@ class ObjectSubscript : public VariantOperators<ObjectSubscript<TStringRef> >,
template <typename TValue>
FORCE_INLINE typename enable_if<!is_array<TValue>::value, bool>::type set(
const TValue &value) {
return set_impl().set(value);
return getOrCreateMember().set(value);
}
//
// bool set(TValue);
// TValue = char*, const char, const __FlashStringHelper*
template <typename TValue>
FORCE_INLINE bool set(const TValue *value) {
return set_impl().set(value);
return getOrCreateMember().set(value);
}
template <typename Visitor>
void accept(Visitor &visitor) const {
return get_impl().accept(visitor);
return getMember().accept(visitor);
}
using ArrayShortcuts<MemberProxy>::add;
FORCE_INLINE VariantRef add() const {
return getOrCreateMember().add();
}
template <typename TNestedKey>
FORCE_INLINE VariantRef get(TNestedKey *key) const {
return getMember().get(key);
}
template <typename TNestedKey>
FORCE_INLINE VariantRef get(const TNestedKey &key) const {
return getMember().get(key);
}
template <typename TNestedKey>
FORCE_INLINE VariantRef getOrCreate(TNestedKey *key) const {
return getOrCreateMember().getOrCreate(key);
}
template <typename TNestedKey>
FORCE_INLINE VariantRef getOrCreate(const TNestedKey &key) const {
return getOrCreateMember().getOrCreate(key);
}
private:
FORCE_INLINE VariantRef get_impl() const {
FORCE_INLINE VariantRef getMember() const {
return _object.get(_key);
}
FORCE_INLINE VariantRef set_impl() const {
return _object.set(_key);
FORCE_INLINE VariantRef getOrCreateMember() const {
return _object.getOrCreate(_key);
}
ObjectRef _object;
TStringRef _key;
TObject _object;
TString _key;
};
template <typename TImpl>
template <typename TObject>
template <typename TString>
inline typename enable_if<IsString<TString>::value,
ObjectSubscript<const TString &> >::type
VariantSubscripts<TImpl>::operator[](const TString &key) const {
return impl()->template as<ObjectRef>()[key];
MemberProxy<const TObject &, const TString &> >::type
ObjectShortcuts<TObject>::operator[](const TString &key) const {
return MemberProxy<const TObject &, const TString &>(*impl(), key);
}
template <typename TImpl>
template <typename TObject>
template <typename TString>
inline typename enable_if<IsString<TString *>::value,
ObjectSubscript<TString *> >::type
VariantSubscripts<TImpl>::operator[](TString *key) const {
return impl()->template as<ObjectRef>()[key];
MemberProxy<const TObject &, TString *> >::type
ObjectShortcuts<TObject>::operator[](TString *key) const {
return MemberProxy<const TObject &, TString *>(*impl(), key);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -40,7 +40,8 @@ void objectRemove(CollectionData *obj, TKey key) {
}
template <typename TKey>
inline VariantData *objectSet(CollectionData *obj, TKey key, MemoryPool *pool) {
inline VariantData *objectGetOrCreate(CollectionData *obj, TKey key,
MemoryPool *pool) {
if (!obj) return 0;
// ignore null key

View File

@ -9,13 +9,31 @@
namespace ARDUINOJSON_NAMESPACE {
template <typename TObject>
template <typename TString>
inline ArrayRef ObjectRef::createNestedArray(const TString& key) const {
return set(key).template to<ArrayRef>();
inline ArrayRef ObjectShortcuts<TObject>::createNestedArray(
const TString& key) const {
return impl()->getOrCreate(key).template to<ArrayRef>();
}
template <typename TObject>
template <typename TString>
inline ArrayRef ObjectRef::createNestedArray(TString* key) const {
return set(key).template to<ArrayRef>();
inline ArrayRef ObjectShortcuts<TObject>::createNestedArray(
TString* key) const {
return impl()->getOrCreate(key).template to<ArrayRef>();
}
template <typename TObject>
template <typename TKey>
ObjectRef ObjectShortcuts<TObject>::createNestedObject(const TKey& key) const {
return impl()->getOrCreate(key).template to<ObjectRef>();
}
//
// ObjectRef createNestedObject(TKey);
// TKey = char*, const char*, char[], const char[], const __FlashStringHelper*
template <typename TObject>
template <typename TKey>
ObjectRef ObjectShortcuts<TObject>::createNestedObject(TKey* key) const {
return impl()->getOrCreate(key).template to<ObjectRef>();
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -17,6 +17,10 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename TData>
class ObjectRefBase {
public:
operator VariantConstRef() const {
return VariantConstRef(reinterpret_cast<const VariantData*>(_data));
}
template <typename Visitor>
FORCE_INLINE void accept(Visitor& visitor) const {
objectAccept(_data, visitor);
@ -127,7 +131,9 @@ class ObjectConstRef : public ObjectRefBase<const CollectionData>,
}
};
class ObjectRef : public ObjectRefBase<CollectionData>, public Visitable {
class ObjectRef : public ObjectRefBase<CollectionData>,
public ObjectShortcuts<ObjectRef>,
public Visitable {
typedef ObjectRefBase<CollectionData> base_type;
public:
@ -164,68 +170,30 @@ class ObjectRef : public ObjectRefBase<CollectionData>, public Visitable {
return _data->copyFrom(*src._data, _pool);
}
// Creates and adds a ArrayRef.
//
// ArrayRef createNestedArray(TKey);
// TKey = const std::string&, const String&
template <typename TKey>
FORCE_INLINE ArrayRef createNestedArray(const TKey& key) const;
// ArrayRef createNestedArray(TKey);
// TKey = char*, const char*, char[], const char[], const __FlashStringHelper*
template <typename TKey>
FORCE_INLINE ArrayRef createNestedArray(TKey* key) const;
// Creates and adds a ObjectRef.
//
// ObjectRef createNestedObject(TKey);
// TKey = const std::string&, const String&
template <typename TKey>
FORCE_INLINE ObjectRef createNestedObject(const TKey& key) const {
return set(key).template to<ObjectRef>();
}
//
// ObjectRef createNestedObject(TKey);
// TKey = char*, const char*, char[], const char[], const __FlashStringHelper*
template <typename TKey>
FORCE_INLINE ObjectRef createNestedObject(TKey* key) const {
return set(key).template to<ObjectRef>();
}
// Gets the value associated with the specified key.
//
// TValue get<TValue>(TKey) const;
// VariantRef get<TValue>(TKey) const;
// TKey = const std::string&, const String&
// TValue = bool, char, long, int, short, float, double,
// std::string, String, ArrayRef, ObjectRef
template <typename TKey>
FORCE_INLINE VariantRef get(const TKey& key) const {
return get_impl(wrapString(key));
}
//
// TValue get<TValue>(TKey) const;
// VariantRef get<TValue>(TKey) const;
// TKey = char*, const char*, const __FlashStringHelper*
// TValue = bool, char, long, int, short, float, double,
// std::string, String, ArrayRef, ObjectRef
template <typename TKey>
FORCE_INLINE VariantRef get(TKey* key) const {
return get_impl(wrapString(key));
}
// Gets or sets the value associated with the specified key.
//
// ObjectSubscript operator[](TKey)
// TKey = const std::string&, const String&
template <typename TKey>
FORCE_INLINE ObjectSubscript<const TKey&> operator[](const TKey& key) const {
return ObjectSubscript<const TKey&>(*this, key);
FORCE_INLINE VariantRef getOrCreate(TKey* key) const {
return getOrCreate_impl(wrapString(key));
}
//
// ObjectSubscript operator[](TKey)
// TKey = char*, const char*, char[], const char[N], const
// __FlashStringHelper*
template <typename TKey>
FORCE_INLINE ObjectSubscript<TKey*> operator[](TKey* key) const {
return ObjectSubscript<TKey*>(*this, key);
FORCE_INLINE VariantRef getOrCreate(const TKey& key) const {
return getOrCreate_impl(wrapString(key));
}
FORCE_INLINE bool operator==(ObjectRef rhs) const {
@ -253,16 +221,6 @@ class ObjectRef : public ObjectRefBase<CollectionData>, public Visitable {
objectRemove(_data, wrapString(key));
}
template <typename TKey>
FORCE_INLINE VariantRef set(TKey* key) const {
return set_impl(wrapString(key));
}
template <typename TKey>
FORCE_INLINE VariantRef set(const TKey& key) const {
return set_impl(wrapString(key));
}
private:
template <typename TKey>
FORCE_INLINE VariantRef get_impl(TKey key) const {
@ -270,8 +228,8 @@ class ObjectRef : public ObjectRefBase<CollectionData>, public Visitable {
}
template <typename TKey>
FORCE_INLINE VariantRef set_impl(TKey key) const {
return VariantRef(_pool, objectSet(_data, key, _pool));
FORCE_INLINE VariantRef getOrCreate_impl(TKey key) const {
return VariantRef(_pool, objectGetOrCreate(_data, key, _pool));
}
MemoryPool* _pool;

View File

@ -0,0 +1,61 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Polyfills/attributes.hpp"
#include "../Polyfills/type_traits.hpp"
#include "../Strings/StringWrappers.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename TParent, typename TKey>
class MemberProxy;
template <typename TObject>
class ObjectShortcuts {
public:
// MemberProxy operator[](TKey) const;
// TKey = const std::string&, const String&
template <typename TKey>
FORCE_INLINE
typename enable_if<IsString<TKey>::value,
MemberProxy<const TObject &, const TKey &> >::type
operator[](const TKey &key) const;
//
// MemberProxy operator[](TKey) const;
// TKey = const char*, const char[N], const __FlashStringHelper*
template <typename TKey>
FORCE_INLINE typename enable_if<IsString<TKey *>::value,
MemberProxy<const TObject &, TKey *> >::type
operator[](TKey *key) const;
// Creates and adds a ArrayRef.
//
// ArrayRef createNestedArray(TKey);
// TKey = const std::string&, const String&
template <typename TKey>
FORCE_INLINE ArrayRef createNestedArray(const TKey &key) const;
// ArrayRef createNestedArray(TKey);
// TKey = char*, const char*, char[], const char[], const __FlashStringHelper*
template <typename TKey>
FORCE_INLINE ArrayRef createNestedArray(TKey *key) const;
// Creates and adds a ObjectRef.
//
// ObjectRef createNestedObject(TKey);
// TKey = const std::string&, const String&
template <typename TKey>
ObjectRef createNestedObject(const TKey &key) const;
//
// ObjectRef createNestedObject(TKey);
// TKey = char*, const char*, char[], const char[], const __FlashStringHelper*
template <typename TKey>
ObjectRef createNestedObject(TKey *key) const;
private:
const TObject *impl() const {
return static_cast<const TObject *>(this);
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -7,7 +7,7 @@
#include "VariantCasts.hpp"
#include "VariantComparisons.hpp"
#include "VariantOr.hpp"
#include "VariantSubscripts.hpp"
#include "VariantShortcuts.hpp"
namespace ARDUINOJSON_NAMESPACE {
@ -15,5 +15,5 @@ template <typename TImpl>
class VariantOperators : public VariantCasts<TImpl>,
public VariantComparisons<TImpl>,
public VariantOr<TImpl>,
public VariantSubscripts<TImpl> {};
public VariantShortcuts<TImpl> {};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -0,0 +1,23 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Array/ArrayShortcuts.hpp"
#include "../Object/ObjectShortcuts.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename TVariant>
class VariantShortcuts : public ObjectShortcuts<TVariant>,
public ArrayShortcuts<TVariant> {
public:
using ArrayShortcuts<TVariant>::createNestedArray;
using ArrayShortcuts<TVariant>::createNestedObject;
using ArrayShortcuts<TVariant>::operator[];
using ObjectShortcuts<TVariant>::createNestedArray;
using ObjectShortcuts<TVariant>::createNestedObject;
using ObjectShortcuts<TVariant>::operator[];
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -1,51 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Polyfills/attributes.hpp"
#include "../Polyfills/type_traits.hpp"
#include "../Strings/StringWrappers.hpp"
#include "../Variant/VariantAs.hpp"
namespace ARDUINOJSON_NAMESPACE {
class ArrayRef;
class ObjectRef;
// Forward declarations.
class ArraySubscript;
template <typename TKey>
class ObjectSubscript;
template <typename TImpl>
class VariantSubscripts {
public:
// Mimics an array.
// Returns the element at specified index if the variant is an array.
FORCE_INLINE ArraySubscript operator[](size_t index) const;
// Mimics an object.
// Returns the value associated with the specified key if the variant is
// an object.
//
// ObjectSubscript operator[](TKey) const;
// TKey = const std::string&, const String&
template <typename TKey>
FORCE_INLINE typename enable_if<IsString<TKey>::value,
ObjectSubscript<const TKey &> >::type
operator[](const TKey &key) const;
//
// ObjectSubscript operator[](TKey) const;
// TKey = const char*, const char[N], const __FlashStringHelper*
template <typename TKey>
FORCE_INLINE typename enable_if<IsString<TKey *>::value,
ObjectSubscript<TKey *> >::type
operator[](TKey *key) const;
private:
const TImpl *impl() const {
return static_cast<const TImpl *>(this);
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -12,19 +12,24 @@
namespace ARDUINOJSON_NAMESPACE {
//
enum {
VALUE_IS_NULL = 0,
VALUE_IS_LINKED_RAW,
VALUE_IS_OWNED_RAW,
VALUE_IS_LINKED_STRING,
VALUE_IS_OWNED_STRING,
VALUE_IS_BOOLEAN,
VALUE_IS_POSITIVE_INTEGER,
VALUE_IS_NEGATIVE_INTEGER,
VALUE_IS_ARRAY,
VALUE_IS_OBJECT,
VALUE_IS_FLOAT,
VALUE_MASK = 0x7F,
VALUE_IS_NULL = 0,
VALUE_IS_LINKED_RAW = 0x01,
VALUE_IS_OWNED_RAW = 0x02,
VALUE_IS_LINKED_STRING = 0x03,
VALUE_IS_OWNED_STRING = 0x04,
VALUE_IS_BOOLEAN = 0x05,
VALUE_IS_POSITIVE_INTEGER = 0x06,
VALUE_IS_NEGATIVE_INTEGER = 0x07,
VALUE_IS_FLOAT = 0x08,
COLLECTION_MASK = 0x60,
VALUE_IS_OBJECT = 0x20,
VALUE_IS_ARRAY = 0x40,
KEY_IS_OWNED = 0x80
};

View File

@ -67,7 +67,7 @@ class VariantData {
}
CollectionData *asArray() {
return type() == VALUE_IS_ARRAY ? &_content.asCollection : 0;
return isArray() ? &_content.asCollection : 0;
}
const CollectionData *asArray() const {
@ -75,7 +75,7 @@ class VariantData {
}
CollectionData *asObject() {
return type() == VALUE_IS_OBJECT ? &_content.asCollection : 0;
return isObject() ? &_content.asCollection : 0;
}
const CollectionData *asObject() const {
@ -135,13 +135,17 @@ class VariantData {
}
bool isArray() const {
return type() == VALUE_IS_ARRAY;
return (_flags & VALUE_IS_ARRAY) != 0;
}
bool isBoolean() const {
return type() == VALUE_IS_BOOLEAN;
}
bool isCollection() const {
return (_flags & COLLECTION_MASK) != 0;
}
bool isInteger() const {
return type() == VALUE_IS_POSITIVE_INTEGER ||
type() == VALUE_IS_NEGATIVE_INTEGER;
@ -153,12 +157,11 @@ class VariantData {
}
bool isString() const {
return (type() == VALUE_IS_LINKED_STRING ||
type() == VALUE_IS_OWNED_STRING);
return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING;
}
bool isObject() const {
return type() == VALUE_IS_OBJECT;
return (_flags & VALUE_IS_OBJECT) != 0;
}
bool isNull() const {
@ -275,20 +278,35 @@ class VariantData {
}
size_t nesting() const {
switch (type()) {
case VALUE_IS_OBJECT:
case VALUE_IS_ARRAY:
return _content.asCollection.nesting();
default:
return 0;
}
return isCollection() ? _content.asCollection.nesting() : 0;
}
size_t size() const {
if (type() == VALUE_IS_OBJECT || type() == VALUE_IS_ARRAY)
return _content.asCollection.size();
else
return 0;
return isCollection() ? _content.asCollection.size() : 0;
}
VariantData *get(size_t index) const {
return isArray() ? _content.asCollection.get(index) : 0;
}
template <typename TKey>
VariantData *get(TKey key) const {
return isObject() ? _content.asCollection.get(key) : 0;
}
template <typename TKey>
VariantData *getOrCreate(TKey key, MemoryPool *pool) {
if (isNull()) toObject();
if (!isObject()) return 0;
VariantData *var = _content.asCollection.get(key);
if (var) return var;
return _content.asCollection.add(key, pool);
}
VariantData *add(MemoryPool *pool) {
if (isNull()) toArray();
if (!isArray()) return 0;
return _content.asCollection.add(pool);
}
private:

View File

@ -146,4 +146,20 @@ inline CollectionData *variantToObject(VariantData *var) {
return &var->toObject();
}
inline NO_INLINE VariantData *variantAdd(VariantData *var, MemoryPool *pool) {
return var != 0 ? var->add(pool) : 0;
}
template <typename TKey>
NO_INLINE VariantData *variantGetOrCreate(VariantData *var, TKey *key,
MemoryPool *pool) {
return var != 0 ? var->getOrCreate(wrapString(key), pool) : 0;
}
template <typename TKey>
NO_INLINE VariantData *variantGetOrCreate(VariantData *var, const TKey &key,
MemoryPool *pool) {
return var != 0 ? var->getOrCreate(wrapString(key), pool) : 0;
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -50,7 +50,7 @@ inline T VariantData::asFloat() const {
}
}
inline const char* VariantData::asString() const {
inline const char *VariantData::asString() const {
switch (type()) {
case VALUE_IS_LINKED_STRING:
case VALUE_IS_OWNED_STRING:
@ -60,37 +60,11 @@ inline const char* VariantData::asString() const {
}
}
inline bool VariantRef::set(ArrayRef array) const {
return to<ArrayRef>().copyFrom(array);
}
inline bool VariantRef::set(ArrayConstRef array) const {
return to<ArrayRef>().copyFrom(array);
}
inline bool VariantRef::set(const ArraySubscript& value) const {
return set(value.as<VariantRef>());
}
inline bool VariantRef::set(ObjectRef object) const {
return to<ObjectRef>().copyFrom(object);
}
inline bool VariantRef::set(ObjectConstRef object) const {
return to<ObjectRef>().copyFrom(object);
}
template <typename TString>
inline bool VariantRef::set(const ObjectSubscript<TString>& value) const {
return set(value.template as<VariantRef>());
}
inline bool VariantRef::set(VariantConstRef value) const {
return variantCopyFrom(_data, value._data, _pool);
}
inline bool VariantRef::set(VariantRef value) const {
return variantCopyFrom(_data, value._data, _pool);
template <typename TVariant>
typename enable_if<IsVisitable<TVariant>::value, bool>::type VariantRef::set(
const TVariant &value) const {
VariantConstRef v = value;
return variantCopyFrom(_data, v._data, _pool);
}
template <typename T>
@ -128,4 +102,32 @@ inline VariantConstRef VariantConstRef::operator[](size_t index) const {
return ArrayConstRef(_data != 0 ? _data->asArray() : 0)[index];
}
inline VariantRef VariantRef::add() const {
return VariantRef(_pool, variantAdd(_data, _pool));
}
inline VariantRef VariantRef::get(size_t index) const {
return VariantRef(_pool, _data != 0 ? _data->get(index) : 0);
}
template <typename TKey>
inline VariantRef VariantRef::get(TKey *key) const {
return VariantRef(_pool, _data != 0 ? _data->get(wrapString(key)) : 0);
}
template <typename TKey>
inline typename enable_if<IsString<TKey>::value, VariantRef>::type
VariantRef::get(const TKey &key) const {
return VariantRef(_pool, _data != 0 ? _data->get(wrapString(key)) : 0);
}
template <typename TKey>
inline VariantRef VariantRef::getOrCreate(TKey *key) const {
return VariantRef(_pool, variantGetOrCreate(_data, key, _pool));
}
template <typename TKey>
inline VariantRef VariantRef::getOrCreate(const TKey &key) const {
return VariantRef(_pool, variantGetOrCreate(_data, key, _pool));
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -23,6 +23,9 @@ namespace ARDUINOJSON_NAMESPACE {
class ArrayRef;
class ObjectRef;
template <typename, typename>
class MemberProxy;
// Contains the methods shared by VariantRef and VariantConstRef
template <typename TData>
class VariantRefBase {
@ -207,16 +210,15 @@ class VariantRef : public VariantRefBase<VariantData>,
return variantSetLinkedString(_data, value);
}
bool set(VariantConstRef value) const;
bool set(VariantRef value) const;
FORCE_INLINE bool set(ArrayRef array) const;
FORCE_INLINE bool set(ArrayConstRef array) const;
FORCE_INLINE bool set(const ArraySubscript &) const;
FORCE_INLINE bool set(ObjectRef object) const;
FORCE_INLINE bool set(ObjectConstRef object) const;
template <typename TString>
FORCE_INLINE bool set(const ObjectSubscript<TString> &) const;
// set(VariantRef)
// set(VariantConstRef)
// set(ArrayRef)
// set(ArrayConstRef)
// set(ObjectRef)
// set(ObjecConstRef)
template <typename TVariant>
typename enable_if<IsVisitable<TVariant>::value, bool>::type set(
const TVariant &value) const;
// Get the variant as the specified type.
//
@ -278,6 +280,26 @@ class VariantRef : public VariantRefBase<VariantData>,
typename enable_if<is_same<T, VariantRef>::value, VariantRef>::type to()
const;
VariantRef add() const;
using ArrayShortcuts::add;
FORCE_INLINE VariantRef get(size_t) const;
template <typename TKey>
FORCE_INLINE VariantRef get(TKey *) const;
// get(const char*)
// get(const __FlashStringHelper*)
template <typename TKey>
FORCE_INLINE typename enable_if<IsString<TKey>::value, VariantRef>::type get(
const TKey &) const;
template <typename TKey>
FORCE_INLINE VariantRef getOrCreate(TKey *) const;
template <typename TKey>
FORCE_INLINE VariantRef getOrCreate(const TKey &) const;
private:
MemoryPool *_pool;
};

View File

@ -71,6 +71,7 @@ if(MSVC)
)
endif()
add_subdirectory(ElementProxy)
add_subdirectory(IntegrationTests)
add_subdirectory(JsonArray)
add_subdirectory(JsonDeserializer)
@ -78,10 +79,11 @@ add_subdirectory(JsonDocument)
add_subdirectory(JsonObject)
add_subdirectory(JsonSerializer)
add_subdirectory(JsonVariant)
add_subdirectory(TextFormatter)
add_subdirectory(MemberProxy)
add_subdirectory(MemoryPool)
add_subdirectory(Misc)
add_subdirectory(MixedConfiguration)
add_subdirectory(MsgPackDeserializer)
add_subdirectory(MsgPackSerializer)
add_subdirectory(Numbers)
add_subdirectory(TextFormatter)

View File

@ -0,0 +1,11 @@
# ArduinoJson - arduinojson.org
# Copyright Benoit Blanchon 2014-2018
# MIT License
add_executable(ElementProxyTests
add.cpp
set.cpp
)
target_link_libraries(ElementProxyTests catch)
add_test(ElementProxy ElementProxyTests)

26
test/ElementProxy/add.cpp Normal file
View File

@ -0,0 +1,26 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
using namespace ARDUINOJSON_NAMESPACE;
TEST_CASE("ElementProxy::add()") {
DynamicJsonDocument doc(4096);
doc.add();
ElementProxy<JsonDocument&> ep = doc[0];
SECTION("add(int)") {
ep.add(42);
REQUIRE(doc.as<std::string>() == "[[42]]");
}
SECTION("add(const char*)") {
ep.add("world");
REQUIRE(doc.as<std::string>() == "[[\"world\"]]");
}
}

26
test/ElementProxy/set.cpp Normal file
View File

@ -0,0 +1,26 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
using namespace ARDUINOJSON_NAMESPACE;
TEST_CASE("ElementProxy::set()") {
DynamicJsonDocument doc(4096);
doc.add();
ElementProxy<JsonDocument&> ep = doc[0];
SECTION("set(int)") {
ep.set(42);
REQUIRE(doc.as<std::string>() == "[42]");
}
SECTION("set(const char*)") {
ep.set("world");
REQUIRE(doc.as<std::string>() == "[\"world\"]");
}
}

View File

@ -3,9 +3,11 @@
# MIT License
add_executable(JsonDocumentTests
add.cpp
createNested.cpp
DynamicJsonDocument.cpp
nesting.cpp
isNull.cpp
nesting.cpp
StaticJsonDocument.cpp
subscript.cpp
)

22
test/JsonDocument/add.cpp Normal file
View File

@ -0,0 +1,22 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonDocument::add()") {
DynamicJsonDocument doc(4096);
SECTION("integer") {
doc.add(42);
REQUIRE(doc.as<std::string>() == "[42]");
}
SECTION("const char*") {
doc.add("hello");
REQUIRE(doc.as<std::string>() == "[\"hello\"]");
}
}

View File

@ -0,0 +1,66 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonDocument::createNestedArray()") {
DynamicJsonDocument doc(4096);
SECTION("promotes to array") {
doc.createNestedArray();
REQUIRE(doc.is<JsonArray>());
}
}
TEST_CASE("JsonDocument::createNestedArray(key)") {
DynamicJsonDocument doc(4096);
SECTION("key is const char*") {
SECTION("promotes to object") {
doc.createNestedArray("hello");
REQUIRE(doc.is<JsonObject>());
}
}
SECTION("key is std::string") {
SECTION("promotes to object") {
doc.createNestedArray(std::string("hello"));
REQUIRE(doc.is<JsonObject>());
}
}
}
TEST_CASE("JsonDocument::createNestedObject()") {
DynamicJsonDocument doc(4096);
SECTION("promotes to array") {
doc.createNestedObject();
REQUIRE(doc.is<JsonArray>());
}
}
TEST_CASE("JsonDocument::createNestedObject(key)") {
DynamicJsonDocument doc(4096);
SECTION("key is const char*") {
SECTION("promotes to object") {
doc.createNestedObject("hello");
REQUIRE(doc.is<JsonObject>());
}
}
SECTION("key is std::string") {
SECTION("promotes to object") {
doc.createNestedObject(std::string("hello"));
REQUIRE(doc.is<JsonObject>());
}
}
}

View File

@ -21,6 +21,11 @@ TEST_CASE("JsonDocument::operator[]") {
REQUIRE(doc[std::string("hello")] == "world");
REQUIRE(cdoc[std::string("hello")] == "world");
}
SECTION("supports operator|") {
REQUIRE((doc["hello"] | "nope") == std::string("world"));
REQUIRE((doc["world"] | "nope") == std::string("nope"));
}
}
SECTION("array") {
@ -30,3 +35,11 @@ TEST_CASE("JsonDocument::operator[]") {
REQUIRE(cdoc[1] == "world");
}
}
TEST_CASE("JsonDocument automatically promotes to object") {
DynamicJsonDocument doc(4096);
doc["one"]["two"]["three"] = 4;
REQUIRE(doc["one"]["two"]["three"] == 4);
}

View File

@ -12,7 +12,7 @@ void check(T value, const std::string &expected) {
REQUIRE(expected.size() == returnValue);
}
TEST_CASE("serializeJson(JsonObjectSubscript)") {
TEST_CASE("serializeJson(MemberProxy)") {
DynamicJsonDocument doc(4096);
deserializeJson(doc, "{\"hello\":42}");
JsonObject obj = doc.as<JsonObject>();
@ -23,7 +23,7 @@ TEST_CASE("serializeJson(JsonObjectSubscript)") {
REQUIRE(result == "42");
}
TEST_CASE("serializeJson(JsonArraySubscript)") {
TEST_CASE("serializeJson(ElementProxy)") {
DynamicJsonDocument doc(4096);
deserializeJson(doc, "[42]");
JsonArray arr = doc.as<JsonArray>();

View File

@ -37,7 +37,7 @@ TEST_CASE("operator<<(std::ostream)") {
REQUIRE("{\"key\":\"value\"}" == os.str());
}
SECTION("JsonObjectSubscript") {
SECTION("MemberProxy") {
JsonObject object = doc.to<JsonObject>();
object["key"] = "value";
@ -55,7 +55,7 @@ TEST_CASE("operator<<(std::ostream)") {
REQUIRE("[\"value\"]" == os.str());
}
SECTION("JsonArraySubscript") {
SECTION("ElementProxy") {
JsonArray array = doc.to<JsonArray>();
array.add("value");

View File

@ -3,18 +3,21 @@
# MIT License
add_executable(JsonVariantTests
add.cpp
as.cpp
compare.cpp
copy.cpp
createNested.cpp
get.cpp
is.cpp
isnull.cpp
memoryUsage.cpp
nesting.cpp
misc.cpp
nesting.cpp
or.cpp
set.cpp
subscript.cpp
types.cpp
undefined.cpp
)

39
test/JsonVariant/add.cpp Normal file
View File

@ -0,0 +1,39 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <stdint.h>
#include <catch.hpp>
static const char* null = 0;
TEST_CASE("JsonVariant::add()") {
DynamicJsonDocument doc(4096);
JsonVariant var = doc.to<JsonVariant>();
SECTION("No argument") {
JsonVariant nested = var.add();
REQUIRE(var.is<JsonArray>() == true);
REQUIRE(nested.isNull() == true);
}
SECTION("integer") {
var.add(42);
REQUIRE(var.as<std::string>() == "[42]");
}
SECTION("const char*") {
var.add("hello");
REQUIRE(var.as<std::string>() == "[\"hello\"]");
}
SECTION("std::string") {
var.add(std::string("hello"));
REQUIRE(var.as<std::string>() == "[\"hello\"]");
}
}

View File

@ -0,0 +1,88 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <stdint.h>
#include <catch.hpp>
static const char* null = 0;
TEST_CASE("JsonVariant::createNestedObject()") {
DynamicJsonDocument doc(4096);
JsonVariant variant = doc.to<JsonVariant>();
SECTION("promotes to array") {
JsonObject obj = variant.createNestedObject();
obj["value"] = "42";
REQUIRE(variant.is<JsonArray>() == true);
REQUIRE(variant[0]["value"] == 42);
REQUIRE(obj.isNull() == false);
}
SECTION("works on MemberProxy") {
JsonObject obj = variant["items"].createNestedObject();
obj["value"] = "42";
REQUIRE(variant["items"][0]["value"] == 42);
}
}
TEST_CASE("JsonVariant::createNestedArray()") {
DynamicJsonDocument doc(4096);
JsonVariant variant = doc.to<JsonVariant>();
SECTION("promotes to array") {
JsonArray arr = variant.createNestedArray();
REQUIRE(variant.is<JsonArray>() == true);
REQUIRE(arr.isNull() == false);
}
SECTION("works on MemberProxy") {
JsonArray arr = variant["items"].createNestedArray();
arr.add("42");
REQUIRE(variant["items"][0][0] == 42);
}
}
TEST_CASE("JsonVariant::createNestedObject(key)") {
DynamicJsonDocument doc(4096);
JsonVariant variant = doc.to<JsonVariant>();
SECTION("promotes to object") {
JsonObject obj = variant.createNestedObject("weather");
obj["temp"] = "42";
REQUIRE(variant.is<JsonObject>() == true);
REQUIRE(variant["weather"]["temp"] == 42);
}
SECTION("works on MemberProxy") {
JsonObject obj = variant["status"].createNestedObject("weather");
obj["temp"] = "42";
REQUIRE(variant["status"]["weather"]["temp"] == 42);
}
}
TEST_CASE("JsonVariant::createNestedArray(key)") {
DynamicJsonDocument doc(4096);
JsonVariant variant = doc.to<JsonVariant>();
SECTION("promotes to object") {
JsonArray arr = variant.createNestedArray("items");
REQUIRE(variant.is<JsonObject>() == true);
REQUIRE(arr.isNull() == false);
}
SECTION("works on MemberProxy") {
JsonArray arr = variant["weather"].createNestedArray("temp");
arr.add("42");
REQUIRE(variant["weather"]["temp"][0] == 42);
}
}

View File

@ -3,138 +3,27 @@
// MIT License
#include <ArduinoJson.h>
#include <stdint.h>
#include <catch.hpp>
#include <limits>
template <typename T>
void checkValue(T expected) {
TEST_CASE("JsonVariant::get()") {
DynamicJsonDocument doc(4096);
JsonVariant variant = doc.to<JsonVariant>();
JsonVariant var = doc.to<JsonVariant>();
variant.set(expected);
REQUIRE(expected == variant.as<T>());
}
SECTION("get(const char*)") {
var["value"] = 42;
template <typename T>
void checkReference(T &expected) {
JsonVariant variant = expected;
REQUIRE(expected == variant.as<T &>());
}
template <typename T>
void checkNumericType() {
DynamicJsonDocument docMin(4096), docMax(4096);
JsonVariant variantMin = docMin.to<JsonVariant>();
JsonVariant variantMax = docMax.to<JsonVariant>();
T min = std::numeric_limits<T>::min();
T max = std::numeric_limits<T>::max();
variantMin.set(min);
variantMax.set(max);
REQUIRE(min == variantMin.as<T>());
REQUIRE(max == variantMax.as<T>());
}
TEST_CASE("JsonVariant set()/get()") {
#if ARDUINOJSON_USE_LONG_LONG
SECTION("SizeOfJsonInteger") {
REQUIRE(8 == sizeof(JsonInteger));
}
#endif
SECTION("Null") {
checkValue<const char *>(NULL);
}
SECTION("const char*") {
checkValue<const char *>("hello");
}
SECTION("std::string") {
checkValue<std::string>("hello");
REQUIRE(var.get("value") == 42);
}
SECTION("False") {
checkValue<bool>(false);
}
SECTION("True") {
checkValue<bool>(true);
SECTION("get(std::string)") {
var["value"] = 42;
REQUIRE(var.get(std::string("value")) == 42);
}
SECTION("Double") {
checkNumericType<double>();
}
SECTION("Float") {
checkNumericType<float>();
}
SECTION("Char") {
checkNumericType<char>();
}
SECTION("SChar") {
checkNumericType<signed char>();
}
SECTION("SInt") {
checkNumericType<signed int>();
}
SECTION("SLong") {
checkNumericType<signed long>();
}
SECTION("SShort") {
checkNumericType<signed short>();
}
SECTION("UChar") {
checkNumericType<unsigned char>();
}
SECTION("UInt") {
checkNumericType<unsigned int>();
}
SECTION("ULong") {
checkNumericType<unsigned long>();
}
SECTION("UShort") {
checkNumericType<unsigned short>();
}
#if ARDUINOJSON_USE_LONG_LONG
SECTION("LongLong") {
checkNumericType<unsigned long long>();
}
SECTION("ULongLong") {
checkNumericType<unsigned long long>();
}
#endif
SECTION("get(int)") {
var.add().set(42);
SECTION("Int8") {
checkNumericType<int8_t>();
}
SECTION("Uint8") {
checkNumericType<uint8_t>();
}
SECTION("Int16") {
checkNumericType<int16_t>();
}
SECTION("Uint16") {
checkNumericType<uint16_t>();
}
SECTION("Int32") {
checkNumericType<int32_t>();
}
SECTION("Uint32") {
checkNumericType<uint32_t>();
}
#if ARDUINOJSON_USE_LONG_LONG
SECTION("Int64") {
checkNumericType<int64_t>();
}
SECTION("Uint64") {
checkNumericType<uint64_t>();
}
#endif
SECTION("CanStoreObject") {
DynamicJsonDocument doc(4096);
JsonObject object = doc.to<JsonObject>();
checkValue<JsonObject>(object);
REQUIRE(var.get(0) == 42);
}
}

View File

@ -30,7 +30,8 @@ TEST_CASE("JsonVariant::operator[]") {
array.add("element at index 1");
REQUIRE(2 == var.size());
REQUIRE(std::string("element at index 0") == var[0]);
var[0].as<std::string>();
// REQUIRE(std::string("element at index 0") == );
REQUIRE(std::string("element at index 1") == var[1]);
REQUIRE(std::string("element at index 0") ==
var[static_cast<unsigned char>(0)]); // issue #381
@ -171,4 +172,24 @@ TEST_CASE("JsonVariantConst::operator[]") {
REQUIRE(cvar[0].isNull());
}
}
SECTION("Auto promote null JsonVariant to JsonObject") {
var["hello"] = "world";
REQUIRE(var.is<JsonObject>() == true);
}
SECTION("Don't auto promote non-null JsonVariant to JsonObject") {
var.set(42);
var["hello"] = "world";
REQUIRE(var.is<JsonObject>() == false);
}
SECTION("Don't auto promote null JsonVariant to JsonObject when reading") {
const char* value = var["hello"];
REQUIRE(var.is<JsonObject>() == false);
REQUIRE(value == 0);
}
}

140
test/JsonVariant/types.cpp Normal file
View File

@ -0,0 +1,140 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <stdint.h>
#include <catch.hpp>
#include <limits>
template <typename T>
void checkValue(T expected) {
DynamicJsonDocument doc(4096);
JsonVariant variant = doc.to<JsonVariant>();
variant.set(expected);
REQUIRE(expected == variant.as<T>());
}
template <typename T>
void checkReference(T &expected) {
JsonVariant variant = expected;
REQUIRE(expected == variant.as<T &>());
}
template <typename T>
void checkNumericType() {
DynamicJsonDocument docMin(4096), docMax(4096);
JsonVariant variantMin = docMin.to<JsonVariant>();
JsonVariant variantMax = docMax.to<JsonVariant>();
T min = std::numeric_limits<T>::min();
T max = std::numeric_limits<T>::max();
variantMin.set(min);
variantMax.set(max);
REQUIRE(min == variantMin.as<T>());
REQUIRE(max == variantMax.as<T>());
}
TEST_CASE("JsonVariant set()/get()") {
#if ARDUINOJSON_USE_LONG_LONG
SECTION("SizeOfJsonInteger") {
REQUIRE(8 == sizeof(JsonInteger));
}
#endif
SECTION("Null") {
checkValue<const char *>(NULL);
}
SECTION("const char*") {
checkValue<const char *>("hello");
}
SECTION("std::string") {
checkValue<std::string>("hello");
}
SECTION("False") {
checkValue<bool>(false);
}
SECTION("True") {
checkValue<bool>(true);
}
SECTION("Double") {
checkNumericType<double>();
}
SECTION("Float") {
checkNumericType<float>();
}
SECTION("Char") {
checkNumericType<char>();
}
SECTION("SChar") {
checkNumericType<signed char>();
}
SECTION("SInt") {
checkNumericType<signed int>();
}
SECTION("SLong") {
checkNumericType<signed long>();
}
SECTION("SShort") {
checkNumericType<signed short>();
}
SECTION("UChar") {
checkNumericType<unsigned char>();
}
SECTION("UInt") {
checkNumericType<unsigned int>();
}
SECTION("ULong") {
checkNumericType<unsigned long>();
}
SECTION("UShort") {
checkNumericType<unsigned short>();
}
#if ARDUINOJSON_USE_LONG_LONG
SECTION("LongLong") {
checkNumericType<unsigned long long>();
}
SECTION("ULongLong") {
checkNumericType<unsigned long long>();
}
#endif
SECTION("Int8") {
checkNumericType<int8_t>();
}
SECTION("Uint8") {
checkNumericType<uint8_t>();
}
SECTION("Int16") {
checkNumericType<int16_t>();
}
SECTION("Uint16") {
checkNumericType<uint16_t>();
}
SECTION("Int32") {
checkNumericType<int32_t>();
}
SECTION("Uint32") {
checkNumericType<uint32_t>();
}
#if ARDUINOJSON_USE_LONG_LONG
SECTION("Int64") {
checkNumericType<int64_t>();
}
SECTION("Uint64") {
checkNumericType<uint64_t>();
}
#endif
SECTION("CanStoreObject") {
DynamicJsonDocument doc(4096);
JsonObject object = doc.to<JsonObject>();
checkValue<JsonObject>(object);
}
}

View File

@ -0,0 +1,12 @@
# ArduinoJson - arduinojson.org
# Copyright Benoit Blanchon 2014-2018
# MIT License
add_executable(MemberProxyTests
add.cpp
subscript.cpp
set.cpp
)
target_link_libraries(MemberProxyTests catch)
add_test(MemberProxy MemberProxyTests)

25
test/MemberProxy/add.cpp Normal file
View File

@ -0,0 +1,25 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
using namespace ARDUINOJSON_NAMESPACE;
TEST_CASE("MemberProxy::add()") {
DynamicJsonDocument doc(4096);
MemberProxy<JsonDocument&, const char*> mp = doc["hello"];
SECTION("add(int)") {
mp.add(42);
REQUIRE(doc.as<std::string>() == "{\"hello\":[42]}");
}
SECTION("add(const char*)") {
mp.add("world");
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
}
}

25
test/MemberProxy/set.cpp Normal file
View File

@ -0,0 +1,25 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
using namespace ARDUINOJSON_NAMESPACE;
TEST_CASE("MemberProxy::set()") {
DynamicJsonDocument doc(4096);
MemberProxy<JsonDocument&, const char*> mp = doc["hello"];
SECTION("set(int)") {
mp.set(42);
REQUIRE(doc.as<std::string>() == "{\"hello\":42}");
}
SECTION("set(const char*)") {
mp.set("world");
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\"}");
}
}

View File

@ -0,0 +1,19 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
using namespace ARDUINOJSON_NAMESPACE;
TEST_CASE("MemberProxy::operator[]") {
DynamicJsonDocument doc(4096);
MemberProxy<JsonDocument&, const char*> mp = doc["hello"];
SECTION("set integer") {
mp["world"] = 42;
REQUIRE(doc.as<std::string>() == "{\"hello\":{\"world\":42}}");
}
}

View File

@ -54,10 +54,10 @@ TEST_CASE("Polyfills/type_traits") {
CHECK(IsVisitable<VariantRef>::value == true);
CHECK(IsVisitable<VariantConstRef>::value == true);
CHECK(IsVisitable<ArrayRef>::value == true);
CHECK(IsVisitable<ArraySubscript>::value == true);
CHECK(IsVisitable<ElementProxy<ArrayRef> >::value == true);
CHECK(IsVisitable<ArrayConstRef>::value == true);
CHECK(IsVisitable<ObjectRef>::value == true);
CHECK(IsVisitable<ObjectSubscript<const char*> >::value == true);
CHECK((IsVisitable<MemberProxy<ObjectRef, const char*> >::value == true));
CHECK(IsVisitable<ObjectConstRef>::value == true);
CHECK(IsVisitable<DynamicJsonDocument>::value == true);
CHECK(IsVisitable<StaticJsonDocument<10> >::value == true);

View File

@ -147,7 +147,7 @@ TEST_CASE("unsigned char[]") {
}
}
SECTION("JsonObjectSubscript") {
SECTION("MemberProxy") {
SECTION("operator=") { // issue #416
unsigned char value[] = "world";
@ -181,7 +181,7 @@ TEST_CASE("unsigned char[]") {
}
}
SECTION("JsonArraySubscript") {
SECTION("ElementProxy") {
SECTION("set()") {
unsigned char value[] = "world";

View File

@ -12,7 +12,7 @@ void check(T value, const std::string &expected) {
REQUIRE(expected.size() == returnValue);
}
TEST_CASE("serializeMsgPack(JsonObjectSubscript)") {
TEST_CASE("serializeMsgPack(MemberProxy)") {
DynamicJsonDocument doc(4096);
deserializeJson(doc, "{\"hello\":42}");
JsonObject obj = doc.as<JsonObject>();
@ -23,7 +23,7 @@ TEST_CASE("serializeMsgPack(JsonObjectSubscript)") {
REQUIRE(result == "*");
}
TEST_CASE("serializeMsgPack(JsonArraySubscript)") {
TEST_CASE("serializeMsgPack(ElementProxy)") {
DynamicJsonDocument doc(4096);
deserializeJson(doc, "[42]");
JsonArray arr = doc.as<JsonArray>();