Renamed function RawJson() to serialized()

This commit is contained in:
Benoit Blanchon
2018-07-12 09:08:20 +02:00
parent 765752261c
commit 87fa87d87b
59 changed files with 842 additions and 550 deletions

View File

@ -6,11 +6,29 @@ HEAD
* Disabled lazy number deserialization (issue #772)
* Improved float serialization when `-fsingle-precision-constant` is used
* Renamed function `RawJson()` to `serialized()`
* `serializeMsgPack()` now supports values marked with `serialized()`
> ### BREAKING CHANGES
>
> #### Non quoted strings
>
> Non quoted strings are now forbidden in values, but they are still allowed in keys.
> For example, `{key:"value"}` is accepted, but `{key:value}` is not.
>
> #### Preformatted values
>
> Old code:
>
> ```c++
> object["values"] = RawJson("[1,2,3,4]");
> ```
>
> New code:
>
> ```c++
> object["values"] = serialized("[1,2,3,4]");
> ```
v6.1.0-beta
-----------

View File

@ -37,8 +37,9 @@ void setup() {
// JsonBuffer.
obj["sensor"] = F("gps");
// It works with RawJson too:
obj["sensor"] = RawJson(F("\"gps\""));
// It works with serialized() too:
obj["sensor"] = serialized(F("\"gps\""));
obj["sensor"] = serialized(F("\xA3gps"), 3);
// You can compare the content of a JsonVariant to a Flash String
if (obj["sensor"] == F("gps")) {

View File

@ -41,8 +41,8 @@ void setup() {
// WARNING: the content of the String will be duplicated in the JsonBuffer.
obj["sensor"] = sensor;
// It works with RawJson too:
obj["sensor"] = RawJson(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.

View File

@ -18,9 +18,13 @@ struct JsonObjectData;
union JsonVariantContent {
JsonFloat asFloat; // used for double and float
JsonUInt asInteger; // used for bool, char, short, int and longs
const char* asString; // asString can be null
JsonArrayData* asArray; // asArray cannot be null
JsonObjectData* asObject; // asObject cannot be null
const char* asString; // asString can be null
struct {
const char* data;
size_t size;
} asRaw;
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -7,7 +7,7 @@
#include "../JsonVariant.hpp"
#include "../Memory/JsonBuffer.hpp"
#include "../Polyfills/type_traits.hpp"
#include "../Strings/StringTraits.hpp"
#include "../Strings/StringTypes.hpp"
namespace ArduinoJson {
namespace Internals {
@ -21,30 +21,31 @@ struct ValueSaver {
}
};
template <typename Source>
// We duplicate all strings except const char*
template <typename TString>
struct ValueSaver<
Source, typename enable_if<StringTraits<Source>::should_duplicate>::type> {
TString, typename enable_if<IsString<TString>::value &&
!is_same<const char*, TString>::value>::type> {
template <typename Destination>
static bool save(JsonBuffer* buffer, Destination& dest, Source source) {
if (!StringTraits<Source>::is_null(source)) {
typename StringTraits<Source>::duplicate_t dup =
StringTraits<Source>::duplicate(source, buffer);
static bool save(JsonBuffer* buffer, Destination& dest, TString source) {
const char* dup = makeString(source).save(buffer);
if (!dup) return false;
dest = dup;
} else {
dest = reinterpret_cast<const char*>(0);
}
return true;
}
};
// const char*, const signed char*, const unsigned char*
template <typename Char>
// We duplicate all SerializedValue<T> except SerializedValue<const char*>
template <typename TString>
struct ValueSaver<
Char*, typename enable_if<!StringTraits<Char*>::should_duplicate>::type> {
const SerializedValue<TString>&,
typename enable_if<!is_same<const char*, TString>::value>::type> {
template <typename Destination>
static bool save(JsonBuffer*, Destination& dest, Char* source) {
dest = reinterpret_cast<const char*>(source);
static bool save(JsonBuffer* buffer, Destination& dest,
const SerializedValue<TString>& source) {
const char* dup = makeString(source.data(), source.size()).save(buffer);
if (!dup) return false;
dest = SerializedValue<const char*>(dup, source.size());
return true;
}
};

View File

@ -19,19 +19,22 @@ class IndentedPrint {
isNewLine = true;
}
size_t print(char c) {
size_t write(uint8_t c) {
size_t n = 0;
if (isNewLine) n += writeTabs();
n += sink->print(c);
n += sink->write(c);
isNewLine = c == '\n';
return n;
}
size_t print(const char *s) {
size_t write(const uint8_t *s, size_t n) {
// TODO: optimize
size_t n = 0;
while (*s) n += print(*s++);
return n;
size_t bytesWritten = 0;
while (n > 0) {
bytesWritten += write(*s++);
n--;
}
return bytesWritten;
}
// Adds one level of indentation
@ -57,7 +60,7 @@ class IndentedPrint {
size_t writeTabs() {
size_t n = 0;
for (int i = 0; i < level * tabSize; i++) n += sink->print(' ');
for (int i = 0; i < level * tabSize; i++) n += sink->write(' ');
return n;
}

View File

@ -11,10 +11,10 @@
namespace ArduinoJson {
namespace Internals {
template <typename TPrint>
template <typename TWriter>
class JsonSerializer {
public:
JsonSerializer(TPrint &destination) : _writer(destination) {}
JsonSerializer(TWriter &writer) : _writer(writer) {}
void acceptFloat(JsonFloat value) {
_writer.writeFloat(value);
@ -58,8 +58,9 @@ class JsonSerializer {
_writer.writeString(value);
}
void acceptRawJson(const char *value) {
_writer.writeRaw(value);
void acceptRawJson(const char *data, size_t n) {
// TODO
for (size_t i = 0; i < n; i++) _writer.writeRaw(data[i]);
}
void acceptNegativeInteger(JsonUInt value) {
@ -84,7 +85,7 @@ class JsonSerializer {
}
private:
JsonWriter<TPrint> _writer;
JsonWriter<TWriter> _writer;
};
} // namespace Internals

View File

@ -5,6 +5,7 @@
#pragma once
#include <stdint.h>
#include <string.h> // for strlen
#include "../Data/JsonInteger.hpp"
#include "../Numbers/FloatParts.hpp"
#include "../Polyfills/attributes.hpp"
@ -13,12 +14,12 @@
namespace ArduinoJson {
namespace Internals {
template <typename Print>
template <typename TWriter>
class JsonWriter {
public:
explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {}
explicit JsonWriter(TWriter &writer) : _writer(writer), _length(0) {}
// Returns the number of bytes sent to the Print implementation.
// Returns the number of bytes sent to the TWriter implementation.
size_t bytesWritten() const {
return _length;
}
@ -45,7 +46,10 @@ class JsonWriter {
}
void writeBoolean(bool value) {
writeRaw(value ? "true" : "false");
if (value)
writeRaw("true");
else
writeRaw("false");
}
void writeString(const char *value) {
@ -98,45 +102,53 @@ class JsonWriter {
template <typename UInt>
void writeInteger(UInt value) {
char buffer[22];
char *end = buffer + sizeof(buffer) - 1;
char *ptr = end;
char *end = buffer + sizeof(buffer);
char *begin = end;
*ptr = 0;
// write the string in reverse order
do {
*--ptr = char(value % 10 + '0');
*--begin = char(value % 10 + '0');
value = UInt(value / 10);
} while (value);
writeRaw(ptr);
// and dump it in the right order
writeRaw(begin, end);
}
void writeDecimals(uint32_t value, int8_t width) {
// buffer should be big enough for all digits, the dot and the null
// terminator
// buffer should be big enough for all digits and the dot
char buffer[16];
char *ptr = buffer + sizeof(buffer) - 1;
char *end = buffer + sizeof(buffer);
char *begin = end;
// write the string in reverse order
*ptr = 0;
while (width--) {
*--ptr = char(value % 10 + '0');
*--begin = char(value % 10 + '0');
value /= 10;
}
*--ptr = '.';
*--begin = '.';
// and dump it in the right order
writeRaw(ptr);
writeRaw(begin, end);
}
void writeRaw(const char *s) {
_length += _sink.print(s);
_length += _writer.write(reinterpret_cast<const uint8_t *>(s), strlen(s));
}
void writeRaw(const char *begin, const char *end) {
_length += _writer.write(reinterpret_cast<const uint8_t *>(begin),
static_cast<size_t>(end - begin));
}
template <size_t N>
void writeRaw(const char (&s)[N]) {
_length += _writer.write(reinterpret_cast<const uint8_t *>(s), N - 1);
}
void writeRaw(char c) {
_length += _sink.print(c);
_length += _writer.write(static_cast<uint8_t>(c));
}
protected:
Print &_sink;
TWriter &_writer;
size_t _length;
private:

View File

@ -10,25 +10,28 @@ namespace ArduinoJson {
namespace Internals {
// Converts a compact JSON string into an indented one.
template <typename Print>
template <typename TWriter>
class Prettyfier {
public:
explicit Prettyfier(IndentedPrint<Print>& p) : _sink(p) {
explicit Prettyfier(IndentedPrint<TWriter>& p) : _sink(p) {
_previousChar = 0;
_inString = false;
}
size_t print(char c) {
size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c);
_previousChar = c;
size_t write(uint8_t c) {
size_t n = _inString ? handleStringChar(c) : handleMarkupChar(char(c));
_previousChar = char(c);
return n;
}
size_t print(const char* s) {
size_t write(const uint8_t* s, size_t n) {
// TODO: optimize
size_t n = 0;
while (*s) n += print(*s++);
return n;
size_t bytesWritten = 0;
while (n > 0) {
bytesWritten += write(*s++);
n--;
}
return bytesWritten;
}
private:
@ -38,12 +41,12 @@ class Prettyfier {
return _previousChar == '{' || _previousChar == '[';
}
size_t handleStringChar(char c) {
size_t handleStringChar(uint8_t c) {
bool isQuote = c == '"' && _previousChar != '\\';
if (isQuote) _inString = false;
return _sink.print(c);
return _sink.write(c);
}
size_t handleMarkupChar(char c) {
@ -73,26 +76,26 @@ class Prettyfier {
size_t writeBlockClose(char c) {
size_t n = 0;
n += unindentIfNeeded();
n += _sink.print(c);
n += write(c);
return n;
}
size_t writeBlockOpen(char c) {
size_t n = 0;
n += indentIfNeeded();
n += _sink.print(c);
n += write(c);
return n;
}
size_t writeColon() {
size_t n = 0;
n += _sink.print(": ");
n += write(": ");
return n;
}
size_t writeComma() {
size_t n = 0;
n += _sink.print(",\r\n");
n += write(",\r\n");
return n;
}
@ -100,14 +103,14 @@ class Prettyfier {
_inString = true;
size_t n = 0;
n += indentIfNeeded();
n += _sink.print('"');
n += write('"');
return n;
}
size_t writeNormalChar(char c) {
size_t n = 0;
n += indentIfNeeded();
n += _sink.print(c);
n += write(c);
return n;
}
@ -115,19 +118,28 @@ class Prettyfier {
if (!inEmptyBlock()) return 0;
_sink.indent();
return _sink.print("\r\n");
return write("\r\n");
}
size_t unindentIfNeeded() {
if (inEmptyBlock()) return 0;
_sink.unindent();
return _sink.print("\r\n");
return write("\r\n");
}
size_t write(char c) {
return _sink.write(static_cast<uint8_t>(c));
}
template <size_t N>
size_t write(const char (&s)[N]) {
return _sink.write(reinterpret_cast<const uint8_t*>(s), N - 1);
}
char _previousChar;
IndentedPrint<Print>& _sink;
IndentedPrint<TWriter>& _sink;
bool _inString;
};
}
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -29,7 +29,7 @@ class JsonArray {
// Adds the specified value at the end of the array.
//
// bool add(TValue);
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArrayData, JsonObject
template <typename T>
bool add(const T& value) {
@ -154,7 +154,7 @@ class JsonArray {
// Sets the value at specified index.
//
// bool add(size_t index, const TValue&);
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArrayData, JsonObject
template <typename T>
bool set(size_t index, const T& value) {

View File

@ -9,7 +9,6 @@
#include "JsonVariant.hpp"
#include "Memory/JsonBufferAllocated.hpp"
#include "Polyfills/type_traits.hpp"
#include "Strings/StringTraits.hpp"
// Returns the size (in bytes) of an array with n elements.
// Can be very handy to determine the size of a StaticJsonBuffer.

View File

@ -27,7 +27,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
// Replaces the value
//
// operator=(const TValue&)
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename T>
FORCE_INLINE JsonArraySubscript& operator=(const T& src) {
@ -60,7 +60,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
// Replaces the value
//
// bool set(const TValue&)
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename TValue>
FORCE_INLINE bool set(const TValue& value) {

View File

@ -188,7 +188,7 @@ class JsonObject {
//
// bool set(TKey, TValue);
// TKey = const std::string&, const String&
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename TValue, typename TString>
bool set(const TString& key, const TValue& value) {
@ -205,7 +205,7 @@ class JsonObject {
//
// bool set(TKey, const TValue&);
// TKey = char*, const char*, const FlashStringHelper*
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename TValue, typename TString>
bool set(TString* key, const TValue& value) {
@ -254,7 +254,7 @@ class JsonObject {
iterator findKey(TStringRef key) {
iterator it;
for (it = begin(); it != end(); ++it) {
if (Internals::StringTraits<TStringRef>::equals(key, it->key)) break;
if (Internals::makeString(key).equals(it->key)) break;
}
return it;
}
@ -288,7 +288,7 @@ class JsonObject {
if (!_data) return false;
// ignore null key
if (Internals::StringTraits<TStringRef>::is_null(key)) return false;
if (Internals::makeString(key).is_null()) return false;
// search a matching key
iterator it = findKey<TStringRef>(key);

View File

@ -9,7 +9,6 @@
#include "JsonPair.hpp"
#include "Memory/JsonBufferAllocated.hpp"
#include "Polyfills/type_traits.hpp"
#include "Strings/StringTraits.hpp"
// Returns the size (in bytes) of an object with n elements.
// Can be very handy to determine the size of a StaticJsonBuffer.

View File

@ -67,7 +67,8 @@ class JsonObjectSubscript
// Sets the specified value.
//
// bool set(const TValue&);
// TValue = bool, char, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, char, long, int, short, float, double, serialized,
// JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename TValue>
FORCE_INLINE typename enable_if<!is_array<TValue>::value, bool>::type set(
@ -94,7 +95,7 @@ class JsonObjectSubscript
template <typename TImpl>
template <typename TString>
inline typename enable_if<StringTraits<TString>::has_equals,
inline typename enable_if<IsString<TString>::value,
const JsonObjectSubscript<const TString &> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString &key) const {
return impl()->template as<JsonObject>()[key];
@ -102,7 +103,7 @@ inline typename enable_if<StringTraits<TString>::has_equals,
template <typename TImpl>
template <typename TString>
inline typename enable_if<StringTraits<TString>::has_equals,
inline typename enable_if<IsString<TString>::value,
JsonObjectSubscript<const TString &> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString &key) {
return impl()->template as<JsonObject>()[key];
@ -110,7 +111,7 @@ inline typename enable_if<StringTraits<TString>::has_equals,
template <typename TImpl>
template <typename TString>
inline typename enable_if<StringTraits<const TString *>::has_equals,
inline typename enable_if<IsString<const TString *>::value,
JsonObjectSubscript<const TString *> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString *key) {
return impl()->template as<JsonObject>()[key];
@ -118,7 +119,7 @@ inline typename enable_if<StringTraits<const TString *>::has_equals,
template <typename TImpl>
template <typename TString>
inline typename enable_if<StringTraits<TString *>::has_equals,
inline typename enable_if<IsString<TString *>::value,
const JsonObjectSubscript<const TString *> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString *key) const {
return impl()->template as<JsonObject>()[key];

View File

@ -12,7 +12,8 @@
#include "Data/JsonVariantType.hpp"
#include "JsonVariantBase.hpp"
#include "Polyfills/type_traits.hpp"
#include "RawJson.hpp"
#include "Serialization/DynamicStringWriter.hpp"
#include "SerializedValue.hpp"
namespace ArduinoJson {
@ -99,9 +100,10 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
}
// Create a JsonVariant containing an unparsed string
JsonVariant(Internals::RawJsonString<const char *> value) {
JsonVariant(Internals::SerializedValue<const char *> value) {
_type = Internals::JSON_UNPARSED;
_content.asString = value;
_content.asRaw.data = value.data();
_content.asRaw.size = value.size();
}
JsonVariant(JsonArray array);
@ -153,7 +155,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
// std::string as<std::string>() const;
// String as<String>() const;
template <typename T>
typename Internals::enable_if<Internals::StringTraits<T>::has_append, T>::type
typename Internals::enable_if<Internals::IsWriteableString<T>::value, T>::type
as() const {
const char *cstr = variantAsString();
if (cstr) return T(cstr);
@ -276,7 +278,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
return visitor.acceptString(_content.asString);
case JSON_UNPARSED:
return visitor.acceptRawJson(_content.asString);
return visitor.acceptRawJson(_content.asRaw.data, _content.asRaw.size);
case JSON_NEGATIVE_INTEGER:
return visitor.acceptNegativeInteger(_content.asInteger);
@ -310,9 +312,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
return _type == Internals::JSON_OBJECT;
}
bool variantIsString() const {
return _type == Internals::JSON_STRING ||
(_type == Internals::JSON_UNPARSED && _content.asString &&
!strcmp("null", _content.asString));
return _type == Internals::JSON_STRING;
}
// The current type of the variant

View File

@ -6,7 +6,7 @@
#include "Data/IsVariant.hpp"
#include "Polyfills/type_traits.hpp"
#include "Strings/StringTraits.hpp"
#include "Strings/StringTypes.hpp"
namespace ArduinoJson {
class JsonArray;
@ -104,16 +104,14 @@ class JsonVariantComparisons {
}
template <typename TString>
typename enable_if<StringTraits<TString>::has_equals, bool>::type equals(
typename enable_if<IsString<TString>::value, bool>::type equals(
const TString &comparand) const {
const char *value = as<const char *>();
return StringTraits<TString>::equals(comparand, value);
return makeString(comparand).equals(as<const char *>());
}
template <typename TComparand>
typename enable_if<!IsVariant<TComparand>::value &&
!StringTraits<TComparand>::has_equals,
bool>::type
typename enable_if<
!IsVariant<TComparand>::value && !IsString<TComparand>::value, bool>::type
equals(const TComparand &comparand) const {
return as<TComparand>() == comparand;
}
@ -132,8 +130,7 @@ class JsonVariantComparisons {
if (is<JsonObject>() && right.template is<JsonObject>())
return as<JsonObject>() == right.template as<JsonObject>();
if (is<char *>() && right.template is<char *>())
return StringTraits<const char *>::equals(as<char *>(),
right.template as<char *>());
return makeString(as<char *>()).equals(right.template as<char *>());
return false;
}

View File

@ -68,6 +68,7 @@ inline T JsonVariant::variantAsInteger() const {
using namespace Internals;
switch (_type) {
case JSON_UNDEFINED:
case JSON_UNPARSED:
return 0;
case JSON_POSITIVE_INTEGER:
case JSON_BOOLEAN:
@ -75,7 +76,6 @@ inline T JsonVariant::variantAsInteger() const {
case JSON_NEGATIVE_INTEGER:
return T(~_content.asInteger + 1);
case JSON_STRING:
case JSON_UNPARSED:
return parseInteger<T>(_content.asString);
default:
return T(_content.asFloat);
@ -84,11 +84,7 @@ inline T JsonVariant::variantAsInteger() const {
inline const char *JsonVariant::variantAsString() const {
using namespace Internals;
if (_type == JSON_UNPARSED && _content.asString &&
!strcmp("null", _content.asString))
return NULL;
if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString;
return NULL;
return _type == JSON_STRING ? _content.asString : NULL;
}
template <typename T>
@ -96,6 +92,7 @@ inline T JsonVariant::variantAsFloat() const {
using namespace Internals;
switch (_type) {
case JSON_UNDEFINED:
case JSON_UNPARSED:
return 0;
case JSON_POSITIVE_INTEGER:
case JSON_BOOLEAN:
@ -103,7 +100,6 @@ inline T JsonVariant::variantAsFloat() const {
case JSON_NEGATIVE_INTEGER:
return -static_cast<T>(_content.asInteger);
case JSON_STRING:
case JSON_UNPARSED:
return parseFloat<T>(_content.asString);
default:
return static_cast<T>(_content.asFloat);
@ -112,27 +108,20 @@ inline T JsonVariant::variantAsFloat() const {
inline bool JsonVariant::variantIsBoolean() const {
using namespace Internals;
if (_type == JSON_BOOLEAN) return true;
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
return !strcmp(_content.asString, "true") ||
!strcmp(_content.asString, "false");
return _type == JSON_BOOLEAN;
}
inline bool JsonVariant::variantIsInteger() const {
using namespace Internals;
return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER ||
(_type == JSON_UNPARSED && isInteger(_content.asString));
return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER;
}
inline bool JsonVariant::variantIsFloat() const {
using namespace Internals;
return _type == JSON_FLOAT || _type == JSON_POSITIVE_INTEGER ||
_type == JSON_NEGATIVE_INTEGER ||
(_type == JSON_UNPARSED && isFloat(_content.asString));
_type == JSON_NEGATIVE_INTEGER;
}
} // namespace ArduinoJson

View File

@ -7,7 +7,7 @@
#include "Data/JsonVariantAs.hpp"
#include "Polyfills/attributes.hpp"
#include "Polyfills/type_traits.hpp"
#include "Strings/StringTraits.hpp"
#include "Strings/StringTypes.hpp"
namespace ArduinoJson {
class JsonArray;
@ -43,21 +43,21 @@ class JsonVariantSubscripts {
// TKey = const std::string&, const String&
template <typename TString>
FORCE_INLINE
typename enable_if<StringTraits<TString>::has_equals,
typename enable_if<IsString<TString>::value,
const JsonObjectSubscript<const TString &> >::type
operator[](const TString &key) const;
//
// const JsonObjectSubscript operator[](TKey) const;
// TKey = const std::string&, const String&
template <typename TString>
FORCE_INLINE typename enable_if<StringTraits<TString>::has_equals,
FORCE_INLINE typename enable_if<IsString<TString>::value,
JsonObjectSubscript<const TString &> >::type
operator[](const TString &key);
//
// JsonObjectSubscript operator[](TKey);
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
FORCE_INLINE typename enable_if<StringTraits<const TString *>::has_equals,
FORCE_INLINE typename enable_if<IsString<const TString *>::value,
JsonObjectSubscript<const TString *> >::type
operator[](const TString *key);
//
@ -65,7 +65,7 @@ class JsonVariantSubscripts {
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
FORCE_INLINE
typename enable_if<StringTraits<TString *>::has_equals,
typename enable_if<IsString<TString *>::value,
const JsonObjectSubscript<const TString *> >::type
operator[](const TString *key) const;

View File

@ -13,10 +13,10 @@
namespace ArduinoJson {
namespace Internals {
template <typename TPrint>
template <typename TWriter>
class MsgPackSerializer {
public:
MsgPackSerializer(TPrint& output) : _output(&output), _bytesWritten(0) {}
MsgPackSerializer(TWriter& writer) : _writer(&writer), _bytesWritten(0) {}
template <typename T>
typename enable_if<sizeof(T) == 4>::type acceptFloat(T value32) {
@ -91,7 +91,9 @@ class MsgPackSerializer {
writeBytes(reinterpret_cast<const uint8_t*>(value), n);
}
void acceptRawJson(const char* /*value*/) {}
void acceptRawJson(const char* data, size_t size) {
writeBytes(reinterpret_cast<const uint8_t*>(data), size);
}
void acceptNegativeInteger(JsonUInt value) {
JsonUInt negated = JsonUInt(~value + 1);
@ -150,12 +152,11 @@ class MsgPackSerializer {
private:
void writeByte(uint8_t c) {
_output->print(char(c));
_bytesWritten++;
_bytesWritten += _writer->write(c);
}
void writeBytes(const uint8_t* c, size_t n) {
for (; n > 0; --n, ++c) writeByte(*c);
void writeBytes(const uint8_t* p, size_t n) {
_bytesWritten += _writer->write(p, n);
}
template <typename T>
@ -164,7 +165,7 @@ class MsgPackSerializer {
writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
}
TPrint* _output;
TWriter* _writer;
size_t _bytesWritten;
};
} // namespace Internals

View File

@ -1,46 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
// A special type of data that can be used to insert pregenerated JSON portions.
template <typename T>
class RawJsonString {
public:
explicit RawJsonString(T str) : _str(str) {}
operator T() const {
return _str;
}
private:
T _str;
};
template <typename String>
struct StringTraits<RawJsonString<String>, void> {
static bool is_null(RawJsonString<String> source) {
return StringTraits<String>::is_null(static_cast<String>(source));
}
typedef RawJsonString<const char*> duplicate_t;
template <typename Buffer>
static duplicate_t duplicate(RawJsonString<String> source, Buffer* buffer) {
return duplicate_t(StringTraits<String>::duplicate(source, buffer));
}
static const bool has_append = false;
static const bool has_equals = false;
static const bool should_duplicate = StringTraits<String>::should_duplicate;
};
}
template <typename T>
inline Internals::RawJsonString<T> RawJson(T str) {
return Internals::RawJsonString<T>(str);
}
}

View File

@ -7,14 +7,14 @@
namespace ArduinoJson {
namespace Internals {
class DummyPrint {
class DummyWriter {
public:
size_t print(char) {
size_t write(uint8_t) {
return 1;
}
size_t print(const char* s) {
return strlen(s);
size_t write(const uint8_t*, size_t n) {
return n;
}
};
} // namespace Internals

View File

@ -1,35 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Strings/StringTraits.hpp"
namespace ArduinoJson {
namespace Internals {
// A Print implementation that allows to write in a String
template <typename TString>
class DynamicStringBuilder {
public:
DynamicStringBuilder(TString &str) : _str(str) {}
size_t print(char c) {
StringTraits<TString>::append(_str, c);
return 1;
}
size_t print(const char *s) {
size_t initialLen = _str.length();
StringTraits<TString>::append(_str, s);
return _str.length() - initialLen;
}
private:
DynamicStringBuilder &operator=(const DynamicStringBuilder &);
TString &_str;
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,81 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Polyfills/type_traits.hpp"
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <WString.h>
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
#include <string>
#endif
namespace ArduinoJson {
namespace Internals {
template <typename>
struct IsWriteableString : false_type {};
// A Print implementation that allows to write in a String
template <typename TString>
class DynamicStringWriter {};
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
template <>
struct IsWriteableString<String> : true_type {};
template <>
class DynamicStringWriter<String> {
public:
DynamicStringWriter(String &str) : _str(&str) {}
size_t write(uint8_t c) {
_str->operator+=(static_cast<char>(c));
return 1;
}
size_t write(const uint8_t *s, size_t n) {
// CAUTION: Arduino String doesn't have append()
// and old version doesn't have size() either
_str->reserve(_str->length() + n);
while (n > 0) {
_str->operator+=(static_cast<char>(*s++));
n--;
}
return n;
}
private:
String *_str;
};
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
template <>
struct IsWriteableString<std::string> : true_type {};
template <>
class DynamicStringWriter<std::string> {
public:
DynamicStringWriter(std::string &str) : _str(&str) {}
size_t write(uint8_t c) {
_str->operator+=(static_cast<char>(c));
return 1;
}
size_t write(const uint8_t *s, size_t n) {
_str->append(reinterpret_cast<const char *>(s), n);
return n;
}
private:
std::string *_str;
};
#endif
} // namespace Internals
} // namespace ArduinoJson

View File

@ -8,22 +8,25 @@ namespace ArduinoJson {
namespace Internals {
// A Print implementation that allows to write in a char[]
class StaticStringBuilder {
class StaticStringWriter {
public:
StaticStringBuilder(char *buf, size_t size) : end(buf + size - 1), p(buf) {
StaticStringWriter(char *buf, size_t size) : end(buf + size - 1), p(buf) {
*p = '\0';
}
size_t print(char c) {
size_t write(uint8_t c) {
if (p >= end) return 0;
*p++ = c;
*p++ = static_cast<char>(c);
*p = '\0';
return 1;
}
size_t print(const char *s) {
size_t write(const uint8_t *s, size_t n) {
char *begin = p;
while (p < end && *s) *p++ = *s++;
while (p < end && n > 0) {
*p++ = static_cast<char>(*s++);
n--;
}
*p = '\0';
return size_t(p - begin);
}

View File

@ -13,27 +13,28 @@
namespace ArduinoJson {
namespace Internals {
class StreamPrintAdapter {
class StreamWriter {
public:
explicit StreamPrintAdapter(std::ostream& os) : _os(os) {}
explicit StreamWriter(std::ostream& os) : _os(os) {}
size_t print(char c) {
size_t write(uint8_t c) {
_os << c;
return 1;
}
size_t print(const char* s) {
_os << s;
return strlen(s);
size_t write(const uint8_t* s, size_t n) {
_os.write(reinterpret_cast<const char*>(s),
static_cast<std::streamsize>(n));
return n;
}
private:
// cannot be assigned
StreamPrintAdapter& operator=(const StreamPrintAdapter&);
StreamWriter& operator=(const StreamWriter&);
std::ostream& _os;
};
}
}
} // namespace Internals
} // namespace ArduinoJson
#endif // ARDUINOJSON_ENABLE_STD_STREAM

View File

@ -4,15 +4,15 @@
#pragma once
#include "./DummyPrint.hpp"
#include "./DummyWriter.hpp"
namespace ArduinoJson {
namespace Internals {
template <template <typename> class TSerializer, typename TSource>
size_t measure(const TSource &source) {
DummyPrint dp;
TSerializer<DummyPrint> serializer(dp);
DummyWriter dp;
TSerializer<DummyWriter> serializer(dp);
source.visit(serializer);
return serializer.bytesWritten();
}

View File

@ -4,11 +4,11 @@
#pragma once
#include "./DynamicStringBuilder.hpp"
#include "./StaticStringBuilder.hpp"
#include "./DynamicStringWriter.hpp"
#include "./StaticStringWriter.hpp"
#if ARDUINOJSON_ENABLE_STD_STREAM
#include "./StreamPrintAdapter.hpp"
#include "./StreamWriter.hpp"
#endif
namespace ArduinoJson {
@ -16,7 +16,7 @@ namespace Internals {
template <template <typename> class TSerializer, typename TSource,
typename TPrint>
typename enable_if<!StringTraits<TPrint>::has_append, size_t>::type serialize(
typename enable_if<!IsWriteableString<TPrint>::value, size_t>::type serialize(
const TSource &source, TPrint &destination) {
TSerializer<TPrint> serializer(destination);
source.visit(serializer);
@ -26,29 +26,29 @@ typename enable_if<!StringTraits<TPrint>::has_append, size_t>::type serialize(
#if ARDUINOJSON_ENABLE_STD_STREAM
template <template <typename> class TSerializer, typename TSource>
size_t serialize(const TSource &source, std::ostream &os) {
StreamPrintAdapter adapter(os);
return serialize<TSerializer>(source, adapter);
StreamWriter writer(os);
return serialize<TSerializer>(source, writer);
}
#endif
template <template <typename> class TSerializer, typename TSource>
size_t serialize(const TSource &source, char *buffer, size_t bufferSize) {
StaticStringBuilder sb(buffer, bufferSize);
return serialize<TSerializer>(source, sb);
StaticStringWriter writer(buffer, bufferSize);
return serialize<TSerializer>(source, writer);
}
template <template <typename> class TSerializer, typename TSource, size_t N>
size_t serialize(const TSource &source, char (&buffer)[N]) {
StaticStringBuilder sb(buffer, N);
return serialize<TSerializer>(source, sb);
StaticStringWriter writer(buffer, N);
return serialize<TSerializer>(source, writer);
}
template <template <typename> class TSerializer, typename TSource,
typename TString>
typename enable_if<StringTraits<TString>::has_append, size_t>::type serialize(
typename enable_if<IsWriteableString<TString>::value, size_t>::type serialize(
const TSource &source, TString &str) {
DynamicStringBuilder<TString> sb(str);
return serialize<TSerializer>(source, sb);
DynamicStringWriter<TString> writer(str);
return serialize<TSerializer>(source, writer);
}
} // namespace Internals

View File

@ -0,0 +1,70 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "Strings/StringTypes.hpp"
namespace ArduinoJson {
namespace Internals {
// A special type of data that can be used to insert pregenerated JSON portions.
template <typename T>
class SerializedValue {
public:
explicit SerializedValue(T str) : _str(str) {}
operator T() const {
return _str;
}
const char* data() const {
return _str.c_str();
}
size_t size() const {
// CAUTION: the old Arduino String doesn't have size()
return _str.length();
}
private:
T _str;
};
template <typename TChar>
class SerializedValue<TChar*> {
public:
explicit SerializedValue(TChar* p, size_t n) : _data(p), _size(n) {}
operator TChar*() const {
return _data;
}
TChar* data() const {
return _data;
}
size_t size() const {
return _size;
}
private:
TChar* _data;
size_t _size;
};
} // namespace Internals
template <typename T>
inline Internals::SerializedValue<T> serialized(T str) {
return Internals::SerializedValue<T>(str);
}
template <typename TChar>
inline Internals::SerializedValue<TChar*> serialized(TChar* p) {
return Internals::SerializedValue<TChar*>(p, Internals::makeString(p).size());
}
template <typename TChar>
inline Internals::SerializedValue<TChar*> serialized(TChar* p, size_t n) {
return Internals::SerializedValue<TChar*>(p, n);
}
} // namespace ArduinoJson

View File

@ -0,0 +1,60 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include <WString.h>
namespace ArduinoJson {
namespace Internals {
class ArduinoString {
public:
ArduinoString(const ::String& str) : _str(&str) {}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str->c_str()) return NULL; // <- Arduino string can return NULL
size_t n = _str->length() + 1;
void* dup = buffer->alloc(n);
if (dup != NULL) memcpy(dup, _str->c_str(), n);
return static_cast<const char*>(dup);
}
bool is_null() const {
// Arduino's String::c_str() can return NULL
return _str->c_str();
}
bool equals(const char* expected) const {
// Arduino's String::c_str() can return NULL
const char* actual = _str->c_str();
if (!actual || !expected) return actual == expected;
return 0 == strcmp(actual, expected);
}
const char* data() const {
return _str->c_str();
}
size_t size() const {
return _str->length();
}
private:
const ::String* _str;
};
template <>
struct IsString< ::String> : true_type {};
template <>
struct IsString< ::StringSumHelper> : true_type {};
inline ArduinoString makeString(const ::String& str) {
return ArduinoString(str);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -1,44 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
template <typename TChar>
struct CharPointerTraits {
static bool equals(const TChar* str, const char* expected) {
const char* actual = reinterpret_cast<const char*>(str);
if (!actual || !expected) return actual == expected;
return strcmp(actual, expected) == 0;
}
static bool is_null(const TChar* str) {
return !str;
}
typedef const char* duplicate_t;
template <typename Buffer>
static duplicate_t duplicate(const TChar* str, Buffer* buffer) {
if (!str) return NULL;
size_t size = strlen(reinterpret_cast<const char*>(str)) + 1;
void* dup = buffer->alloc(size);
if (dup != NULL) memcpy(dup, str, size);
return static_cast<duplicate_t>(dup);
}
static const bool has_append = false;
static const bool has_equals = true;
static const bool should_duplicate = !is_const<TChar>::value;
};
// char*, unsigned char*, signed char*
// const char*, const unsigned char*, const signed char*
template <typename TChar>
struct StringTraits<TChar*, typename enable_if<sizeof(TChar) == 1>::type>
: CharPointerTraits<TChar> {};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,47 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
class FixedSizeFlashString {
public:
FixedSizeFlashString(const __FlashStringHelper* str, size_t sz)
: _str(str), _size(sz) {}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strcmp_P(actual, expected) == 0;
}
bool is_null() const {
return !_str;
}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str) return NULL;
void* dup = buffer->alloc(_size);
if (dup != NULL) memcpy_P(dup, (const char*)_str, _size);
return static_cast<const char*>(dup);
}
size_t size() const {
return strlen_P(reinterpret_cast<const char*>(_str));
}
private:
const __FlashStringHelper* _str;
size_t _size;
};
inline FixedSizeFlashString makeString(const __FlashStringHelper* str,
size_t sz) {
return FixedSizeFlashString(str, sz);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,48 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
class FixedSizeRamString {
public:
FixedSizeRamString(const char* str, size_t n) : _str(str), _size(n) {}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strcmp(actual, expected) == 0;
}
bool is_null() const {
return !_str;
}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str) return NULL;
void* dup = buffer->alloc(_size);
if (!dup) return NULL;
memcpy(dup, _str, _size);
return static_cast<const char*>(dup);
}
size_t size() const {
return strlen(reinterpret_cast<const char*>(_str));
}
private:
const char* _str;
size_t _size;
};
template <typename TChar>
inline FixedSizeRamString makeString(const TChar* str, size_t size) {
return FixedSizeRamString(reinterpret_cast<const char*>(str), size);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -1,41 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#if ARDUINOJSON_ENABLE_PROGMEM
namespace ArduinoJson {
namespace Internals {
template <>
struct StringTraits<const __FlashStringHelper*, void> {
static bool equals(const __FlashStringHelper* str, const char* expected) {
const char* actual = reinterpret_cast<const char*>(str);
if (!actual || !expected) return actual == expected;
return strcmp_P(expected, actual) == 0;
}
static bool is_null(const __FlashStringHelper* str) {
return !str;
}
typedef const char* duplicate_t;
template <typename Buffer>
static duplicate_t duplicate(const __FlashStringHelper* str, Buffer* buffer) {
if (!str) return NULL;
size_t size = strlen_P((const char*)str) + 1;
void* dup = buffer->alloc(size);
if (dup != NULL) memcpy_P(dup, (const char*)str, size);
return static_cast<duplicate_t>(dup);
}
static const bool has_append = false;
static const bool has_equals = true;
static const bool should_duplicate = true;
};
} // namespace Internals
} // namespace ArduinoJson
#endif

View File

@ -1,73 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#if ARDUINOJSON_ENABLE_STD_STRING || ARDUINOJSON_ENABLE_ARDUINO_STRING
#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 StdStringTraits {
typedef const char* duplicate_t;
template <typename Buffer>
static duplicate_t 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<duplicate_t>(dup);
}
static bool is_null(const TString& str) {
// Arduino's String::c_str() can return NULL
return !str.c_str();
}
static bool equals(const TString& str, const char* expected) {
// Arduino's String::c_str() can return NULL
const char* actual = str.c_str();
if (!actual || !expected) return actual == expected;
return 0 == strcmp(actual, expected);
}
static void append(TString& str, char c) {
str += c;
}
static void append(TString& str, const char* s) {
str += s;
}
static const bool has_append = true;
static const bool has_equals = true;
static const bool should_duplicate = true;
};
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
template <>
struct StringTraits<String, void> : StdStringTraits<String> {};
template <>
struct StringTraits<StringSumHelper, void> : StdStringTraits<StringSumHelper> {
};
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
template <>
struct StringTraits<std::string, void> : StdStringTraits<std::string> {};
#endif
} // namespace Internals
} // namespace ArduinoJson
#endif

View File

@ -0,0 +1,52 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include <string>
namespace ArduinoJson {
namespace Internals {
class StlString {
public:
StlString(const std::string& str) : _str(&str) {}
template <typename Buffer>
const char* save(Buffer* buffer) const {
size_t n = _str->length() + 1;
void* dup = buffer->alloc(n);
if (dup != NULL) memcpy(dup, _str->c_str(), n);
return static_cast<const char*>(dup);
}
bool is_null() const {
return false;
}
bool equals(const char* expected) const {
return *_str == expected;
}
const char* data() const {
return _str->data();
}
size_t size() const {
return _str->size();
}
private:
const std::string* _str;
};
template <>
struct IsString<std::string> : true_type {};
inline StlString makeString(const std::string& str) {
return StlString(str);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -1,30 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include <string.h>
#include "../Configuration.hpp"
#include "../Polyfills/type_traits.hpp"
namespace ArduinoJson {
namespace Internals {
template <typename TString, typename Enable = void>
struct StringTraits {
static const bool has_append = false;
static const bool has_equals = false;
};
template <typename TString>
struct StringTraits<const TString, void> : StringTraits<TString> {};
template <typename TString>
struct StringTraits<TString&, void> : StringTraits<TString> {};
} // namespace Internals
} // namespace ArduinoJson
#include "CharPointer.hpp"
#include "FlashString.hpp"
#include "StdString.hpp"

View File

@ -0,0 +1,36 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Polyfills/type_traits.hpp"
namespace ArduinoJson {
namespace Internals {
template <typename>
struct IsString : false_type {};
template <typename T>
struct IsString<const T> : IsString<T> {};
template <typename T>
struct IsString<T&> : IsString<T> {};
} // namespace Internals
} // namespace ArduinoJson
#include "FixedSizeRamString.hpp"
#include "ZeroTerminatedRamString.hpp"
#if ARDUINOJSON_ENABLE_STD_STRING
#include "StlString.hpp"
#endif
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include "ArduinoString.hpp"
#endif
#if ARDUINOJSON_ENABLE_PROGMEM
#include "FixedSizeFlashString.hpp"
#include "ZeroTerminatedFlashString.hpp"
#endif

View File

@ -0,0 +1,48 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
class ZeroTerminatedFlashString {
public:
ZeroTerminatedFlashString(const __FlashStringHelper* str) : _str(str) {}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strcmp_P(actual, expected) == 0;
}
bool is_null() const {
return !_str;
}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str) return NULL;
size_t n = size() + 1; // copy the terminator
void* dup = buffer->alloc(n);
if (dup != NULL) memcpy_P(dup, (const char*)_str, n);
return static_cast<const char*>(dup);
}
size_t size() const {
return strlen_P(reinterpret_cast<const char*>(_str));
}
private:
const __FlashStringHelper* _str;
};
inline ZeroTerminatedFlashString makeString(const __FlashStringHelper* str) {
return ZeroTerminatedFlashString(str);
}
template <>
struct IsString<const __FlashStringHelper*> : true_type {};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,53 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
class ZeroTerminatedRamString {
public:
ZeroTerminatedRamString(const char* str) : _str(str) {}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strcmp(actual, expected) == 0;
}
bool is_null() const {
return !_str;
}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str) return NULL;
size_t n = size() + 1;
void* dup = buffer->alloc(n);
if (!dup) return NULL;
memcpy(dup, _str, n);
return static_cast<const char*>(dup);
}
size_t size() const {
return strlen(reinterpret_cast<const char*>(_str));
}
private:
const char* _str;
};
template <typename TChar>
inline ZeroTerminatedRamString makeString(const TChar* str) {
return ZeroTerminatedRamString(reinterpret_cast<const char*>(str));
}
template <typename TChar>
struct IsString<TChar*> {
static const bool value = sizeof(TChar) == 1;
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -4,16 +4,17 @@
add_executable(JsonArrayTests
add.cpp
basics.cpp
copyFrom.cpp
copyTo.cpp
invalid.cpp
createNested.cpp
isNull.cpp
iterator.cpp
remove.cpp
set.cpp
size.cpp
std_string.cpp
subscript.cpp
undefined.cpp
)
target_link_libraries(JsonArrayTests catch)

View File

@ -100,14 +100,26 @@ TEST_CASE("JsonArray::add()") {
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should not duplicate RawJson(const char*)") {
_array.add(RawJson("{}"));
SECTION("should not duplicate serialized(const char*)") {
_array.add(serialized("{}"));
const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate RawJson(char*)") {
_array.add(RawJson(const_cast<char*>("{}")));
SECTION("should duplicate serialized(char*)") {
_array.add(serialized(const_cast<char*>("{}")));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2;
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate serialized(std::string)") {
_array.add(serialized(std::string("{}")));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2;
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate serialized(std::string)") {
_array.add(serialized(std::string("\0XX", 3)));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 3;
REQUIRE(expectedSize == doc.memoryUsage());
}

View File

@ -9,14 +9,6 @@ TEST_CASE("JsonArray basics") {
DynamicJsonDocument doc;
JsonArray array = doc.to<JsonArray>();
SECTION("isNull()") {
REQUIRE(array.isNull() == false);
}
SECTION("InitialSizeIsZero") {
REQUIRE(0U == array.size());
}
SECTION("CreateNestedArray") {
JsonArray arr = array.createNestedArray();
REQUIRE(arr == array[0].as<JsonArray>());

25
test/JsonArray/isNull.cpp Normal file
View File

@ -0,0 +1,25 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray::isNull()") {
SECTION("returns true for undefined JsonArray") {
JsonArray array;
REQUIRE(array.isNull() == true);
}
SECTION("returns false when allocation succeeds") {
StaticJsonDocument<JSON_ARRAY_SIZE(0)> doc;
JsonArray array = doc.to<JsonArray>();
REQUIRE(array.isNull() == false);
}
SECTION("returns true when allocation fails") {
StaticJsonDocument<1> doc;
JsonArray array = doc.to<JsonArray>();
REQUIRE(array.isNull() == true);
}
}

View File

@ -7,29 +7,33 @@
TEST_CASE("JsonArray::size()") {
DynamicJsonDocument doc;
JsonArray _array = doc.to<JsonArray>();
JsonArray array = doc.to<JsonArray>();
SECTION("InitialSizeIsZero") {
REQUIRE(0U == array.size());
}
SECTION("increases after add()") {
_array.add("hello");
REQUIRE(1U == _array.size());
array.add("hello");
REQUIRE(1U == array.size());
_array.add("world");
REQUIRE(2U == _array.size());
array.add("world");
REQUIRE(2U == array.size());
}
SECTION("remains the same after set()") {
_array.add("hello");
REQUIRE(1U == _array.size());
array.add("hello");
REQUIRE(1U == array.size());
_array.set(0, "hello");
REQUIRE(1U == _array.size());
array.set(0, "hello");
REQUIRE(1U == array.size());
}
SECTION("remains the same after assigment") {
_array.add("hello");
REQUIRE(1U == _array.size());
array.add("hello");
REQUIRE(1U == array.size());
_array[0] = "hello";
REQUIRE(1U == _array.size());
array[0] = "hello";
REQUIRE(1U == array.size());
}
}

View File

@ -3,10 +3,10 @@
# MIT License
add_executable(JsonObjectTests
basics.cpp
containsKey.cpp
get.cpp
invalid.cpp
isNull.cpp
iterator.cpp
remove.cpp
set.cpp

View File

@ -1,15 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonObject basics") {
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
SECTION("isNull()") {
REQUIRE(obj.isNull() == false);
}
}

View File

@ -0,0 +1,25 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonObject::isNull()") {
SECTION("returns true for undefined JsonObject") {
JsonObject array;
REQUIRE(array.isNull() == true);
}
SECTION("returns false when allocation succeeds") {
StaticJsonDocument<JSON_OBJECT_SIZE(0)> doc;
JsonObject array = doc.to<JsonObject>();
REQUIRE(array.isNull() == false);
}
SECTION("returns true when allocation fails") {
StaticJsonDocument<1> doc;
JsonObject array = doc.to<JsonObject>();
REQUIRE(array.isNull() == true);
}
}

View File

@ -67,15 +67,15 @@ TEST_CASE("serializeJson(JsonArray)") {
check(array, "[1,2]");
}
SECTION("RawJson(const char*)") {
array.add(RawJson("{\"key\":\"value\"}"));
SECTION("serialized(const char*)") {
array.add(serialized("{\"key\":\"value\"}"));
check(array, "[{\"key\":\"value\"}]");
}
SECTION("RawJson(char*)") {
SECTION("serialized(char*)") {
char tmp[] = "{\"key\":\"value\"}";
array.add(RawJson(tmp));
array.add(serialized(tmp));
check(array, "[{\"key\":\"value\"}]");
}

View File

@ -68,9 +68,9 @@ TEST_CASE("serializeJson(JsonObject)") {
check(obj, "{\"a\":1,\"b\":2}");
}
SECTION("RawJson") {
obj["a"] = RawJson("[1,2]");
obj.set("b", RawJson("[4,5]"));
SECTION("serialized(const char*)") {
obj["a"] = serialized("[1,2]");
obj.set("b", serialized("[4,5]"));
check(obj, "{\"a\":[1,2],\"b\":[4,5]}");
}

View File

@ -95,21 +95,4 @@ TEST_CASE("JsonVariant::is()") {
SECTION("string") {
checkIsString("42");
}
SECTION("unparsed bool") {
checkIsBool(RawJson("true"));
checkIsBool(RawJson("false"));
}
SECTION("unparsed int") {
checkIsInteger(RawJson("42"));
}
SECTION("unparsed float") {
checkIsFloat(RawJson("4.2e-10"));
}
SECTION("unparsed null") {
checkIsString(RawJson("null"));
}
}

View File

@ -7,15 +7,15 @@
#include <string>
#include <ArduinoJson/Json/JsonWriter.hpp>
#include <ArduinoJson/Serialization/DynamicStringBuilder.hpp>
#include <ArduinoJson/Serialization/DynamicStringWriter.hpp>
using namespace ArduinoJson::Internals;
template <typename TFloat>
void check(TFloat input, const std::string& expected) {
std::string output;
DynamicStringBuilder<std::string> sb(output);
JsonWriter<DynamicStringBuilder<std::string> > writer(sb);
DynamicStringWriter<std::string> sb(output);
JsonWriter<DynamicStringWriter<std::string> > writer(sb);
writer.writeFloat(input);
REQUIRE(writer.bytesWritten() == output.size());
CHECK(expected == output);

View File

@ -5,14 +5,14 @@
#include <catch.hpp>
#include <ArduinoJson/Json/JsonWriter.hpp>
#include <ArduinoJson/Serialization/StaticStringBuilder.hpp>
#include <ArduinoJson/Serialization/StaticStringWriter.hpp>
using namespace ArduinoJson::Internals;
void check(const char* input, std::string expected) {
char output[1024];
StaticStringBuilder sb(output, sizeof(output));
JsonWriter<StaticStringBuilder> writer(sb);
StaticStringWriter sb(output, sizeof(output));
JsonWriter<StaticStringWriter> writer(sb);
writer.writeString(input);
REQUIRE(expected == output);
REQUIRE(writer.bytesWritten() == expected.size());

View File

@ -4,8 +4,7 @@
add_executable(MiscTests
FloatParts.cpp
StringBuilder.cpp
StringTraits.cpp
StringWriter.cpp
TypeTraits.cpp
unsigned_char.cpp
version.cpp

View File

@ -1,22 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
using namespace ArduinoJson::Internals;
template <typename String>
bool should_duplicate() {
return StringTraits<String>::should_duplicate;
}
TEST_CASE("StringTraits") {
SECTION("should_duplicate") {
REQUIRE(false == should_duplicate<const char*>());
REQUIRE(true == should_duplicate<char*>());
REQUIRE(true == should_duplicate<RawJsonString<char*> >());
REQUIRE(false == should_duplicate<RawJsonString<const char*> >());
}
}

View File

@ -7,44 +7,49 @@
using namespace ArduinoJson::Internals;
template <typename StringBuilder, typename String>
void common_tests(StringBuilder& sb, const String& output) {
template <typename StringWriter>
static size_t print(StringWriter& sb, const char* s) {
return sb.write(reinterpret_cast<const uint8_t*>(s), strlen(s));
}
template <typename StringWriter, typename String>
void common_tests(StringWriter& sb, const String& output) {
SECTION("InitialState") {
REQUIRE(std::string("") == output);
}
SECTION("EmptyString") {
REQUIRE(0 == sb.print(""));
REQUIRE(0 == print(sb, ""));
REQUIRE(std::string("") == output);
}
SECTION("OneString") {
REQUIRE(4 == sb.print("ABCD"));
REQUIRE(4 == print(sb, "ABCD"));
REQUIRE(std::string("ABCD") == output);
}
SECTION("TwoStrings") {
REQUIRE(4 == sb.print("ABCD"));
REQUIRE(4 == sb.print("EFGH"));
REQUIRE(4 == print(sb, "ABCD"));
REQUIRE(4 == print(sb, "EFGH"));
REQUIRE(std::string("ABCDEFGH") == output);
}
}
TEST_CASE("StaticStringBuilder") {
TEST_CASE("StaticStringWriter") {
char output[20];
StaticStringBuilder sb(output, sizeof(output));
StaticStringWriter sb(output, sizeof(output));
common_tests(sb, static_cast<const char*>(output));
SECTION("OverCapacity") {
REQUIRE(19 == sb.print("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
REQUIRE(0 == sb.print("ABC"));
REQUIRE(19 == print(sb, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
REQUIRE(0 == print(sb, "ABC"));
REQUIRE(std::string("ABCDEFGHIJKLMNOPQRS") == output);
}
}
TEST_CASE("DynamicStringBuilder") {
TEST_CASE("DynamicStringWriter") {
std::string output;
DynamicStringBuilder<std::string> sb(output);
DynamicStringWriter<std::string> sb(output);
common_tests(sb, output);
}

View File

@ -70,4 +70,14 @@ TEST_CASE("serialize MsgPack object") {
//
// check(object, expected);
// }
SECTION("serialized(const char*)") {
object["hello"] = serialized("\xDB\x00\x01\x00\x00", 5);
check(object, "\x81\xA5hello\xDB\x00\x01\x00\x00");
}
SECTION("serialized(std::string)") {
object["hello"] = serialized(std::string("\xDB\x00\x01\x00\x00", 5));
check(object, "\x81\xA5hello\xDB\x00\x01\x00\x00");
}
}

View File

@ -126,4 +126,9 @@ TEST_CASE("serialize MsgPack value") {
std::string shortest(65536, '?');
check(shortest.c_str(), std::string("\xDB\x00\x01\x00\x00", 5) + shortest);
}
SECTION("serialized(const char*)") {
check(serialized("\xDA\xFF\xFF"), "\xDA\xFF\xFF");
check(serialized("\xDB\x00\x01\x00\x00", 5), "\xDB\x00\x01\x00\x00");
}
}