Templatized all functions using String or std::string

* Removed `ArduinoJson::String`
* Removed `JsonVariant::defaultValue<T>()`
* Removed non-template `JsonObject::get()` and `JsonArray.get()`
* Fixed support for `StringSumHelper` (issue #184)
* Replaced `ARDUINOJSON_USE_ARDUINO_STRING` by `ARDUINOJSON_ENABLE_STD_STRING` and `ARDUINOJSON_ENABLE_ARDUINO_STRING` (issue #378)
* Added example `StringExample.ino` to show where `String` can be used
This commit is contained in:
Benoit Blanchon
2016-11-06 17:48:32 +01:00
parent 7ad57f1c33
commit aa2ef79e55
31 changed files with 622 additions and 545 deletions

View File

@ -4,8 +4,37 @@ ArduinoJson: change log
HEAD HEAD
---- ----
* Templatized all functions using `String` or `std::string`
* Removed `ArduinoJson::String`
* Removed `JsonVariant::defaultValue<T>()`
* Removed non-template `JsonObject::get()` and `JsonArray.get()`
* Fixed support for `StringSumHelper` (issue #184)
* Replaced `ARDUINOJSON_USE_ARDUINO_STRING` by `ARDUINOJSON_ENABLE_STD_STRING` and `ARDUINOJSON_ENABLE_ARDUINO_STRING` (issue #378)
* Added example `StringExample.ino` to show where `String` can be used
* Increased default nesting limit to 50 when compiled for a computer (issue #349) * Increased default nesting limit to 50 when compiled for a computer (issue #349)
**BREAKING CHANGES**:
The non-template functions `JsonObject::get()` and `JsonArray.get()` have been removed. This means that you need to explicitely tell the type you expect in return.
Old code:
```c++
#define ARDUINOJSON_USE_ARDUINO_STRING 0
JsonVariant value1 = myObject.get("myKey");
JsonVariant value2 = myArray.get(0);
```
New code:
```c++
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
#define ARDUINOJSON_ENABLE_STD_STRING 1
JsonVariant value1 = myObject.get<JsonVariant>("myKey");
JsonVariant value2 = myArray.get<JsonVariant>(0);
```
v5.6.7 v5.6.7
------ ------

View File

@ -0,0 +1,53 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include <ArduinoJson.h>
// About
// -----
// This example shows the different ways you can use String with ArduinoJson.
// Please don't see this as an invitation to use String.
// On the contrary, you should always use char[] when possible, it's much more
// efficient in term of code size, speed and memory usage.
void setup() {
DynamicJsonBuffer jsonBuffer;
// You can use a String as your JSON input.
// WARNING: the content of the String will be duplicated in the JsonBuffer.
String input =
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
JsonObject& root = jsonBuffer.parseObject(input);
// You can use a String to get an element of a JsonObject
// No duplication is done.
long time = root[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.
root[String("time")] = time;
// You can get a String from a JsonObject or JsonArray:
// No duplication is done, at least not in the JsonBuffer.
String sensor = root[String("sensor")];
// You can set a String to a JsonObject or JsonArray:
// WARNING: the content of the String will be duplicated in the JsonBuffer.
root["sensor"] = sensor;
// You can also concatenate strings
// WARNING: the content of the String will be duplicated in the JsonBuffer.
root[String("sen") + "sor"] = String("gp") + "s";
// Lastly, you can print the resulting JSON to a String
String output;
root.printTo(output);
}
void loop() {
// not used in this example
}

View File

@ -22,12 +22,17 @@
#define ARDUINOJSON_USE_INT64 0 #define ARDUINOJSON_USE_INT64 0
#endif #endif
// arduino has its own implementation of String to replace std::string // Arduino has its own implementation of String to replace std::string
#ifndef ARDUINOJSON_USE_ARDUINO_STRING #ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
#define ARDUINOJSON_USE_ARDUINO_STRING 1 #define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
#endif #endif
// arduino doesn't support STL stream // Arduino doesn't have std::string
#ifndef ARDUINOJSON_ENABLE_STD_STRING
#define ARDUINOJSON_ENABLE_STD_STRING 0
#endif
// Arduino doesn't support STL stream
#ifndef ARDUINOJSON_ENABLE_STD_STREAM #ifndef ARDUINOJSON_ENABLE_STD_STREAM
#define ARDUINOJSON_ENABLE_STD_STREAM 0 #define ARDUINOJSON_ENABLE_STD_STREAM 0
#endif #endif
@ -73,8 +78,13 @@
#endif #endif
// on a computer, we can use std::string // on a computer, we can use std::string
#ifndef ARDUINOJSON_USE_ARDUINO_STRING #ifndef ARDUINOJSON_ENABLE_STD_STRING
#define ARDUINOJSON_USE_ARDUINO_STRING 0 #define ARDUINOJSON_ENABLE_STD_STRING 1
#endif
// on a computer, there is no reason to beleive Arduino String is available
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
#endif #endif
// on a computer, we can assume that the STL is there // on a computer, we can assume that the STL is there

View File

@ -8,26 +8,26 @@
#pragma once #pragma once
#include "../Print.hpp" #include "../Print.hpp"
#include "../String.hpp" #include "StringFuncs.hpp"
namespace ArduinoJson { namespace ArduinoJson {
namespace Internals { namespace Internals {
// A Print implementation that allows to write in a String // A Print implementation that allows to write in a String
template <typename TString>
class DynamicStringBuilder : public Print { class DynamicStringBuilder : public Print {
public: public:
DynamicStringBuilder(String &str) : _str(str) {} DynamicStringBuilder(TString &str) : _str(str) {}
virtual size_t write(uint8_t c) { virtual size_t write(uint8_t c) {
// Need to cast to char, otherwise String will print a number (issue #120) StringFuncs<TString>::append(_str, static_cast<char>(c));
_str += static_cast<char>(c);
return 1; return 1;
} }
private: private:
DynamicStringBuilder &operator=(const DynamicStringBuilder &); DynamicStringBuilder &operator=(const DynamicStringBuilder &);
String &_str; TString &_str;
}; };
} }
} }

View File

@ -8,6 +8,7 @@
#pragma once #pragma once
#include "../Configuration.hpp" #include "../Configuration.hpp"
#include "../TypeTraits/EnableIf.hpp"
#include "DummyPrint.hpp" #include "DummyPrint.hpp"
#include "DynamicStringBuilder.hpp" #include "DynamicStringBuilder.hpp"
#include "IndentedPrint.hpp" #include "IndentedPrint.hpp"
@ -49,8 +50,10 @@ class JsonPrintable {
return printTo(sb); return printTo(sb);
} }
size_t printTo(String &str) const { template <typename TString>
DynamicStringBuilder sb(str); typename TypeTraits::EnableIf<StringFuncs<TString>::has_append, size_t>::type
printTo(TString &str) const {
DynamicStringBuilder<TString> sb(str);
return printTo(sb); return printTo(sb);
} }
@ -69,8 +72,10 @@ class JsonPrintable {
return prettyPrintTo(indentedPrint); return prettyPrintTo(indentedPrint);
} }
size_t prettyPrintTo(String &str) const { template <typename TString>
DynamicStringBuilder sb(str); typename TypeTraits::EnableIf<StringFuncs<TString>::has_append, size_t>::type
prettyPrintTo(TString &str) const {
DynamicStringBuilder<TString> sb(str);
return prettyPrintTo(sb); return prettyPrintTo(sb);
} }

View File

@ -8,17 +8,19 @@
#pragma once #pragma once
namespace ArduinoJson { namespace ArduinoJson {
namespace TypeTraits { namespace Internals {
// A meta-function that returns true if T is a reference
template <typename T> template <typename T>
struct IsReference { struct JsonVariantDefault {
static const bool value = false; static T get() {
return T();
}
}; };
template <typename T> template <typename T>
struct IsReference<T&> { struct JsonVariantDefault<const T> : JsonVariantDefault<T> {};
static const bool value = true;
}; template <typename T>
struct JsonVariantDefault<T&> : JsonVariantDefault<T> {};
} }
} }

View File

@ -0,0 +1,94 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#pragma once
#include "../Configuration.hpp"
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <WString.h>
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
#include <string>
#endif
namespace ArduinoJson {
namespace Internals {
template <typename TString>
struct StringFuncs {};
template <typename TString>
struct StringFuncs<const TString> : StringFuncs<TString> {};
template <typename TString>
struct StringFuncs<TString&> : StringFuncs<TString> {};
struct CharPtrFuncs {
static bool equals(const char* str, const char* expected) {
return strcmp(str, expected) == 0;
}
template <typename Buffer>
static char* duplicate(const char* str, Buffer* buffer) {
if (!str) return NULL;
size_t size = strlen(str) + 1;
void* dup = buffer->alloc(size);
if (dup != NULL) memcpy(dup, str, size);
return static_cast<char*>(dup);
}
static const bool has_append = false;
static const bool should_duplicate = false;
};
template <>
struct StringFuncs<const char*> : CharPtrFuncs {};
template <>
struct StringFuncs<char*> : CharPtrFuncs {};
template <size_t N>
struct StringFuncs<char[N]> : CharPtrFuncs {};
template <typename TString>
struct StdStringFuncs {
template <typename Buffer>
static char* duplicate(const TString& str, Buffer* buffer) {
if (!str.c_str()) return NULL; // <- Arduino string can return NULL
size_t size = str.length() + 1;
void* dup = buffer->alloc(size);
if (dup != NULL) memcpy(dup, str.c_str(), size);
return static_cast<char*>(dup);
}
static bool equals(const TString& str, const char* expected) {
return str == expected;
}
static void append(TString& str, char c) {
str += c;
}
static const bool has_append = true;
static const bool should_duplicate = true;
};
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
template <>
struct StringFuncs<String> : StdStringFuncs<String> {};
template <>
struct StringFuncs<StringSumHelper> : StdStringFuncs<StringSumHelper> {};
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
template <>
struct StringFuncs<std::string> : StdStringFuncs<std::string> {};
#endif
}
}

View File

@ -0,0 +1,41 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#pragma once
#include "../JsonBuffer.hpp"
#include "../JsonVariant.hpp"
#include "../TypeTraits/EnableIf.hpp"
#include "StringFuncs.hpp"
namespace ArduinoJson {
namespace Internals {
template <typename TSource, typename Enable = void>
struct ValueSetter {
template <typename TDestination>
static bool set(JsonBuffer*, TDestination& destination,
const TSource& source) {
destination = source;
return true;
}
};
template <typename TSource>
struct ValueSetter<TSource, typename TypeTraits::EnableIf<
StringFuncs<TSource>::should_duplicate>::type> {
template <typename TDestination>
static bool set(JsonBuffer* buffer, TDestination& destination,
const TSource& source) {
const char* copy = buffer->strdup(source);
if (!copy) return false;
destination = copy;
return true;
}
};
}
}

View File

@ -11,10 +11,12 @@
#include "Internals/JsonPrintable.hpp" #include "Internals/JsonPrintable.hpp"
#include "Internals/List.hpp" #include "Internals/List.hpp"
#include "Internals/ReferenceType.hpp" #include "Internals/ReferenceType.hpp"
#include "Internals/StringFuncs.hpp"
#include "Internals/ValueSetter.hpp"
#include "JsonVariant.hpp" #include "JsonVariant.hpp"
#include "TypeTraits/ConstRefOrConstPtr.hpp"
#include "TypeTraits/EnableIf.hpp" #include "TypeTraits/EnableIf.hpp"
#include "TypeTraits/IsFloatingPoint.hpp" #include "TypeTraits/IsFloatingPoint.hpp"
#include "TypeTraits/IsReference.hpp"
#include "TypeTraits/IsSame.hpp" #include "TypeTraits/IsSame.hpp"
// Returns the size (in bytes) of an array with n elements. // Returns the size (in bytes) of an array with n elements.
@ -40,15 +42,6 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
public Internals::List<JsonVariant>, public Internals::List<JsonVariant>,
public Internals::JsonBufferAllocated { public Internals::JsonBufferAllocated {
public: public:
// A meta-function that returns true if type T can be used in
// JsonArray::set()
template <typename T>
struct CanSet {
static const bool value = JsonVariant::IsConstructibleFrom<T>::value ||
TypeTraits::IsSame<T, String &>::value ||
TypeTraits::IsSame<T, const String &>::value;
};
// Create an empty JsonArray attached to the specified JsonBuffer. // Create an empty JsonArray attached to the specified JsonBuffer.
// You should not call this constructor directly. // You should not call this constructor directly.
// Instead, use JsonBuffer::createArray() or JsonBuffer::parseArray(). // Instead, use JsonBuffer::createArray() or JsonBuffer::parseArray().
@ -57,7 +50,7 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// Gets the value at the specified index // Gets the value at the specified index
JsonVariant operator[](size_t index) const { JsonVariant operator[](size_t index) const {
return get(index); return get<JsonVariant>(index);
} }
// Gets or sets the value at specified index // Gets or sets the value at specified index
@ -73,29 +66,24 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// bool add(float value); // bool add(float value);
// bool add(double value); // bool add(double value);
// bool add(const char*); // bool add(const char*);
template <typename T> // bool add(const char[]);
bool add( // bool add(const char[N]);
T value, // bool add(RawJson);
typename TypeTraits::EnableIf< // bool add(const std::string&)
CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type * = 0) {
return addNode<T>(value);
}
// bool add(const String&) // bool add(const String&)
// bool add(const JsonVariant&); // bool add(const JsonVariant&);
// bool add(JsonArray&); // bool add(JsonArray&);
// bool add(JsonObject&); // bool add(JsonObject&);
template <typename T> template <typename T>
bool add(const T &value, bool add(const T &value) {
typename TypeTraits::EnableIf<CanSet<T &>::value>::type * = 0) { // reduce the number of template function instanciation to reduce code size
return addNode<T &>(const_cast<T &>(value)); return addNodeImpl<typename TypeTraits::ConstRefOrConstPtr<T>::type>(value);
} }
// bool add(float value, uint8_t decimals); // bool add(float value, uint8_t decimals);
// bool add(double value, uint8_t decimals); // bool add(double value, uint8_t decimals);
template <typename T> template <typename T>
bool add(T value, uint8_t decimals, bool add(T value, uint8_t decimals) {
typename TypeTraits::EnableIf< return add(JsonVariant(value, decimals));
TypeTraits::IsFloatingPoint<T>::value>::type * = 0) {
return addNode<JsonVariant>(JsonVariant(value, decimals));
} }
// Sets the value at specified index. // Sets the value at specified index.
@ -104,42 +92,33 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// bool set(size_t index, long value); // bool set(size_t index, long value);
// bool set(size_t index, int value); // bool set(size_t index, int value);
// bool set(size_t index, short value); // bool set(size_t index, short value);
template <typename T> // bool set(size_t index, const std::string&)
bool set(
size_t index, T value,
typename TypeTraits::EnableIf<
CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type * = 0) {
return setNodeAt<T>(index, value);
}
// bool set(size_t index, const String&) // bool set(size_t index, const String&)
// bool set(size_t index, const JsonVariant&); // bool set(size_t index, const JsonVariant&);
// bool set(size_t index, JsonArray&); // bool set(size_t index, JsonArray&);
// bool set(size_t index, JsonObject&); // bool set(size_t index, JsonObject&);
template <typename T> template <typename T>
bool set(size_t index, const T &value, bool set(size_t index, const T &value) {
typename TypeTraits::EnableIf<CanSet<T &>::value>::type * = 0) { // reduce the number of template function instanciation to reduce code size
return setNodeAt<T &>(index, const_cast<T &>(value)); return setNodeAt<typename TypeTraits::ConstRefOrConstPtr<T>::type>(index,
value);
} }
// bool set(size_t index, float value, uint8_t decimals = 2); // bool set(size_t index, float value, uint8_t decimals = 2);
// bool set(size_t index, double value, uint8_t decimals = 2); // bool set(size_t index, double value, uint8_t decimals = 2);
template <typename T> template <typename T>
bool set(size_t index, T value, uint8_t decimals, typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<T>::value,
typename TypeTraits::EnableIf< bool>::type
TypeTraits::IsFloatingPoint<T>::value>::type * = 0) { set(size_t index, T value, uint8_t decimals) {
return setNodeAt<const JsonVariant &>(index, JsonVariant(value, decimals)); return set(index, JsonVariant(value, decimals));
}
// Gets the value at the specified index.
JsonVariant get(size_t index) const {
node_type *node = getNodeAt(index);
return node ? node->content : JsonVariant();
} }
// Gets the value at the specified index. // Gets the value at the specified index.
template <typename T> template <typename T>
typename Internals::JsonVariantAs<T>::type get(size_t index) const { typename Internals::JsonVariantAs<T>::type get(size_t index) const {
node_type *node = getNodeAt(index); node_type *node = getNodeAt(index);
return node ? node->content.as<T>() : JsonVariant::defaultValue<T>(); return node ? node->content.as<T>()
: Internals::JsonVariantDefault<T>::get();
;
} }
// Check the type of the value at specified index. // Check the type of the value at specified index.
@ -172,7 +151,7 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// Imports a 1D array // Imports a 1D array
template <typename T, size_t N> template <typename T, size_t N>
bool copyFrom(T(&array)[N]) { bool copyFrom(T (&array)[N]) {
return copyFrom(array, N); return copyFrom(array, N);
} }
@ -188,7 +167,7 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// Imports a 2D array // Imports a 2D array
template <typename T, size_t N1, size_t N2> template <typename T, size_t N1, size_t N2>
bool copyFrom(T(&array)[N1][N2]) { bool copyFrom(T (&array)[N1][N2]) {
bool ok = true; bool ok = true;
for (size_t i = 0; i < N1; i++) { for (size_t i = 0; i < N1; i++) {
JsonArray &nestedArray = createNestedArray(); JsonArray &nestedArray = createNestedArray();
@ -201,7 +180,7 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// Exports a 1D array // Exports a 1D array
template <typename T, size_t N> template <typename T, size_t N>
size_t copyTo(T(&array)[N]) const { size_t copyTo(T (&array)[N]) const {
return copyTo(array, N); return copyTo(array, N);
} }
@ -216,7 +195,7 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// Exports a 2D array // Exports a 2D array
template <typename T, size_t N1, size_t N2> template <typename T, size_t N1, size_t N2>
void copyTo(T(&array)[N1][N2]) const { void copyTo(T (&array)[N1][N2]) const {
size_t i = 0; size_t i = 0;
for (const_iterator it = begin(); it != end() && i < N1; ++it) { for (const_iterator it = begin(); it != end() && i < N1; ++it) {
it->asArray().copyTo(array[i++]); it->asArray().copyTo(array[i++]);
@ -230,22 +209,22 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
return node; return node;
} }
template <typename TValue> template <typename TValueRef>
bool setNodeAt(size_t index, TValue value) { bool setNodeAt(size_t index, TValueRef value) {
node_type *node = getNodeAt(index); node_type *node = getNodeAt(index);
return node != NULL && setNodeValue<TValue>(node, value); if (!node) return false;
return Internals::ValueSetter<TValueRef>::set(_buffer, node->content,
value);
} }
template <typename TValue> template <typename TValueRef>
bool addNode(TValue value) { bool addNodeImpl(TValueRef value) {
node_type *node = addNewNode(); node_type *node = addNewNode();
return node != NULL && setNodeValue<TValue>(node, value); if (!node) return false;
}
template <typename T> return Internals::ValueSetter<TValueRef>::set(_buffer, node->content,
bool setNodeValue(node_type *node, T value) { value);
node->content = value;
return true;
} }
}; };
} }

View File

@ -13,50 +13,31 @@
namespace ArduinoJson { namespace ArduinoJson {
inline JsonVariant::JsonVariant(JsonArray &array) { inline JsonVariant::JsonVariant(const JsonArray &array) {
if (array.success()) { if (array.success()) {
_type = Internals::JSON_ARRAY; _type = Internals::JSON_ARRAY;
_content.asArray = &array; _content.asArray = const_cast<JsonArray *>(&array);
} else { } else {
_type = Internals::JSON_UNDEFINED; _type = Internals::JSON_UNDEFINED;
} }
} }
inline JsonVariant::JsonVariant(JsonObject &object) { inline JsonVariant::JsonVariant(const JsonObject &object) {
if (object.success()) { if (object.success()) {
_type = Internals::JSON_OBJECT; _type = Internals::JSON_OBJECT;
_content.asObject = &object; _content.asObject = const_cast<JsonObject *>(&object);
} else { } else {
_type = Internals::JSON_UNDEFINED; _type = Internals::JSON_UNDEFINED;
} }
} }
namespace Internals {
template <> template <>
inline bool JsonArray::setNodeValue(node_type *node, String &value) { struct JsonVariantDefault<JsonArray> {
const char *copy = _buffer->strdup(value); static JsonArray &get() {
if (!copy) return false; return JsonArray::invalid();
node->content = copy; }
return true; };
}
template <>
inline JsonArray &JsonVariant::defaultValue<JsonArray>() {
return JsonArray::invalid();
}
template <>
inline JsonArray &JsonVariant::defaultValue<JsonArray &>() {
return JsonArray::invalid();
}
template <>
inline const JsonArray &JsonVariant::defaultValue<const JsonArray>() {
return JsonArray::invalid();
}
template <>
inline const JsonArray &JsonVariant::defaultValue<const JsonArray &>() {
return JsonArray::invalid();
} }
inline JsonArray &JsonVariant::asArray() const { inline JsonArray &JsonVariant::asArray() const {
@ -71,10 +52,11 @@ inline JsonArray &JsonArray::createNestedArray() {
return array; return array;
} }
inline JsonArray &JsonObject::createNestedArray(JsonObjectKey key) { template <typename TString>
inline JsonArray &JsonObject::createNestedArray(const TString &key) {
if (!_buffer) return JsonArray::invalid(); if (!_buffer) return JsonArray::invalid();
JsonArray &array = _buffer->createArray(); JsonArray &array = _buffer->createArray();
setNodeAt<const JsonVariant &>(key, array); set(key, array);
return array; return array;
} }
} }

View File

@ -21,24 +21,14 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index) FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index)
: _array(array), _index(index) {} : _array(array), _index(index) {}
JsonArraySubscript& operator=(const JsonArraySubscript& src) { FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& src) {
_array.set<const JsonVariant&>(_index, src); _array.set(_index, src);
return *this; return *this;
} }
template <typename T> template <typename T>
typename TypeTraits::EnableIf<JsonArray::CanSet<T&>::value, FORCE_INLINE JsonArraySubscript& operator=(const T& src) {
JsonArraySubscript>::type& _array.set(_index, src);
operator=(const T& src) {
_array.set<T&>(_index, const_cast<T&>(src));
return *this;
}
template <typename T>
typename TypeTraits::EnableIf<JsonArray::CanSet<T>::value,
JsonArraySubscript>::type&
operator=(T src) {
_array.set<T>(_index, src);
return *this; return *this;
} }
@ -46,10 +36,6 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
return _index < _array.size(); return _index < _array.size();
} }
FORCE_INLINE operator JsonVariant() const {
return _array.get(_index);
}
template <typename T> template <typename T>
FORCE_INLINE typename Internals::JsonVariantAs<T>::type as() const { FORCE_INLINE typename Internals::JsonVariantAs<T>::type as() const {
return _array.get<T>(_index); return _array.get<T>(_index);
@ -61,7 +47,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
} }
template <typename TValue> template <typename TValue>
void set(TValue value) { FORCE_INLINE void set(const TValue& value) {
_array.set(_index, value); _array.set(_index, value);
} }

View File

@ -12,7 +12,6 @@
#include <string.h> #include <string.h>
#include "JsonVariant.hpp" #include "JsonVariant.hpp"
#include "String.hpp"
#if defined(__clang__) #if defined(__clang__)
#pragma clang diagnostic push #pragma clang diagnostic push
@ -58,67 +57,56 @@ class JsonBuffer {
// writable // writable
// because the parser will insert null-terminators and replace escaped chars. // because the parser will insert null-terminators and replace escaped chars.
// //
// The second argument set the nesting limit (see comment on DEFAULT_LIMIT) // The second argument set the nesting limit
// //
// Returns a reference to the new JsonObject or JsonObject::invalid() if the // Returns a reference to the new JsonObject or JsonObject::invalid() if the
// allocation fails. // allocation fails.
JsonArray &parseArray(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); JsonArray &parseArray(
char *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT);
// Same with a const char*.
// With this overload, the JsonBuffer will make a copy of the string // With this overload, the JsonBuffer will make a copy of the string
JsonArray &parseArray(const char *json, uint8_t nesting = DEFAULT_LIMIT) { template <typename TString>
JsonArray &parseArray(const TString &json,
uint8_t nesting = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
return parseArray(strdup(json), nesting); return parseArray(strdup(json), nesting);
} }
// Same as above with a String class
JsonArray &parseArray(const String &json, uint8_t nesting = DEFAULT_LIMIT) {
return parseArray(json.c_str(), nesting);
}
// Allocates and populate a JsonObject from a JSON string. // Allocates and populate a JsonObject from a JSON string.
// //
// The First argument is a pointer to the JSON string, the memory must be // The First argument is a pointer to the JSON string, the memory must be
// writable // writable
// because the parser will insert null-terminators and replace escaped chars. // because the parser will insert null-terminators and replace escaped chars.
// //
// The second argument set the nesting limit (see comment on DEFAULT_LIMIT) // The second argument set the nesting limit
// //
// Returns a reference to the new JsonObject or JsonObject::invalid() if the // Returns a reference to the new JsonObject or JsonObject::invalid() if the
// allocation fails. // allocation fails.
JsonObject &parseObject(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); JsonObject &parseObject(
char *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT);
// Same with a const char*.
// With this overload, the JsonBuffer will make a copy of the string // With this overload, the JsonBuffer will make a copy of the string
JsonObject &parseObject(const char *json, uint8_t nesting = DEFAULT_LIMIT) { template <typename TString>
JsonObject &parseObject(const TString &json,
uint8_t nesting = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
return parseObject(strdup(json), nesting); return parseObject(strdup(json), nesting);
} }
// Same as above with a String class
JsonObject &parseObject(const String &json, uint8_t nesting = DEFAULT_LIMIT) {
return parseObject(json.c_str(), nesting);
}
// Generalized version of parseArray() and parseObject(), also works for // Generalized version of parseArray() and parseObject(), also works for
// integral types. // integral types.
JsonVariant parse(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); JsonVariant parse(char *json,
uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT);
// Same with a const char*.
// With this overload, the JsonBuffer will make a copy of the string // With this overload, the JsonBuffer will make a copy of the string
JsonVariant parse(const char *json, uint8_t nesting = DEFAULT_LIMIT) { template <typename TString>
JsonVariant parse(const TString &json,
uint8_t nesting = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
return parse(strdup(json), nesting); return parse(strdup(json), nesting);
} }
// Same as above with a String class
JsonVariant parse(const String &json, uint8_t nesting = DEFAULT_LIMIT) {
return parse(json.c_str(), nesting);
}
// Duplicate a string // Duplicate a string
char *strdup(const char *src) { template <typename TString>
return src ? strdup(src, strlen(src)) : NULL; char *strdup(const TString &src) {
} return Internals::StringFuncs<TString>::duplicate(src, this);
char *strdup(const String &src) {
return strdup(src.c_str(), src.length());
} }
// Allocates n bytes in the JsonBuffer. // Allocates n bytes in the JsonBuffer.
@ -135,23 +123,6 @@ class JsonBuffer {
return bytes; return bytes;
#endif #endif
} }
private:
char *strdup(const char *, size_t);
// Default value of nesting limit of parseArray() and parseObject().
//
// The nesting limit is a constrain on the level of nesting allowed in the
// JSON string.
// If set to 0, only a flat array or objects can be parsed.
// If set to 1, the object can contain nested arrays or objects but only 1
// level deep.
// And bigger values will allow more level of nesting.
//
// The purpose of this feature is to prevent stack overflow that could
// lead to
// a security risk.
static const uint8_t DEFAULT_LIMIT = ARDUINOJSON_DEFAULT_NESTING_LIMIT;
}; };
} }

