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) * Disabled lazy number deserialization (issue #772)
* Improved float serialization when `-fsingle-precision-constant` is used * Improved float serialization when `-fsingle-precision-constant` is used
* Renamed function `RawJson()` to `serialized()`
* `serializeMsgPack()` now supports values marked with `serialized()`
> ### BREAKING CHANGES > ### BREAKING CHANGES
> >
> #### Non quoted strings
>
> Non quoted strings are now forbidden in values, but they are still allowed in keys. > 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. > 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 v6.1.0-beta
----------- -----------

View File

@ -37,8 +37,9 @@ void setup() {
// JsonBuffer. // JsonBuffer.
obj["sensor"] = F("gps"); obj["sensor"] = F("gps");
// It works with RawJson too: // It works with serialized() too:
obj["sensor"] = RawJson(F("\"gps\"")); obj["sensor"] = serialized(F("\"gps\""));
obj["sensor"] = serialized(F("\xA3gps"), 3);
// You can compare the content of a JsonVariant to a Flash String // You can compare the content of a JsonVariant to a Flash String
if (obj["sensor"] == F("gps")) { 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. // WARNING: the content of the String will be duplicated in the JsonBuffer.
obj["sensor"] = sensor; obj["sensor"] = sensor;
// It works with RawJson too: // It works with serialized() too:
obj["sensor"] = RawJson(sensor); obj["sensor"] = serialized(sensor);
// You can also concatenate strings // You can also concatenate strings
// WARNING: the content of the String will be duplicated in the JsonBuffer. // WARNING: the content of the String will be duplicated in the JsonBuffer.

View File

@ -18,9 +18,13 @@ struct JsonObjectData;
union JsonVariantContent { union JsonVariantContent {
JsonFloat asFloat; // used for double and float JsonFloat asFloat; // used for double and float
JsonUInt asInteger; // used for bool, char, short, int and longs JsonUInt asInteger; // used for bool, char, short, int and longs
const char* asString; // asString can be null
JsonArrayData* asArray; // asArray cannot be null JsonArrayData* asArray; // asArray cannot be null
JsonObjectData* asObject; // asObject 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 Internals
} // namespace ArduinoJson } // namespace ArduinoJson

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -29,7 +29,7 @@ class JsonArray {
// Adds the specified value at the end of the array. // Adds the specified value at the end of the array.
// //
// bool add(TValue); // 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 // std::string, String, JsonArrayData, JsonObject
template <typename T> template <typename T>
bool add(const T& value) { bool add(const T& value) {
@ -154,7 +154,7 @@ class JsonArray {
// Sets the value at specified index. // Sets the value at specified index.
// //
// bool add(size_t index, const TValue&); // 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 // std::string, String, JsonArrayData, JsonObject
template <typename T> template <typename T>
bool set(size_t index, const T& value) { bool set(size_t index, const T& value) {

View File

@ -9,7 +9,6 @@
#include "JsonVariant.hpp" #include "JsonVariant.hpp"
#include "Memory/JsonBufferAllocated.hpp" #include "Memory/JsonBufferAllocated.hpp"
#include "Polyfills/type_traits.hpp" #include "Polyfills/type_traits.hpp"
#include "Strings/StringTraits.hpp"
// Returns the size (in bytes) of an array with n elements. // Returns the size (in bytes) of an array with n elements.
// Can be very handy to determine the size of a StaticJsonBuffer. // 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 // Replaces the value
// //
// operator=(const TValue&) // 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 // std::string, String, JsonArray, JsonObject
template <typename T> template <typename T>
FORCE_INLINE JsonArraySubscript& operator=(const T& src) { FORCE_INLINE JsonArraySubscript& operator=(const T& src) {
@ -60,7 +60,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
// Replaces the value // Replaces the value
// //
// bool set(const TValue&) // 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 // std::string, String, JsonArray, JsonObject
template <typename TValue> template <typename TValue>
FORCE_INLINE bool set(const TValue& value) { FORCE_INLINE bool set(const TValue& value) {

View File

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

View File

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

View File

@ -67,7 +67,8 @@ class JsonObjectSubscript
// Sets the specified value. // Sets the specified value.
// //
// bool set(const TValue&); // 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 // std::string, String, JsonArray, JsonObject
template <typename TValue> template <typename TValue>
FORCE_INLINE typename enable_if<!is_array<TValue>::value, bool>::type set( FORCE_INLINE typename enable_if<!is_array<TValue>::value, bool>::type set(
@ -94,7 +95,7 @@ class JsonObjectSubscript
template <typename TImpl> template <typename TImpl>
template <typename TString> template <typename TString>
inline typename enable_if<StringTraits<TString>::has_equals, inline typename enable_if<IsString<TString>::value,
const JsonObjectSubscript<const TString &> >::type const JsonObjectSubscript<const TString &> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString &key) const { JsonVariantSubscripts<TImpl>::operator[](const TString &key) const {
return impl()->template as<JsonObject>()[key]; return impl()->template as<JsonObject>()[key];
@ -102,7 +103,7 @@ inline typename enable_if<StringTraits<TString>::has_equals,
template <typename TImpl> template <typename TImpl>
template <typename TString> template <typename TString>
inline typename enable_if<StringTraits<TString>::has_equals, inline typename enable_if<IsString<TString>::value,
JsonObjectSubscript<const TString &> >::type JsonObjectSubscript<const TString &> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString &key) { JsonVariantSubscripts<TImpl>::operator[](const TString &key) {
return impl()->template as<JsonObject>()[key]; return impl()->template as<JsonObject>()[key];
@ -110,7 +111,7 @@ inline typename enable_if<StringTraits<TString>::has_equals,
template <typename TImpl> template <typename TImpl>
template <typename TString> template <typename TString>
inline typename enable_if<StringTraits<const TString *>::has_equals, inline typename enable_if<IsString<const TString *>::value,
JsonObjectSubscript<const TString *> >::type JsonObjectSubscript<const TString *> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString *key) { JsonVariantSubscripts<TImpl>::operator[](const TString *key) {
return impl()->template as<JsonObject>()[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 TImpl>
template <typename TString> template <typename TString>
inline typename enable_if<StringTraits<TString *>::has_equals, inline typename enable_if<IsString<TString *>::value,
const JsonObjectSubscript<const TString *> >::type const JsonObjectSubscript<const TString *> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString *key) const { JsonVariantSubscripts<TImpl>::operator[](const TString *key) const {
return impl()->template as<JsonObject>()[key]; return impl()->template as<JsonObject>()[key];

View File

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

View File

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

View File

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

View File

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

View File

@ -13,10 +13,10 @@
namespace ArduinoJson { namespace ArduinoJson {
namespace Internals { namespace Internals {
template <typename TPrint> template <typename TWriter>
class MsgPackSerializer { class MsgPackSerializer {
public: public:
MsgPackSerializer(TPrint& output) : _output(&output), _bytesWritten(0) {} MsgPackSerializer(TWriter& writer) : _writer(&writer), _bytesWritten(0) {}
template <typename T> template <typename T>
typename enable_if<sizeof(T) == 4>::type acceptFloat(T value32) { typename enable_if<sizeof(T) == 4>::type acceptFloat(T value32) {
@ -91,7 +91,9 @@ class MsgPackSerializer {
writeBytes(reinterpret_cast<const uint8_t*>(value), n); 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) { void acceptNegativeInteger(JsonUInt value) {
JsonUInt negated = JsonUInt(~value + 1); JsonUInt negated = JsonUInt(~value + 1);
@ -150,12 +152,11 @@ class MsgPackSerializer {
private: private:
void writeByte(uint8_t c) { void writeByte(uint8_t c) {
_output->print(char(c)); _bytesWritten += _writer->write(c);
_bytesWritten++;
} }
void writeBytes(const uint8_t* c, size_t n) { void writeBytes(const uint8_t* p, size_t n) {
for (; n > 0; --n, ++c) writeByte(*c); _bytesWritten += _writer->write(p, n);
} }
template <typename T> template <typename T>
@ -164,7 +165,7 @@ class MsgPackSerializer {
writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value)); writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
} }
TPrint* _output; TWriter* _writer;
size_t _bytesWritten; size_t _bytesWritten;
}; };
} // namespace Internals } // 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 ArduinoJson {
namespace Internals { namespace Internals {
class DummyPrint { class DummyWriter {
public: public:
size_t print(char) { size_t write(uint8_t) {
return 1; return 1;
} }
size_t print(const char* s) { size_t write(const uint8_t*, size_t n) {
return strlen(s); return n;
} }
}; };
} // namespace Internals } // 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 { namespace Internals {
// A Print implementation that allows to write in a char[] // A Print implementation that allows to write in a char[]
class StaticStringBuilder { class StaticStringWriter {
public: 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'; *p = '\0';
} }
size_t print(char c) { size_t write(uint8_t c) {
if (p >= end) return 0; if (p >= end) return 0;
*p++ = c; *p++ = static_cast<char>(c);
*p = '\0'; *p = '\0';
return 1; return 1;
} }
size_t print(const char *s) { size_t write(const uint8_t *s, size_t n) {
char *begin = p; char *begin = p;
while (p < end && *s) *p++ = *s++; while (p < end && n > 0) {
*p++ = static_cast<char>(*s++);
n--;
}
*p = '\0'; *p = '\0';
return size_t(p - begin); return size_t(p - begin);
} }

View File

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

View File

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

View File

@ -4,11 +4,11 @@
#pragma once #pragma once
#include "./DynamicStringBuilder.hpp" #include "./DynamicStringWriter.hpp"
#include "./StaticStringBuilder.hpp" #include "./StaticStringWriter.hpp"
#if ARDUINOJSON_ENABLE_STD_STREAM #if ARDUINOJSON_ENABLE_STD_STREAM
#include "./StreamPrintAdapter.hpp" #include "./StreamWriter.hpp"
#endif #endif
namespace ArduinoJson { namespace ArduinoJson {
@ -16,7 +16,7 @@ namespace Internals {
template <template <typename> class TSerializer, typename TSource, template <template <typename> class TSerializer, typename TSource,
typename TPrint> 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) { const TSource &source, TPrint &destination) {
TSerializer<TPrint> serializer(destination); TSerializer<TPrint> serializer(destination);
source.visit(serializer); source.visit(serializer);
@ -26,29 +26,29 @@ typename enable_if<!StringTraits<TPrint>::has_append, size_t>::type serialize(
#if ARDUINOJSON_ENABLE_STD_STREAM #if ARDUINOJSON_ENABLE_STD_STREAM
template <template <typename> class TSerializer, typename TSource> template <template <typename> class TSerializer, typename TSource>
size_t serialize(const TSource &source, std::ostream &os) { size_t serialize(const TSource &source, std::ostream &os) {
StreamPrintAdapter adapter(os); StreamWriter writer(os);
return serialize<TSerializer>(source, adapter); return serialize<TSerializer>(source, writer);
} }
#endif #endif
template <template <typename> class TSerializer, typename TSource> template <template <typename> class TSerializer, typename TSource>
size_t serialize(const TSource &source, char *buffer, size_t bufferSize) { size_t serialize(const TSource &source, char *buffer, size_t bufferSize) {
StaticStringBuilder sb(buffer, bufferSize); StaticStringWriter writer(buffer, bufferSize);
return serialize<TSerializer>(source, sb); return serialize<TSerializer>(source, writer);
} }
template <template <typename> class TSerializer, typename TSource, size_t N> template <template <typename> class TSerializer, typename TSource, size_t N>
size_t serialize(const TSource &source, char (&buffer)[N]) { size_t serialize(const TSource &source, char (&buffer)[N]) {
StaticStringBuilder sb(buffer, N); StaticStringWriter writer(buffer, N);
return serialize<TSerializer>(source, sb); return serialize<TSerializer>(source, writer);
} }
template <template <typename> class TSerializer, typename TSource, template <template <typename> class TSerializer, typename TSource,
typename TString> 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) { const TSource &source, TString &str) {
DynamicStringBuilder<TString> sb(str); DynamicStringWriter<TString> writer(str);
return serialize<TSerializer>(source, sb); return serialize<TSerializer>(source, writer);
} }
} // namespace Internals } // 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_executable(JsonArrayTests
add.cpp add.cpp
basics.cpp
copyFrom.cpp copyFrom.cpp
copyTo.cpp copyTo.cpp
invalid.cpp createNested.cpp
isNull.cpp
iterator.cpp iterator.cpp
remove.cpp remove.cpp
set.cpp set.cpp
size.cpp size.cpp
std_string.cpp std_string.cpp
subscript.cpp subscript.cpp
undefined.cpp
) )
target_link_libraries(JsonArrayTests catch) target_link_libraries(JsonArrayTests catch)

View File

@ -100,14 +100,26 @@ TEST_CASE("JsonArray::add()") {
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should not duplicate RawJson(const char*)") { SECTION("should not duplicate serialized(const char*)") {
_array.add(RawJson("{}")); _array.add(serialized("{}"));
const size_t expectedSize = JSON_ARRAY_SIZE(1); const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate RawJson(char*)") { SECTION("should duplicate serialized(char*)") {
_array.add(RawJson(const_cast<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; const size_t expectedSize = JSON_ARRAY_SIZE(1) + 3;
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }

View File

@ -9,14 +9,6 @@ TEST_CASE("JsonArray basics") {
DynamicJsonDocument doc; DynamicJsonDocument doc;
JsonArray array = doc.to<JsonArray>(); JsonArray array = doc.to<JsonArray>();
SECTION("isNull()") {
REQUIRE(array.isNull() == false);
}
SECTION("InitialSizeIsZero") {
REQUIRE(0U == array.size());
}
SECTION("CreateNestedArray") { SECTION("CreateNestedArray") {
JsonArray arr = array.createNestedArray(); JsonArray arr = array.createNestedArray();
REQUIRE(arr == array[0].as<JsonArray>()); 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()") { TEST_CASE("JsonArray::size()") {
DynamicJsonDocument doc; DynamicJsonDocument doc;
JsonArray _array = doc.to<JsonArray>(); JsonArray array = doc.to<JsonArray>();
SECTION("InitialSizeIsZero") {
REQUIRE(0U == array.size());
}
SECTION("increases after add()") { SECTION("increases after add()") {
_array.add("hello"); array.add("hello");
REQUIRE(1U == _array.size()); REQUIRE(1U == array.size());
_array.add("world"); array.add("world");
REQUIRE(2U == _array.size()); REQUIRE(2U == array.size());
} }
SECTION("remains the same after set()") { SECTION("remains the same after set()") {
_array.add("hello"); array.add("hello");
REQUIRE(1U == _array.size()); REQUIRE(1U == array.size());
_array.set(0, "hello"); array.set(0, "hello");
REQUIRE(1U == _array.size()); REQUIRE(1U == array.size());
} }
SECTION("remains the same after assigment") { SECTION("remains the same after assigment") {
_array.add("hello"); array.add("hello");
REQUIRE(1U == _array.size()); REQUIRE(1U == array.size());
_array[0] = "hello"; array[0] = "hello";
REQUIRE(1U == _array.size()); REQUIRE(1U == array.size());
} }
} }

View File

@ -3,10 +3,10 @@
# MIT License # MIT License
add_executable(JsonObjectTests add_executable(JsonObjectTests
basics.cpp
containsKey.cpp containsKey.cpp
get.cpp get.cpp
invalid.cpp invalid.cpp
isNull.cpp
iterator.cpp iterator.cpp
remove.cpp remove.cpp
set.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]"); check(array, "[1,2]");
} }
SECTION("RawJson(const char*)") { SECTION("serialized(const char*)") {
array.add(RawJson("{\"key\":\"value\"}")); array.add(serialized("{\"key\":\"value\"}"));
check(array, "[{\"key\":\"value\"}]"); check(array, "[{\"key\":\"value\"}]");
} }
SECTION("RawJson(char*)") { SECTION("serialized(char*)") {
char tmp[] = "{\"key\":\"value\"}"; char tmp[] = "{\"key\":\"value\"}";
array.add(RawJson(tmp)); array.add(serialized(tmp));
check(array, "[{\"key\":\"value\"}]"); check(array, "[{\"key\":\"value\"}]");
} }

View File

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

View File

@ -95,21 +95,4 @@ TEST_CASE("JsonVariant::is()") {
SECTION("string") { SECTION("string") {
checkIsString("42"); 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 <string>
#include <ArduinoJson/Json/JsonWriter.hpp> #include <ArduinoJson/Json/JsonWriter.hpp>
#include <ArduinoJson/Serialization/DynamicStringBuilder.hpp> #include <ArduinoJson/Serialization/DynamicStringWriter.hpp>
using namespace ArduinoJson::Internals; using namespace ArduinoJson::Internals;
template <typename TFloat> template <typename TFloat>
void check(TFloat input, const std::string& expected) { void check(TFloat input, const std::string& expected) {
std::string output; std::string output;
DynamicStringBuilder<std::string> sb(output); DynamicStringWriter<std::string> sb(output);
JsonWriter<DynamicStringBuilder<std::string> > writer(sb); JsonWriter<DynamicStringWriter<std::string> > writer(sb);
writer.writeFloat(input); writer.writeFloat(input);
REQUIRE(writer.bytesWritten() == output.size()); REQUIRE(writer.bytesWritten() == output.size());
CHECK(expected == output); CHECK(expected == output);

View File

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

View File

@ -4,8 +4,7 @@
add_executable(MiscTests add_executable(MiscTests
FloatParts.cpp FloatParts.cpp
StringBuilder.cpp StringWriter.cpp
StringTraits.cpp
TypeTraits.cpp TypeTraits.cpp
unsigned_char.cpp unsigned_char.cpp
version.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; using namespace ArduinoJson::Internals;
template <typename StringBuilder, typename String> template <typename StringWriter>
void common_tests(StringBuilder& sb, const String& output) { 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") { SECTION("InitialState") {
REQUIRE(std::string("") == output); REQUIRE(std::string("") == output);
} }
SECTION("EmptyString") { SECTION("EmptyString") {
REQUIRE(0 == sb.print("")); REQUIRE(0 == print(sb, ""));
REQUIRE(std::string("") == output); REQUIRE(std::string("") == output);
} }
SECTION("OneString") { SECTION("OneString") {
REQUIRE(4 == sb.print("ABCD")); REQUIRE(4 == print(sb, "ABCD"));
REQUIRE(std::string("ABCD") == output); REQUIRE(std::string("ABCD") == output);
} }
SECTION("TwoStrings") { SECTION("TwoStrings") {
REQUIRE(4 == sb.print("ABCD")); REQUIRE(4 == print(sb, "ABCD"));
REQUIRE(4 == sb.print("EFGH")); REQUIRE(4 == print(sb, "EFGH"));
REQUIRE(std::string("ABCDEFGH") == output); REQUIRE(std::string("ABCDEFGH") == output);
} }
} }
TEST_CASE("StaticStringBuilder") { TEST_CASE("StaticStringWriter") {
char output[20]; char output[20];
StaticStringBuilder sb(output, sizeof(output)); StaticStringWriter sb(output, sizeof(output));
common_tests(sb, static_cast<const char*>(output)); common_tests(sb, static_cast<const char*>(output));
SECTION("OverCapacity") { SECTION("OverCapacity") {
REQUIRE(19 == sb.print("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); REQUIRE(19 == print(sb, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
REQUIRE(0 == sb.print("ABC")); REQUIRE(0 == print(sb, "ABC"));
REQUIRE(std::string("ABCDEFGHIJKLMNOPQRS") == output); REQUIRE(std::string("ABCDEFGHIJKLMNOPQRS") == output);
} }
} }
TEST_CASE("DynamicStringBuilder") { TEST_CASE("DynamicStringWriter") {
std::string output; std::string output;
DynamicStringBuilder<std::string> sb(output); DynamicStringWriter<std::string> sb(output);
common_tests(sb, output); common_tests(sb, output);
} }

View File

@ -70,4 +70,14 @@ TEST_CASE("serialize MsgPack object") {
// //
// check(object, expected); // 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, '?'); std::string shortest(65536, '?');
check(shortest.c_str(), std::string("\xDB\x00\x01\x00\x00", 5) + shortest); 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");
}
} }