mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 08:42:39 +01:00 
			
		
		
		
	JsonVariant automatically promotes to JsonObject or JsonArray on write
This commit is contained in:
		| @@ -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 | ||||
| >  | ||||
|   | ||||
| @@ -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 JsonObject to the Config | ||||
|   config.port = root["port"] | 2731; | ||||
|   // Copy values from the JsonDocument to the Config | ||||
|   config.port = doc["port"] | 2731; | ||||
|   strlcpy(config.hostname,                  // <- destination | ||||
|           root["hostname"] | "example.com",  // <- source | ||||
|           doc["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(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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: | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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" | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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); | ||||
|   } | ||||
|   | ||||
							
								
								
									
										47
									
								
								src/ArduinoJson/Array/ArrayShortcuts.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/ArduinoJson/Array/ArrayShortcuts.hpp
									
									
									
									
									
										Normal 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 | ||||
| @@ -13,14 +13,18 @@ | ||||
| #endif | ||||
| 
 | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
| class ArraySubscript : public VariantOperators<ArraySubscript>, | ||||
| 
 | ||||
| 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 | ||||
| @@ -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 | ||||
|       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 getVariant()[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: | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -15,21 +15,21 @@ | ||||
| 
 | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
| 
 | ||||
| template <typename TStringRef> | ||||
| class ObjectSubscript : public VariantOperators<ObjectSubscript<TStringRef> >, | ||||
| template <typename TObject, typename TString> | ||||
| class MemberProxy : public VariantOperators<MemberProxy<TObject, TString> >, | ||||
|                     public Visitable { | ||||
|   typedef ObjectSubscript<TStringRef> this_type; | ||||
|   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
 | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
							
								
								
									
										61
									
								
								src/ArduinoJson/Object/ObjectShortcuts.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/ArduinoJson/Object/ObjectShortcuts.hpp
									
									
									
									
									
										Normal 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 | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										23
									
								
								src/ArduinoJson/Operators/VariantShortcuts.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/ArduinoJson/Operators/VariantShortcuts.hpp
									
									
									
									
									
										Normal 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 | ||||
| @@ -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 | ||||
| @@ -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 | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -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: | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
| }; | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
							
								
								
									
										11
									
								
								test/ElementProxy/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								test/ElementProxy/CMakeLists.txt
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										26
									
								
								test/ElementProxy/add.cpp
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										26
									
								
								test/ElementProxy/set.cpp
									
									
									
									
									
										Normal 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\"]"); | ||||
|   } | ||||
| } | ||||
| @@ -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
									
								
							
							
						
						
									
										22
									
								
								test/JsonDocument/add.cpp
									
									
									
									
									
										Normal 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\"]"); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										66
									
								
								test/JsonDocument/createNested.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								test/JsonDocument/createNested.cpp
									
									
									
									
									
										Normal 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>()); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -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); | ||||
| } | ||||
|   | ||||
| @@ -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>(); | ||||
|   | ||||
| @@ -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"); | ||||
|  | ||||
|   | ||||
| @@ -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
									
								
							
							
						
						
									
										39
									
								
								test/JsonVariant/add.cpp
									
									
									
									
									
										Normal 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\"]"); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										88
									
								
								test/JsonVariant/createNested.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								test/JsonVariant/createNested.cpp
									
									
									
									
									
										Normal 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); | ||||
|   } | ||||
| } | ||||
| @@ -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); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -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
									
								
							
							
						
						
									
										140
									
								
								test/JsonVariant/types.cpp
									
									
									
									
									
										Normal 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); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										12
									
								
								test/MemberProxy/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								test/MemberProxy/CMakeLists.txt
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										25
									
								
								test/MemberProxy/add.cpp
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										25
									
								
								test/MemberProxy/set.cpp
									
									
									
									
									
										Normal 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\"}"); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										19
									
								
								test/MemberProxy/subscript.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								test/MemberProxy/subscript.cpp
									
									
									
									
									
										Normal 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}}"); | ||||
|   } | ||||
| } | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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"; | ||||
|  | ||||
|   | ||||
| @@ -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>(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user