View File

@ -36,11 +36,3 @@ inline ArduinoJson::JsonVariant ArduinoJson::JsonBuffer::parse(
Internals::JsonParser parser(this, json, nestingLimit); Internals::JsonParser parser(this, json, nestingLimit);
return parser.parseVariant(); return parser.parseVariant();
} }
inline char *ArduinoJson::JsonBuffer::strdup(const char *source,
size_t length) {
size_t size = length + 1;
char *dest = static_cast<char *>(alloc(size));
if (dest != NULL) memcpy(dest, source, size);
return dest;
}

View File

@ -7,15 +7,16 @@
#pragma once #pragma once
#include "String.hpp"
#include "Internals/JsonBufferAllocated.hpp" #include "Internals/JsonBufferAllocated.hpp"
#include "Internals/JsonPrintable.hpp" #include "Internals/JsonPrintable.hpp"
#include "Internals/List.hpp" #include "Internals/List.hpp"
#include "Internals/ReferenceType.hpp" #include "Internals/ReferenceType.hpp"
#include "Internals/StringFuncs.hpp"
#include "Internals/ValueSetter.hpp"
#include "JsonPair.hpp" #include "JsonPair.hpp"
#include "TypeTraits/ConstRefOrConstPtr.hpp"
#include "TypeTraits/EnableIf.hpp" #include "TypeTraits/EnableIf.hpp"
#include "TypeTraits/IsFloatingPoint.hpp" #include "TypeTraits/IsFloatingPoint.hpp"
#include "TypeTraits/IsReference.hpp"
#include "TypeTraits/IsSame.hpp" #include "TypeTraits/IsSame.hpp"
// Returns the size (in bytes) of an object with n elements. // Returns the size (in bytes) of an object with n elements.
@ -40,27 +41,19 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
public Internals::List<JsonPair>, public Internals::List<JsonPair>,
public Internals::JsonBufferAllocated { public Internals::JsonBufferAllocated {
public: public:
// A meta-function that returns true if type T can be used in
// JsonObject::set()
template <typename T>
struct CanSet {
static const bool value = JsonVariant::IsConstructibleFrom<T>::value ||
TypeTraits::IsSame<T, String&>::value ||
TypeTraits::IsSame<T, const String&>::value;
};
// Create an empty JsonArray attached to the specified JsonBuffer. // Create an empty JsonArray attached to the specified JsonBuffer.
// You should not use this constructor directly. // You should not use this constructor directly.
// Instead, use JsonBuffer::createObject() or JsonBuffer.parseObject(). // Instead, use JsonBuffer::createObject() or JsonBuffer.parseObject().
explicit JsonObject(JsonBuffer* buffer) : Internals::List<JsonPair>(buffer) {} explicit JsonObject(JsonBuffer* buffer) : Internals::List<JsonPair>(buffer) {}
// Gets or sets the value associated with the specified key. // Gets or sets the value associated with the specified key.
JsonObjectSubscript<const char*> operator[](const char* key); template <typename TString>
JsonObjectSubscript<const String&> operator[](const String& key); JsonObjectSubscript<TString> operator[](const TString& key);
// Gets the value associated with the specified key. // Gets the value associated with the specified key.
JsonVariant operator[](JsonObjectKey key) const { template <typename TString>
return get(key); JsonVariant operator[](const TString& key) const {
return get<JsonVariant>(key);
} }
// Sets the specified key with the specified value. // Sets the specified key with the specified value.
@ -73,67 +66,62 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
// bool set(TKey key, double value); // bool set(TKey key, double value);
// bool set(TKey key, const char* value); // bool set(TKey key, const char* value);
// bool set(TKey key, RawJson value); // bool set(TKey key, RawJson value);
template <typename T>
bool set(
JsonObjectKey key, T value,
typename TypeTraits::EnableIf<
CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type* = 0) {
return setNodeAt<T>(key, value);
}
// bool set(Key, String&); // bool set(Key, String&);
// bool set(Key, JsonArray&); // bool set(Key, JsonArray&);
// bool set(Key, JsonObject&); // bool set(Key, JsonObject&);
// bool set(Key, JsonVariant&); // bool set(Key, JsonVariant&);
template <typename T> template <typename TValue, typename TString>
bool set(JsonObjectKey key, const T& value, bool set(const TString& key, const TValue& value) {
typename TypeTraits::EnableIf<CanSet<T&>::value>::type* = 0) { // reduce the number of template function instanciation to reduce code size
return setNodeAt<T&>(key, const_cast<T&>(value)); return setNodeAt<typename TypeTraits::ConstRefOrConstPtr<TString>::type,
typename TypeTraits::ConstRefOrConstPtr<TValue>::type>(
key, value);
} }
// bool set(Key, float value, uint8_t decimals); // bool set(Key, float value, uint8_t decimals);
// bool set(Key, double value, uint8_t decimals); // bool set(Key, double value, uint8_t decimals);
template <typename TValue> template <typename TValue, typename TString>
bool set(JsonObjectKey key, TValue value, uint8_t decimals, typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<TValue>::value,
typename TypeTraits::EnableIf< bool>::type
TypeTraits::IsFloatingPoint<TValue>::value>::type* = 0) { set(const TString& key, TValue value, uint8_t decimals) {
return setNodeAt<const JsonVariant&>(key, JsonVariant(value, decimals)); return set(key, JsonVariant(value, decimals));
} }
// Gets the value associated with the specified key. // Gets the value associated with the specified key.
JsonVariant get(JsonObjectKey key) const { template <typename TValue, typename TString>
node_type* node = getNodeAt(key.c_str()); typename Internals::JsonVariantAs<TValue>::type get(
return node ? node->content.value : JsonVariant(); const TString& key) const {
} node_type* node = getNodeAt(key);
return node ? node->content.value.as<TValue>()
// Gets the value associated with the specified key. : Internals::JsonVariantDefault<TValue>::get();
template <typename T>
typename Internals::JsonVariantAs<T>::type get(JsonObjectKey key) const {
node_type* node = getNodeAt(key.c_str());
return node ? node->content.value.as<T>() : JsonVariant::defaultValue<T>();
} }
// Checks the type of the value associated with the specified key. // Checks the type of the value associated with the specified key.
template <typename T> template <typename TValue, typename TString>
bool is(JsonObjectKey key) const { bool is(const TString& key) const {
node_type* node = getNodeAt(key.c_str()); node_type* node = getNodeAt(key);
return node ? node->content.value.is<T>() : false; return node ? node->content.value.is<TValue>() : false;
} }
// Creates and adds a JsonArray. // Creates and adds a JsonArray.
// This is a shortcut for JsonBuffer::createArray() and JsonObject::add(). // This is a shortcut for JsonBuffer::createArray() and JsonObject::add().
JsonArray& createNestedArray(JsonObjectKey key); template <typename TString>
JsonArray& createNestedArray(const TString& key);
// Creates and adds a JsonObject. // Creates and adds a JsonObject.
// This is a shortcut for JsonBuffer::createObject() and JsonObject::add(). // This is a shortcut for JsonBuffer::createObject() and JsonObject::add().
JsonObject& createNestedObject(JsonObjectKey key); template <typename TString>
JsonObject& createNestedObject(const TString& key);
// Tells weither the specified key is present and associated with a value. // Tells weither the specified key is present and associated with a value.
bool containsKey(JsonObjectKey key) const { template <typename TString>
return getNodeAt(key.c_str()) != NULL; bool containsKey(const TString& key) const {
return getNodeAt(key) != NULL;
} }
// Removes the specified key and the associated value. // Removes the specified key and the associated value.
void remove(JsonObjectKey key) { template <typename TString>
removeNode(getNodeAt(key.c_str())); void remove(const TString& key) {
removeNode(getNodeAt(key));
} }
// Returns a reference an invalid JsonObject. // Returns a reference an invalid JsonObject.
@ -146,37 +134,35 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
private: private:
// Returns the list node that matches the specified key. // Returns the list node that matches the specified key.
node_type* getNodeAt(const char* key) const { template <typename TString>
node_type* getNodeAt(const TString& key) const {
// reduce the number of template function instanciation to reduce code size
return getNodeAtImpl<
typename TypeTraits::ConstRefOrConstPtr<TString>::type>(key);
}
template <typename TStringRef>
node_type* getNodeAtImpl(TStringRef key) const {
for (node_type* node = _firstNode; node; node = node->next) { for (node_type* node = _firstNode; node; node = node->next) {
if (!strcmp(node->content.key, key)) return node; if (Internals::StringFuncs<TStringRef>::equals(key, node->content.key))
return node;
} }
return NULL; return NULL;
} }
template <typename T> template <typename TStringRef, typename TValueRef>
bool setNodeAt(JsonObjectKey key, T value) { bool setNodeAt(TStringRef key, TValueRef value) {
node_type* node = getNodeAt(key.c_str()); node_type* node = getNodeAtImpl<TStringRef>(key);
if (!node) { if (!node) {
node = addNewNode(); node = addNewNode();
if (!node || !setNodeKey(node, key)) return false; if (!node) return false;
}
return setNodeValue<T>(node, value);
}
bool setNodeKey(node_type* node, JsonObjectKey key) { bool key_ok = Internals::ValueSetter<TStringRef>::set(
if (key.needs_copy()) { _buffer, node->content.key, key);
node->content.key = _buffer->strdup(key.c_str()); if (!key_ok) return false;
if (node->content.key == NULL) return false;
} else {
node->content.key = key.c_str();
} }
return true; return Internals::ValueSetter<TValueRef>::set(_buffer, node->content.value,
} value);
template <typename T>
bool setNodeValue(node_type* node, T value) {
node->content.value = value;
return true;
} }
}; };
} }

View File

@ -13,38 +13,13 @@
namespace ArduinoJson { namespace ArduinoJson {
namespace Internals {
template <> template <>
inline bool JsonObject::setNodeValue(node_type *node, String &value) { struct JsonVariantDefault<JsonObject> {
const char *dup = _buffer->strdup(value); static JsonObject &get() {
node->content.value = dup; return JsonObject::invalid();
return dup != NULL; }
} };
template <>
inline bool JsonObject::setNodeValue(node_type *node, const String &value) {
const char *dup = _buffer->strdup(value);
node->content.value = dup;
return dup != NULL;
}
template <>
inline const JsonObject &JsonVariant::defaultValue<const JsonObject &>() {
return JsonObject::invalid();
}
template <>
inline const JsonObject &JsonVariant::defaultValue<const JsonObject>() {
return JsonObject::invalid();
}
template <>
inline JsonObject &JsonVariant::defaultValue<JsonObject &>() {
return JsonObject::invalid();
}
template <>
inline JsonObject &JsonVariant::defaultValue<JsonObject>() {
return JsonObject::invalid();
} }
inline JsonObject &JsonVariant::asObject() const { inline JsonObject &JsonVariant::asObject() const {
@ -52,11 +27,12 @@ inline JsonObject &JsonVariant::asObject() const {
return JsonObject::invalid(); return JsonObject::invalid();
} }
inline JsonObject &JsonObject::createNestedObject(JsonObjectKey key) { template <typename TString>
inline JsonObject &JsonObject::createNestedObject(const TString &key) {
if (!_buffer) return JsonObject::invalid(); if (!_buffer) return JsonObject::invalid();
JsonObject &array = _buffer->createObject(); JsonObject &object = _buffer->createObject();
setNodeAt<const JsonVariant &>(key, array); set(key, object);
return array; return object;
} }
inline JsonObject &JsonArray::createNestedObject() { inline JsonObject &JsonArray::createNestedObject() {

View File

@ -1,27 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#pragma once
#include "String.hpp"
namespace ArduinoJson {
// Represents a key in a JsonObject
class JsonObjectKey {
public:
JsonObjectKey(const char* key) : _value(key), _needs_copy(false) {}
JsonObjectKey(const String& key) : _value(key.c_str()), _needs_copy(true) {}
const char* c_str() const { return _value; }
bool needs_copy() const { return _needs_copy; }
private:
const char* _value;
bool _needs_copy;
};
}

View File

@ -9,6 +9,7 @@
#include "Configuration.hpp" #include "Configuration.hpp"
#include "JsonVariantBase.hpp" #include "JsonVariantBase.hpp"
#include "TypeTraits/ConstRefOrConstPtr.hpp"
#include "TypeTraits/EnableIf.hpp" #include "TypeTraits/EnableIf.hpp"
#ifdef _MSC_VER #ifdef _MSC_VER
@ -18,30 +19,27 @@
namespace ArduinoJson { namespace ArduinoJson {
template <typename TKey> template <typename TString>
class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript<TKey> > { class JsonObjectSubscript
: public JsonVariantBase<JsonObjectSubscript<TString> > {
// const String&
// const std::string&
// const char*
typedef typename TypeTraits::ConstRefOrConstPtr<TString>::type TStringRef;
public: public:
FORCE_INLINE JsonObjectSubscript(JsonObject& object, TKey key) FORCE_INLINE JsonObjectSubscript(JsonObject& object, TStringRef key)
: _object(object), _key(key) {} : _object(object), _key(key) {}
JsonObjectSubscript<TKey>& operator=(const JsonObjectSubscript<TKey>& src) { FORCE_INLINE JsonObjectSubscript<TString>& operator=(
_object.set<const JsonVariant&>(_key, src); const JsonObjectSubscript<TString>& src) {
_object.set(_key, src);
return *this; return *this;
} }
template <typename T> template <typename T>
typename TypeTraits::EnableIf<JsonObject::CanSet<T&>::value, FORCE_INLINE JsonObjectSubscript<TString>& operator=(const T& src) {
JsonObjectSubscript<TKey> >::type& _object.set(_key, src);
operator=(const T& src) {
_object.set<T&>(_key, const_cast<T&>(src));
return *this;
}
template <typename T>
typename TypeTraits::EnableIf<JsonObject::CanSet<T>::value,
JsonObjectSubscript<TKey> >::type&
operator=(T src) {
_object.set<T>(_key, src);
return *this; return *this;
} }
@ -49,13 +47,9 @@ class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript<TKey> > {
return _object.containsKey(_key); return _object.containsKey(_key);
} }
FORCE_INLINE operator JsonVariant() const {
return _object.get(_key);
}
template <typename TValue> template <typename TValue>
FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type as() const { FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type as() const {
return _object.get<TValue>(_key); return _object.get<TValue, TStringRef>(_key);
} }
template <typename TValue> template <typename TValue>
@ -64,58 +58,39 @@ class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript<TKey> > {
} }
template <typename TValue> template <typename TValue>
FORCE_INLINE bool set(TValue value) { FORCE_INLINE bool set(const TValue& value) {
return _object.set<TValue>(_key, value); return _object.set(_key, value);
} }
template <typename TValue> template <typename TValue>
FORCE_INLINE bool set(TValue value, uint8_t decimals) { FORCE_INLINE bool set(const TValue& value, uint8_t decimals) {
return _object.set(_key, value, decimals); return _object.set(_key, value, decimals);
} }
FORCE_INLINE JsonVariant get() {
return _object.get(_key);
}
private: private:
JsonObject& _object; JsonObject& _object;
TKey _key; TStringRef _key;
}; };
#if ARDUINOJSON_ENABLE_STD_STREAM #if ARDUINOJSON_ENABLE_STD_STREAM
inline std::ostream& operator<<( template <typename TString>
std::ostream& os, const JsonObjectSubscript<const String&>& source) { inline std::ostream& operator<<(std::ostream& os,
return source.printTo(os); const JsonObjectSubscript<TString>& source) {
}
inline std::ostream& operator<<(
std::ostream& os, const JsonObjectSubscript<const char*>& source) {
return source.printTo(os); return source.printTo(os);
} }
#endif #endif
inline JsonObjectSubscript<const char*> JsonObject::operator[]( template <typename TString>
const char* key) { inline JsonObjectSubscript<TString> JsonObject::operator[](const TString& key) {
return JsonObjectSubscript<const char*>(*this, key); return JsonObjectSubscript<TString>(*this, key);
}
inline JsonObjectSubscript<const String&> JsonObject::operator[](
const String& key) {
return JsonObjectSubscript<const String&>(*this, key);
} }
template <typename TImplem> template <typename TImplem>
inline const JsonObjectSubscript<const char*> JsonVariantBase<TImplem>:: template <class TString>
operator[](const char* key) const { inline const JsonObjectSubscript<TString> JsonVariantBase<TImplem>::operator[](
const TString& key) const {
return asObject()[key]; return asObject()[key];
} }
template <typename TImplem>
inline const JsonObjectSubscript<const String&> JsonVariantBase<TImplem>::
operator[](const String& key) const {
return asObject()[key];
}
} // namespace ArduinoJson } // namespace ArduinoJson
#ifdef _MSC_VER #ifdef _MSC_VER

View File

@ -7,7 +7,6 @@
#pragma once #pragma once
#include "JsonObjectKey.hpp"
#include "JsonVariant.hpp" #include "JsonVariant.hpp"
namespace ArduinoJson { namespace ArduinoJson {

View File

@ -12,6 +12,7 @@
#include "Internals/JsonPrintable.hpp" #include "Internals/JsonPrintable.hpp"
#include "Internals/JsonVariantContent.hpp" #include "Internals/JsonVariantContent.hpp"
#include "Internals/JsonVariantDefault.hpp"
#include "Internals/JsonVariantType.hpp" #include "Internals/JsonVariantType.hpp"
#include "JsonVariantBase.hpp" #include "JsonVariantBase.hpp"
#include "RawJson.hpp" #include "RawJson.hpp"
@ -19,6 +20,8 @@
#include "TypeTraits/IsFloatingPoint.hpp" #include "TypeTraits/IsFloatingPoint.hpp"
#include "TypeTraits/IsIntegral.hpp" #include "TypeTraits/IsIntegral.hpp"
#include "TypeTraits/IsSame.hpp" #include "TypeTraits/IsSame.hpp"
#include "TypeTraits/IsSignedIntegral.hpp"
#include "TypeTraits/IsUnsignedIntegral.hpp"
#include "TypeTraits/RemoveConst.hpp" #include "TypeTraits/RemoveConst.hpp"
#include "TypeTraits/RemoveReference.hpp" #include "TypeTraits/RemoveReference.hpp"
@ -40,9 +43,6 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
JsonWriter &); JsonWriter &);
public: public:
template <typename T>
struct IsConstructibleFrom;
// Creates an uninitialized JsonVariant // Creates an uninitialized JsonVariant
JsonVariant() : _type(Internals::JSON_UNDEFINED) {} JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
@ -110,10 +110,14 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
} }
// Create a JsonVariant containing a reference to an array. // Create a JsonVariant containing a reference to an array.
JsonVariant(JsonArray &array); // CAUTION: we are lying about constness, because the array can be modified if
// the variant is converted back to a JsonArray&
JsonVariant(const JsonArray &array);
// Create a JsonVariant containing a reference to an object. // Create a JsonVariant containing a reference to an object.
JsonVariant(JsonObject &object); // CAUTION: we are lying about constness, because the object can be modified
// if the variant is converted back to a JsonObject&
JsonVariant(const JsonObject &object);
// Get the variant as the specified type. // Get the variant as the specified type.
// //
@ -146,14 +150,6 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
return static_cast<T>(asFloat()); return static_cast<T>(asFloat());
} }
// //
// const String as<String>() const;
template <typename T>
const typename TypeTraits::EnableIf<TypeTraits::IsSame<T, String>::value,
T>::type
as() const {
return toString();
}
//
// const char* as<const char*>() const; // const char* as<const char*>() const;
// const char* as<char*>() const; // const char* as<char*>() const;
template <typename T> template <typename T>
@ -164,6 +160,18 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
return asString(); return asString();
} }
// //
// std::string as<std::string>() const;
// String as<String>() const;
template <typename T>
typename TypeTraits::EnableIf<Internals::StringFuncs<T>::has_append, T>::type
as() const {
const char *cstr = asString();
if (cstr) return T(cstr);
T s;
printTo(s);
return s;
}
//
// const bool as<bool>() const // const bool as<bool>() const
template <typename T> template <typename T>
const typename TypeTraits::EnableIf<TypeTraits::IsSame<T, bool>::value, const typename TypeTraits::EnableIf<TypeTraits::IsSame<T, bool>::value,
@ -230,7 +238,8 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
// int as<int>() const; // int as<int>() const;
// long as<long>() const; // long as<long>() const;
template <typename T> template <typename T>
const typename TypeTraits::EnableIf<TypeTraits::IsIntegral<T>::value, const typename TypeTraits::EnableIf<TypeTraits::IsIntegral<T>::value &&
!TypeTraits::IsSame<T, bool>::value,
bool>::type bool>::type
is() const { is() const {
return isInteger(); return isInteger();
@ -296,12 +305,6 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
return _type != Internals::JSON_UNDEFINED; return _type != Internals::JSON_UNDEFINED;
} }
// Value returned if the variant has an incompatible type
template <typename T>
static typename Internals::JsonVariantAs<T>::type defaultValue() {
return T();
}
// DEPRECATED: use as<char*>() instead // DEPRECATED: use as<char*>() instead
const char *asString() const; const char *asString() const;
@ -317,7 +320,6 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
JsonVariant(T value, typename TypeTraits::EnableIf< JsonVariant(T value, typename TypeTraits::EnableIf<
TypeTraits::IsSame<T, char>::value>::type * = 0); TypeTraits::IsSame<T, char>::value>::type * = 0);
String toString() const;
Internals::JsonFloat asFloat() const; Internals::JsonFloat asFloat() const;
Internals::JsonInteger asInteger() const; Internals::JsonInteger asInteger() const;
Internals::JsonUInt asUnsignedInteger() const; Internals::JsonUInt asUnsignedInteger() const;
@ -350,27 +352,4 @@ inline JsonVariant float_with_n_digits(float value, uint8_t digits) {
inline JsonVariant double_with_n_digits(double value, uint8_t digits) { inline JsonVariant double_with_n_digits(double value, uint8_t digits) {
return JsonVariant(value, digits); return JsonVariant(value, digits);
} }
template <typename T>
struct JsonVariant::IsConstructibleFrom {
static const bool value =
TypeTraits::IsIntegral<T>::value ||
TypeTraits::IsFloatingPoint<T>::value ||
TypeTraits::IsSame<T, bool>::value ||
TypeTraits::IsSame<T, char *>::value ||
TypeTraits::IsSame<T, const char *>::value ||
TypeTraits::IsSame<T, RawJson>::value ||
TypeTraits::IsSame<T, JsonArray &>::value ||
TypeTraits::IsSame<T, const JsonArray &>::value ||
TypeTraits::IsSame<T, JsonArraySubscript &>::value ||
TypeTraits::IsSame<T, const JsonArraySubscript &>::value ||
TypeTraits::IsSame<T, JsonObject &>::value ||
TypeTraits::IsSame<T, const JsonObject &>::value ||
TypeTraits::IsSame<T, JsonObjectSubscript<const char *> &>::value ||
TypeTraits::IsSame<T, const JsonObjectSubscript<const char *> &>::value ||
TypeTraits::IsSame<T, JsonObjectSubscript<String> &>::value ||
TypeTraits::IsSame<T, const JsonObjectSubscript<String> &>::value ||
TypeTraits::IsSame<T, JsonVariant &>::value ||
TypeTraits::IsSame<T, const JsonVariant &>::value;
};
} }

View File

@ -8,14 +8,14 @@
#pragma once #pragma once
#include "Configuration.hpp" #include "Configuration.hpp"
#include "JsonVariant.hpp"
#include "Internals/Parse.hpp" #include "Internals/Parse.hpp"
#include "JsonArray.hpp" #include "JsonArray.hpp"
#include "JsonObject.hpp" #include "JsonObject.hpp"
#include "JsonVariant.hpp"
#include <string.h> // for strcmp
#include <errno.h> // for errno #include <errno.h> // for errno
#include <stdlib.h> // for strtol, strtod #include <stdlib.h> // for strtol, strtod
#include <string.h> // for strcmp
namespace ArduinoJson { namespace ArduinoJson {
@ -85,17 +85,6 @@ inline Internals::JsonFloat JsonVariant::asFloat() const {
} }
} }
inline String JsonVariant::toString() const {
using namespace Internals;
String s;
if ((_type == JSON_STRING || _type == JSON_UNPARSED) &&
_content.asString != NULL)
s = _content.asString;
else
printTo(s);
return s;
}
inline bool JsonVariant::isBoolean() const { inline bool JsonVariant::isBoolean() const {
using namespace Internals; using namespace Internals;
if (_type == JSON_BOOLEAN) return true; if (_type == JSON_BOOLEAN) return true;

View File

@ -8,7 +8,6 @@
#pragma once #pragma once
#include "Internals/JsonVariantAs.hpp" #include "Internals/JsonVariantAs.hpp"
#include "JsonObjectKey.hpp"
#include "Polyfills/attributes.hpp" #include "Polyfills/attributes.hpp"
namespace ArduinoJson { namespace ArduinoJson {
@ -77,10 +76,9 @@ class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
// Returns the value associated with the specified key if the variant is // Returns the value associated with the specified key if the variant is
// an object. // an object.
// Return JsonVariant::invalid() if the variant is not an object. // Return JsonVariant::invalid() if the variant is not an object.
FORCE_INLINE const JsonObjectSubscript<const char *> operator[]( template <typename TString>
const char *key) const; FORCE_INLINE const JsonObjectSubscript<TString> operator[](
FORCE_INLINE const JsonObjectSubscript<const String &> operator[]( const TString &key) const;
const String &key) const;
private: private:
const TImpl *impl() const { const TImpl *impl() const {

View File

@ -13,7 +13,9 @@ namespace ArduinoJson {
class RawJson { class RawJson {
public: public:
explicit RawJson(const char* str) : _str(str) {} explicit RawJson(const char* str) : _str(str) {}
operator const char*() const { return _str; } operator const char*() const {
return _str;
}
private: private:
const char* _str; const char* _str;

View File

@ -1,24 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#pragma once
#include "Configuration.hpp"
#if ARDUINOJSON_USE_ARDUINO_STRING
#include <WString.h>
#else
#include <string>
namespace ArduinoJson {
typedef std::string String;
}
#endif

View File

@ -0,0 +1,31 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#pragma once
namespace ArduinoJson {
namespace TypeTraits {
// A meta-function that return the type T without the const modifier
template <typename T>
struct ConstRefOrConstPtr {
typedef const T& type;
};
template <typename T>
struct ConstRefOrConstPtr<T*> {
typedef const T* type;
};
template <typename T>
struct ConstRefOrConstPtr<T[]> {
typedef const T* type;
};
template <typename T, size_t N>
struct ConstRefOrConstPtr<T[N]> {
typedef const T* type;
};
}
}

View File

@ -7,7 +7,6 @@
#pragma once #pragma once
#include "../Configuration.hpp"
#include "IsSame.hpp" #include "IsSame.hpp"
#include "IsSignedIntegral.hpp" #include "IsSignedIntegral.hpp"
#include "IsUnsignedIntegral.hpp" #include "IsUnsignedIntegral.hpp"
@ -20,7 +19,11 @@ template <typename T>
struct IsIntegral { struct IsIntegral {
static const bool value = TypeTraits::IsSignedIntegral<T>::value || static const bool value = TypeTraits::IsSignedIntegral<T>::value ||
TypeTraits::IsUnsignedIntegral<T>::value || TypeTraits::IsUnsignedIntegral<T>::value ||
TypeTraits::IsSame<T, char>::value; TypeTraits::IsSame<T, char>::value ||
TypeTraits::IsSame<T, bool>::value;
}; };
template <typename T>
struct IsIntegral<const T> : IsIntegral<T> {};
} }
} }

View File

@ -5,8 +5,8 @@
// https://github.com/bblanchon/ArduinoJson // https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star! // If you like this project, please add a star!
#include <gtest/gtest.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <gtest/gtest.h>
class DynamicJsonBuffer_Basic_Tests : public testing::Test { class DynamicJsonBuffer_Basic_Tests : public testing::Test {
protected: protected:
@ -38,3 +38,16 @@ TEST_F(DynamicJsonBuffer_Basic_Tests, Alignment) {
ASSERT_EQ(0, addr & mask); ASSERT_EQ(0, addr & mask);
} }
} }
TEST_F(DynamicJsonBuffer_Basic_Tests, strdup) {
char original[] = "hello";
char* copy = buffer.strdup(original);
strcpy(original, "world");
ASSERT_STREQ("hello", copy);
}
TEST_F(DynamicJsonBuffer_Basic_Tests, strdup_givenNull) {
const char* original = NULL;
char* copy = buffer.strdup(original);
ASSERT_EQ(NULL, copy);
}

View File

@ -0,0 +1,26 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include <ArduinoJson.h>
#include <gtest/gtest.h>
class JsonObject_Get_Tests : public ::testing::Test {
public:
JsonObject_Get_Tests() : _object(_jsonBuffer.createObject()) {}
protected:
DynamicJsonBuffer _jsonBuffer;
JsonObject& _object;
};
#define TEST_(name) TEST_F(JsonObject_Get_Tests, name)
TEST_(GetConstCharPointer_GivenStringLiteral) {
_object.set("hello", "world");
const char* value = _object.get<const char*>("hello");
EXPECT_STREQ("world", value);
}

View File

@ -5,11 +5,11 @@
// https://github.com/bblanchon/ArduinoJson // https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star! // If you like this project, please add a star!
#include <gtest/gtest.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <gtest/gtest.h>
TEST(JsonObject_Invalid_Tests, SubscriptFails) { TEST(JsonObject_Invalid_Tests, SubscriptFails) {
ASSERT_FALSE(JsonObject::invalid()[0].success()); ASSERT_FALSE(JsonObject::invalid()["key"].success());
} }
TEST(JsonObject_Invalid_Tests, AddFails) { TEST(JsonObject_Invalid_Tests, AddFails) {

View File

@ -5,8 +5,8 @@
// https://github.com/bblanchon/ArduinoJson // https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star! // If you like this project, please add a star!
#include <gtest/gtest.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <gtest/gtest.h>
class JsonObject_Set_Tests : public ::testing::Test { class JsonObject_Set_Tests : public ::testing::Test {
public: public:
@ -112,7 +112,7 @@ TEST_(ShouldReturnTrue_WhenAllocationSucceeds) {
StaticJsonBuffer<JSON_OBJECT_SIZE(1) + 15> jsonBuffer; StaticJsonBuffer<JSON_OBJECT_SIZE(1) + 15> jsonBuffer;
JsonObject& obj = jsonBuffer.createObject(); JsonObject& obj = jsonBuffer.createObject();
bool result = obj.set(String("hello"), String("world")); bool result = obj.set(std::string("hello"), std::string("world"));
ASSERT_TRUE(result); ASSERT_TRUE(result);
} }
@ -121,7 +121,7 @@ TEST_(ShouldReturnFalse_WhenAllocationFails) {
StaticJsonBuffer<JSON_OBJECT_SIZE(1) + 10> jsonBuffer; StaticJsonBuffer<JSON_OBJECT_SIZE(1) + 10> jsonBuffer;
JsonObject& obj = jsonBuffer.createObject(); JsonObject& obj = jsonBuffer.createObject();
bool result = obj.set(String("hello"), String("world")); bool result = obj.set(std::string("hello"), std::string("world"));
ASSERT_FALSE(result); ASSERT_FALSE(result);
} }

View File

@ -24,7 +24,7 @@ TEST(JsonVariant_As_Tests, DoubleAsCstr) {
TEST(JsonVariant_As_Tests, DoubleAsString) { TEST(JsonVariant_As_Tests, DoubleAsString) {
JsonVariant variant = 4.2; JsonVariant variant = 4.2;
ASSERT_EQ(String("4.20"), variant.as<String>()); ASSERT_EQ(std::string("4.20"), variant.as<std::string>());
} }
TEST(JsonVariant_As_Tests, DoubleAsLong) { TEST(JsonVariant_As_Tests, DoubleAsLong) {
@ -64,7 +64,7 @@ TEST(JsonVariant_As_Tests, FalseAsLong) {
TEST(JsonVariant_As_Tests, FalseAsString) { TEST(JsonVariant_As_Tests, FalseAsString) {
JsonVariant variant = false; JsonVariant variant = false;
ASSERT_EQ(String("false"), variant.as<String>()); ASSERT_EQ(std::string("false"), variant.as<std::string>());
} }
TEST(JsonVariant_As_Tests, TrueAsBool) { TEST(JsonVariant_As_Tests, TrueAsBool) {
@ -84,7 +84,7 @@ TEST(JsonVariant_As_Tests, TrueAsLong) {
TEST(JsonVariant_As_Tests, TrueAsString) { TEST(JsonVariant_As_Tests, TrueAsString) {
JsonVariant variant = true; JsonVariant variant = true;
ASSERT_EQ(String("true"), variant.as<String>()); ASSERT_EQ(std::string("true"), variant.as<std::string>());
} }
TEST(JsonVariant_As_Tests, LongAsBool) { TEST(JsonVariant_As_Tests, LongAsBool) {
@ -109,7 +109,7 @@ TEST(JsonVariant_As_Tests, NegativeLongAsDouble) {
TEST(JsonVariant_As_Tests, LongAsString) { TEST(JsonVariant_As_Tests, LongAsString) {
JsonVariant variant = 42L; JsonVariant variant = 42L;
ASSERT_EQ(String("42"), variant.as<String>()); ASSERT_EQ(std::string("42"), variant.as<std::string>());
} }
TEST(JsonVariant_As_Tests, LongZeroAsDouble) { TEST(JsonVariant_As_Tests, LongZeroAsDouble) {
@ -134,7 +134,7 @@ TEST(JsonVariant_As_Tests, NullAsLong) {
TEST(JsonVariant_As_Tests, NullAsString) { TEST(JsonVariant_As_Tests, NullAsString) {
JsonVariant variant = null; JsonVariant variant = null;
ASSERT_EQ(String("null"), variant.as<String>()); ASSERT_EQ(std::string("null"), variant.as<std::string>());
} }
TEST(JsonVariant_As_Tests, NumberStringAsBool) { TEST(JsonVariant_As_Tests, NumberStringAsBool) {
@ -181,7 +181,7 @@ TEST(JsonVariant_As_Tests, RandomStringAsCharPtr) {
TEST(JsonVariant_As_Tests, RandomStringAsString) { TEST(JsonVariant_As_Tests, RandomStringAsString) {
JsonVariant variant = "hello"; JsonVariant variant = "hello";
ASSERT_EQ(String("hello"), variant.as<String>()); ASSERT_EQ(std::string("hello"), variant.as<std::string>());
} }
TEST(JsonVariant_As_Tests, TrueStringAsBool) { TEST(JsonVariant_As_Tests, TrueStringAsBool) {
@ -201,7 +201,7 @@ TEST(JsonVariant_As_Tests, ObjectAsString) {
obj["key"] = "value"; obj["key"] = "value";
JsonVariant variant = obj; JsonVariant variant = obj;
ASSERT_EQ(String("{\"key\":\"value\"}"), variant.as<String>()); ASSERT_EQ(std::string("{\"key\":\"value\"}"), variant.as<std::string>());
} }
TEST(JsonVariant_As_Tests, ArrayAsString) { TEST(JsonVariant_As_Tests, ArrayAsString) {
@ -212,7 +212,7 @@ TEST(JsonVariant_As_Tests, ArrayAsString) {
arr.add(2); arr.add(2);
JsonVariant variant = arr; JsonVariant variant = arr;
ASSERT_EQ(String("[4,2]"), variant.as<String>()); ASSERT_EQ(std::string("[4,2]"), variant.as<std::string>());
} }
TEST(JsonVariant_As_Tests, ArrayAsJsonArray) { TEST(JsonVariant_As_Tests, ArrayAsJsonArray) {

View File

@ -5,12 +5,12 @@
// https://github.com/bblanchon/ArduinoJson // https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star! // If you like this project, please add a star!
#include <gtest/gtest.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <gtest/gtest.h>
class ArduinoStringTests : public ::testing::Test { class StringTests : public ::testing::Test {
protected: protected:
static void eraseString(String &str) { static void eraseString(std::string &str) {
char *p = const_cast<char *>(str.c_str()); char *p = const_cast<char *>(str.c_str());
while (*p) *p++ = '*'; while (*p) *p++ = '*';
} }
@ -18,100 +18,100 @@ class ArduinoStringTests : public ::testing::Test {
DynamicJsonBuffer _jsonBuffer; DynamicJsonBuffer _jsonBuffer;
}; };
TEST_F(ArduinoStringTests, JsonBuffer_ParseArray) { TEST_F(StringTests, JsonBuffer_ParseArray) {
String json("[\"hello\"]"); std::string json("[\"hello\"]");
JsonArray &array = _jsonBuffer.parseArray(json); JsonArray &array = _jsonBuffer.parseArray(json);
eraseString(json); eraseString(json);
ASSERT_TRUE(array.success()); ASSERT_TRUE(array.success());
ASSERT_STREQ("hello", array[0]); ASSERT_STREQ("hello", array[0]);
} }
TEST_F(ArduinoStringTests, JsonBuffer_ParseObject) { TEST_F(StringTests, JsonBuffer_ParseObject) {
String json("{\"hello\":\"world\"}"); std::string json("{\"hello\":\"world\"}");
JsonObject &object = _jsonBuffer.parseObject(json); JsonObject &object = _jsonBuffer.parseObject(json);
eraseString(json); eraseString(json);
ASSERT_TRUE(object.success()); ASSERT_TRUE(object.success());
ASSERT_STREQ("world", object["hello"]); ASSERT_STREQ("world", object["hello"]);
} }
TEST_F(ArduinoStringTests, JsonObject_Subscript) { TEST_F(StringTests, JsonObject_Subscript) {
char json[] = "{\"key\":\"value\"}"; char json[] = "{\"key\":\"value\"}";
JsonObject &object = _jsonBuffer.parseObject(json); JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_STREQ("value", object[String("key")]); ASSERT_STREQ("value", object[std::string("key")]);
} }
TEST_F(ArduinoStringTests, JsonObject_ConstSubscript) { TEST_F(StringTests, JsonObject_ConstSubscript) {
char json[] = "{\"key\":\"value\"}"; char json[] = "{\"key\":\"value\"}";
const JsonObject &object = _jsonBuffer.parseObject(json); const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_STREQ("value", object[String("key")]); ASSERT_STREQ("value", object[std::string("key")]);
} }
TEST_F(ArduinoStringTests, JsonObject_SetKey) { TEST_F(StringTests, JsonObject_SetKey) {
JsonObject &object = _jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
String key("hello"); std::string key("hello");
object.set(key, "world"); object.set(key, "world");
eraseString(key); eraseString(key);
ASSERT_STREQ("world", object["hello"]); ASSERT_STREQ("world", object["hello"]);
} }
TEST_F(ArduinoStringTests, JsonObject_SetValue) { TEST_F(StringTests, JsonObject_SetValue) {
JsonObject &object = _jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
String value("world"); std::string value("world");
object.set("hello", value); object.set("hello", value);
eraseString(value); eraseString(value);
ASSERT_STREQ("world", object["hello"]); ASSERT_STREQ("world", object["hello"]);
} }
TEST_F(ArduinoStringTests, JsonObject_SetKeyValue) { TEST_F(StringTests, JsonObject_SetKeyValue) {
JsonObject &object = _jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
String key("hello"); std::string key("hello");
String value("world"); std::string value("world");
object.set(key, value); object.set(key, value);
eraseString(key); eraseString(key);
eraseString(value); eraseString(value);
ASSERT_STREQ("world", object["hello"]); ASSERT_STREQ("world", object["hello"]);
} }
TEST_F(ArduinoStringTests, JsonObject_SetToArraySubscript) { TEST_F(StringTests, JsonObject_SetToArraySubscript) {
JsonArray &arr = _jsonBuffer.createArray(); JsonArray &arr = _jsonBuffer.createArray();
arr.add("world"); arr.add("world");
JsonObject &object = _jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
object.set(String("hello"), arr[0]); object.set(std::string("hello"), arr[0]);
ASSERT_STREQ("world", object["hello"]); ASSERT_STREQ("world", object["hello"]);
} }
TEST_F(ArduinoStringTests, JsonObject_SetToObjectSubscript) { TEST_F(StringTests, JsonObject_SetToObjectSubscript) {
JsonObject &arr = _jsonBuffer.createObject(); JsonObject &arr = _jsonBuffer.createObject();
arr.set("x", "world"); arr.set("x", "world");
JsonObject &object = _jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
object.set(String("hello"), arr["x"]); object.set(std::string("hello"), arr["x"]);
ASSERT_STREQ("world", object["hello"]); ASSERT_STREQ("world", object["hello"]);
} }
TEST_F(ArduinoStringTests, JsonObject_Get) { TEST_F(StringTests, JsonObject_Get) {
char json[] = "{\"key\":\"value\"}"; char json[] = "{\"key\":\"value\"}";
const JsonObject &object = _jsonBuffer.parseObject(json); const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_STREQ("value", object.get(String("key"))); ASSERT_STREQ("value", object.get<const char *>(std::string("key")));
} }
TEST_F(ArduinoStringTests, JsonObject_GetT) { TEST_F(StringTests, JsonObject_GetT) {
char json[] = "{\"key\":\"value\"}"; char json[] = "{\"key\":\"value\"}";
const JsonObject &object = _jsonBuffer.parseObject(json); const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_STREQ("value", object.get<const char *>(String("key"))); ASSERT_STREQ("value", object.get<const char *>(std::string("key")));
} }
TEST_F(ArduinoStringTests, JsonObject_IsT) { TEST_F(StringTests, JsonObject_IsT) {
char json[] = "{\"key\":\"value\"}"; char json[] = "{\"key\":\"value\"}";
const JsonObject &object = _jsonBuffer.parseObject(json); const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_TRUE(object.is<const char *>(String("key"))); ASSERT_TRUE(object.is<const char *>(std::string("key")));
} }
TEST_F(ArduinoStringTests, JsonObject_CreateNestedObject) { TEST_F(StringTests, JsonObject_CreateNestedObject) {
String key = "key"; std::string key = "key";
char json[64]; char json[64];
JsonObject &object = _jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
object.createNestedObject(key); object.createNestedObject(key);
@ -120,8 +120,8 @@ TEST_F(ArduinoStringTests, JsonObject_CreateNestedObject) {
ASSERT_STREQ("{\"key\":{}}", json); ASSERT_STREQ("{\"key\":{}}", json);
} }
TEST_F(ArduinoStringTests, JsonObject_CreateNestedArray) { TEST_F(StringTests, JsonObject_CreateNestedArray) {
String key = "key"; std::string key = "key";
char json[64]; char json[64];
JsonObject &object = _jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
object.createNestedArray(key); object.createNestedArray(key);
@ -130,99 +130,99 @@ TEST_F(ArduinoStringTests, JsonObject_CreateNestedArray) {
ASSERT_STREQ("{\"key\":[]}", json); ASSERT_STREQ("{\"key\":[]}", json);
} }
TEST_F(ArduinoStringTests, JsonObject_ContainsKey) { TEST_F(StringTests, JsonObject_ContainsKey) {
char json[] = "{\"key\":\"value\"}"; char json[] = "{\"key\":\"value\"}";
const JsonObject &object = _jsonBuffer.parseObject(json); const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_TRUE(object.containsKey(String("key"))); ASSERT_TRUE(object.containsKey(std::string("key")));
} }
TEST_F(ArduinoStringTests, JsonObject_Remove) { TEST_F(StringTests, JsonObject_Remove) {
char json[] = "{\"key\":\"value\"}"; char json[] = "{\"key\":\"value\"}";
JsonObject &object = _jsonBuffer.parseObject(json); JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_EQ(1, object.size()); ASSERT_EQ(1, object.size());
object.remove(String("key")); object.remove(std::string("key"));
ASSERT_EQ(0, object.size()); ASSERT_EQ(0, object.size());
} }
TEST_F(ArduinoStringTests, JsonObjectSubscript_SetKey) { TEST_F(StringTests, JsonObjectSubscript_SetKey) {
JsonObject &object = _jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
String key("hello"); std::string key("hello");
object[key] = "world"; object[key] = "world";
eraseString(key); eraseString(key);
ASSERT_STREQ("world", object["hello"]); ASSERT_STREQ("world", object["hello"]);
} }
TEST_F(ArduinoStringTests, JsonObjectSubscript_SetValue) { TEST_F(StringTests, JsonObjectSubscript_SetValue) {
JsonObject &object = _jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
String value("world"); std::string value("world");
object["hello"] = value; object["hello"] = value;
eraseString(value); eraseString(value);
ASSERT_STREQ("world", object["hello"]); ASSERT_STREQ("world", object["hello"]);
} }
TEST_F(ArduinoStringTests, JsonArray_Add) { TEST_F(StringTests, JsonArray_Add) {
JsonArray &array = _jsonBuffer.createArray(); JsonArray &array = _jsonBuffer.createArray();
String value("hello"); std::string value("hello");
array.add(value); array.add(value);
eraseString(value); eraseString(value);
ASSERT_STREQ("hello", array[0]); ASSERT_STREQ("hello", array[0]);
} }
TEST_F(ArduinoStringTests, JsonArray_Set) { TEST_F(StringTests, JsonArray_Set) {
JsonArray &array = _jsonBuffer.createArray(); JsonArray &array = _jsonBuffer.createArray();
String value("world"); std::string value("world");
array.add("hello"); array.add("hello");
array.set(0, value); array.set(0, value);
eraseString(value); eraseString(value);
ASSERT_STREQ("world", array[0]); ASSERT_STREQ("world", array[0]);
} }
TEST_F(ArduinoStringTests, JsonArraySubscript) { TEST_F(StringTests, JsonArraySubscript) {
JsonArray &array = _jsonBuffer.createArray(); JsonArray &array = _jsonBuffer.createArray();
String value("world"); std::string value("world");
array.add("hello"); array.add("hello");
array[0] = value; array[0] = value;
eraseString(value); eraseString(value);
ASSERT_STREQ("world", array[0]); ASSERT_STREQ("world", array[0]);
} }
TEST_F(ArduinoStringTests, JsonArray_PrintTo) { TEST_F(StringTests, JsonArray_PrintTo) {
JsonArray &array = _jsonBuffer.createArray(); JsonArray &array = _jsonBuffer.createArray();
array.add(4); array.add(4);
array.add(2); array.add(2);
String json; std::string json;
array.printTo(json); array.printTo(json);
ASSERT_EQ(String("[4,2]"), json); ASSERT_EQ(std::string("[4,2]"), json);
} }
TEST_F(ArduinoStringTests, JsonArray_PrettyPrintTo) { TEST_F(StringTests, JsonArray_PrettyPrintTo) {
JsonArray &array = _jsonBuffer.createArray(); JsonArray &array = _jsonBuffer.createArray();
array.add(4); array.add(4);
array.add(2); array.add(2);
String json; std::string json;
array.prettyPrintTo(json); array.prettyPrintTo(json);
ASSERT_EQ(String("[\r\n 4,\r\n 2\r\n]"), json); ASSERT_EQ(std::string("[\r\n 4,\r\n 2\r\n]"), json);
} }
TEST_F(ArduinoStringTests, JsonObject_PrintTo) { TEST_F(StringTests, JsonObject_PrintTo) {
JsonObject &object = _jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
object["key"] = "value"; object["key"] = "value";
String json; std::string json;
object.printTo(json); object.printTo(json);
ASSERT_EQ(String("{\"key\":\"value\"}"), json); ASSERT_EQ(std::string("{\"key\":\"value\"}"), json);
} }
TEST_F(ArduinoStringTests, JsonObject_PrettyPrintTo) { TEST_F(StringTests, JsonObject_PrettyPrintTo) {
JsonObject &object = _jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
object["key"] = "value"; object["key"] = "value";
String json; std::string json;
object.prettyPrintTo(json); object.prettyPrintTo(json);
ASSERT_EQ(String("{\r\n \"key\": \"value\"\r\n}"), json); ASSERT_EQ(std::string("{\r\n \"key\": \"value\"\r\n}"), json);
} }
TEST_F(ArduinoStringTests, JsonBuffer_GrowWhenAddingNewKey) { TEST_F(StringTests, JsonBuffer_GrowWhenAddingNewKey) {
JsonObject &object = _jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
String key1("hello"), key2("world"); std::string key1("hello"), key2("world");
object[key1] = 1; object[key1] = 1;
size_t sizeBefore = _jsonBuffer.size(); size_t sizeBefore = _jsonBuffer.size();
@ -232,9 +232,9 @@ TEST_F(ArduinoStringTests, JsonBuffer_GrowWhenAddingNewKey) {
ASSERT_GT(sizeAfter - sizeBefore, key2.size()); ASSERT_GT(sizeAfter - sizeBefore, key2.size());
} }
TEST_F(ArduinoStringTests, JsonBuffer_DontGrowWhenReusingKey) { TEST_F(StringTests, JsonBuffer_DontGrowWhenReusingKey) {
JsonObject &object = _jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
String key("hello"); std::string key("hello");
object[key] = 1; object[key] = 1;
size_t sizeBefore = _jsonBuffer.size(); size_t sizeBefore = _jsonBuffer.size();
@ -243,3 +243,10 @@ TEST_F(ArduinoStringTests, JsonBuffer_DontGrowWhenReusingKey) {
ASSERT_EQ(sizeBefore, sizeAfter); ASSERT_EQ(sizeBefore, sizeAfter);
} }
TEST_F(StringTests, JsonBuffer_strdup) {
std::string original("hello");
char *copy = _jsonBuffer.strdup(original);
original[0] = 'w';
ASSERT_STREQ("hello", copy);
}