diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fd159de..92acc223 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 ----------- diff --git a/examples/ProgmemExample/ProgmemExample.ino b/examples/ProgmemExample/ProgmemExample.ino index 45a51c76..286f25da 100644 --- a/examples/ProgmemExample/ProgmemExample.ino +++ b/examples/ProgmemExample/ProgmemExample.ino @@ -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")) { diff --git a/examples/StringExample/StringExample.ino b/examples/StringExample/StringExample.ino index 967b9146..dd07e834 100644 --- a/examples/StringExample/StringExample.ino +++ b/examples/StringExample/StringExample.ino @@ -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. diff --git a/src/ArduinoJson/Data/JsonVariantContent.hpp b/src/ArduinoJson/Data/JsonVariantContent.hpp index 5b8403c7..97a84a0c 100644 --- a/src/ArduinoJson/Data/JsonVariantContent.hpp +++ b/src/ArduinoJson/Data/JsonVariantContent.hpp @@ -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 diff --git a/src/ArduinoJson/Data/ValueSaver.hpp b/src/ArduinoJson/Data/ValueSaver.hpp index d3f7e3ae..5912629b 100644 --- a/src/ArduinoJson/Data/ValueSaver.hpp +++ b/src/ArduinoJson/Data/ValueSaver.hpp @@ -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 +// We duplicate all strings except const char* +template struct ValueSaver< - Source, typename enable_if::should_duplicate>::type> { + TString, typename enable_if::value && + !is_same::value>::type> { template - static bool save(JsonBuffer* buffer, Destination& dest, Source source) { - if (!StringTraits::is_null(source)) { - typename StringTraits::duplicate_t dup = - StringTraits::duplicate(source, buffer); - if (!dup) return false; - dest = dup; - } else { - dest = reinterpret_cast(0); - } + static bool save(JsonBuffer* buffer, Destination& dest, TString source) { + const char* dup = makeString(source).save(buffer); + if (!dup) return false; + dest = dup; return true; } }; -// const char*, const signed char*, const unsigned char* -template +// We duplicate all SerializedValue except SerializedValue +template struct ValueSaver< - Char*, typename enable_if::should_duplicate>::type> { + const SerializedValue&, + typename enable_if::value>::type> { template - static bool save(JsonBuffer*, Destination& dest, Char* source) { - dest = reinterpret_cast(source); + static bool save(JsonBuffer* buffer, Destination& dest, + const SerializedValue& source) { + const char* dup = makeString(source.data(), source.size()).save(buffer); + if (!dup) return false; + dest = SerializedValue(dup, source.size()); return true; } }; diff --git a/src/ArduinoJson/Json/IndentedPrint.hpp b/src/ArduinoJson/Json/IndentedPrint.hpp index a71ceb66..75d28fc8 100644 --- a/src/ArduinoJson/Json/IndentedPrint.hpp +++ b/src/ArduinoJson/Json/IndentedPrint.hpp @@ -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; } diff --git a/src/ArduinoJson/Json/JsonSerializer.hpp b/src/ArduinoJson/Json/JsonSerializer.hpp index 3f0989cf..97c21ab1 100644 --- a/src/ArduinoJson/Json/JsonSerializer.hpp +++ b/src/ArduinoJson/Json/JsonSerializer.hpp @@ -11,10 +11,10 @@ namespace ArduinoJson { namespace Internals { -template +template 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 _writer; + JsonWriter _writer; }; } // namespace Internals diff --git a/src/ArduinoJson/Json/JsonWriter.hpp b/src/ArduinoJson/Json/JsonWriter.hpp index 31071eea..680e7e6c 100644 --- a/src/ArduinoJson/Json/JsonWriter.hpp +++ b/src/ArduinoJson/Json/JsonWriter.hpp @@ -5,6 +5,7 @@ #pragma once #include +#include // for strlen #include "../Data/JsonInteger.hpp" #include "../Numbers/FloatParts.hpp" #include "../Polyfills/attributes.hpp" @@ -13,12 +14,12 @@ namespace ArduinoJson { namespace Internals { -template +template 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 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(s), strlen(s)); + } + void writeRaw(const char *begin, const char *end) { + _length += _writer.write(reinterpret_cast(begin), + static_cast(end - begin)); + } + template + void writeRaw(const char (&s)[N]) { + _length += _writer.write(reinterpret_cast(s), N - 1); } void writeRaw(char c) { - _length += _sink.print(c); + _length += _writer.write(static_cast(c)); } protected: - Print &_sink; + TWriter &_writer; size_t _length; private: diff --git a/src/ArduinoJson/Json/Prettyfier.hpp b/src/ArduinoJson/Json/Prettyfier.hpp index 8b4f0d2e..8168875a 100644 --- a/src/ArduinoJson/Json/Prettyfier.hpp +++ b/src/ArduinoJson/Json/Prettyfier.hpp @@ -10,25 +10,28 @@ namespace ArduinoJson { namespace Internals { // Converts a compact JSON string into an indented one. -template +template class Prettyfier { public: - explicit Prettyfier(IndentedPrint& p) : _sink(p) { + explicit Prettyfier(IndentedPrint& 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(c)); + } + + template + size_t write(const char (&s)[N]) { + return _sink.write(reinterpret_cast(s), N - 1); } char _previousChar; - IndentedPrint& _sink; + IndentedPrint& _sink; bool _inString; }; -} -} +} // namespace Internals +} // namespace ArduinoJson diff --git a/src/ArduinoJson/JsonArray.hpp b/src/ArduinoJson/JsonArray.hpp index b223960b..2410a8c3 100644 --- a/src/ArduinoJson/JsonArray.hpp +++ b/src/ArduinoJson/JsonArray.hpp @@ -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 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 bool set(size_t index, const T& value) { diff --git a/src/ArduinoJson/JsonArrayData.hpp b/src/ArduinoJson/JsonArrayData.hpp index 152a7008..38bd7055 100644 --- a/src/ArduinoJson/JsonArrayData.hpp +++ b/src/ArduinoJson/JsonArrayData.hpp @@ -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. diff --git a/src/ArduinoJson/JsonArraySubscript.hpp b/src/ArduinoJson/JsonArraySubscript.hpp index 66e1eb47..474f2dff 100644 --- a/src/ArduinoJson/JsonArraySubscript.hpp +++ b/src/ArduinoJson/JsonArraySubscript.hpp @@ -27,7 +27,7 @@ class JsonArraySubscript : public JsonVariantBase { // 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 FORCE_INLINE JsonArraySubscript& operator=(const T& src) { @@ -60,7 +60,7 @@ class JsonArraySubscript : public JsonVariantBase { // 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 FORCE_INLINE bool set(const TValue& value) { diff --git a/src/ArduinoJson/JsonObject.hpp b/src/ArduinoJson/JsonObject.hpp index 17f7ac25..29aa1ffc 100644 --- a/src/ArduinoJson/JsonObject.hpp +++ b/src/ArduinoJson/JsonObject.hpp @@ -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 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 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::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::is_null(key)) return false; + if (Internals::makeString(key).is_null()) return false; // search a matching key iterator it = findKey(key); diff --git a/src/ArduinoJson/JsonObjectData.hpp b/src/ArduinoJson/JsonObjectData.hpp index 5a9cf0a0..05d66504 100644 --- a/src/ArduinoJson/JsonObjectData.hpp +++ b/src/ArduinoJson/JsonObjectData.hpp @@ -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. diff --git a/src/ArduinoJson/JsonObjectSubscript.hpp b/src/ArduinoJson/JsonObjectSubscript.hpp index 9f758647..e9d8c0dc 100644 --- a/src/ArduinoJson/JsonObjectSubscript.hpp +++ b/src/ArduinoJson/JsonObjectSubscript.hpp @@ -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 FORCE_INLINE typename enable_if::value, bool>::type set( @@ -94,7 +95,7 @@ class JsonObjectSubscript template template -inline typename enable_if::has_equals, +inline typename enable_if::value, const JsonObjectSubscript >::type JsonVariantSubscripts::operator[](const TString &key) const { return impl()->template as()[key]; @@ -102,7 +103,7 @@ inline typename enable_if::has_equals, template template -inline typename enable_if::has_equals, +inline typename enable_if::value, JsonObjectSubscript >::type JsonVariantSubscripts::operator[](const TString &key) { return impl()->template as()[key]; @@ -110,7 +111,7 @@ inline typename enable_if::has_equals, template template -inline typename enable_if::has_equals, +inline typename enable_if::value, JsonObjectSubscript >::type JsonVariantSubscripts::operator[](const TString *key) { return impl()->template as()[key]; @@ -118,7 +119,7 @@ inline typename enable_if::has_equals, template template -inline typename enable_if::has_equals, +inline typename enable_if::value, const JsonObjectSubscript >::type JsonVariantSubscripts::operator[](const TString *key) const { return impl()->template as()[key]; diff --git a/src/ArduinoJson/JsonVariant.hpp b/src/ArduinoJson/JsonVariant.hpp index 274e960c..2ad63b1d 100644 --- a/src/ArduinoJson/JsonVariant.hpp +++ b/src/ArduinoJson/JsonVariant.hpp @@ -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 { } // Create a JsonVariant containing an unparsed string - JsonVariant(Internals::RawJsonString value) { + JsonVariant(Internals::SerializedValue 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 { // std::string as() const; // String as() const; template - typename Internals::enable_if::has_append, T>::type + typename Internals::enable_if::value, T>::type as() const { const char *cstr = variantAsString(); if (cstr) return T(cstr); @@ -276,7 +278,7 @@ class JsonVariant : public Internals::JsonVariantBase { 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 { 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 diff --git a/src/ArduinoJson/JsonVariantComparisons.hpp b/src/ArduinoJson/JsonVariantComparisons.hpp index b08ff0c2..f9f55cc3 100644 --- a/src/ArduinoJson/JsonVariantComparisons.hpp +++ b/src/ArduinoJson/JsonVariantComparisons.hpp @@ -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 enable_if::has_equals, bool>::type equals( + typename enable_if::value, bool>::type equals( const TString &comparand) const { - const char *value = as(); - return StringTraits::equals(comparand, value); + return makeString(comparand).equals(as()); } template - typename enable_if::value && - !StringTraits::has_equals, - bool>::type + typename enable_if< + !IsVariant::value && !IsString::value, bool>::type equals(const TComparand &comparand) const { return as() == comparand; } @@ -132,8 +130,7 @@ class JsonVariantComparisons { if (is() && right.template is()) return as() == right.template as(); if (is() && right.template is()) - return StringTraits::equals(as(), - right.template as()); + return makeString(as()).equals(right.template as()); return false; } diff --git a/src/ArduinoJson/JsonVariantImpl.hpp b/src/ArduinoJson/JsonVariantImpl.hpp index b3c3d834..cc752939 100644 --- a/src/ArduinoJson/JsonVariantImpl.hpp +++ b/src/ArduinoJson/JsonVariantImpl.hpp @@ -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(_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 @@ -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(_content.asInteger); case JSON_STRING: - case JSON_UNPARSED: return parseFloat(_content.asString); default: return static_cast(_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 diff --git a/src/ArduinoJson/JsonVariantSubscripts.hpp b/src/ArduinoJson/JsonVariantSubscripts.hpp index 2227df9a..d2aa3aa5 100644 --- a/src/ArduinoJson/JsonVariantSubscripts.hpp +++ b/src/ArduinoJson/JsonVariantSubscripts.hpp @@ -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 FORCE_INLINE - typename enable_if::has_equals, + typename enable_if::value, const JsonObjectSubscript >::type operator[](const TString &key) const; // // const JsonObjectSubscript operator[](TKey) const; // TKey = const std::string&, const String& template - FORCE_INLINE typename enable_if::has_equals, + FORCE_INLINE typename enable_if::value, JsonObjectSubscript >::type operator[](const TString &key); // // JsonObjectSubscript operator[](TKey); // TKey = const char*, const char[N], const FlashStringHelper* template - FORCE_INLINE typename enable_if::has_equals, + FORCE_INLINE typename enable_if::value, JsonObjectSubscript >::type operator[](const TString *key); // @@ -65,7 +65,7 @@ class JsonVariantSubscripts { // TKey = const char*, const char[N], const FlashStringHelper* template FORCE_INLINE - typename enable_if::has_equals, + typename enable_if::value, const JsonObjectSubscript >::type operator[](const TString *key) const; diff --git a/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp b/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp index 0981f662..fe1e6163 100644 --- a/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp @@ -13,10 +13,10 @@ namespace ArduinoJson { namespace Internals { -template +template class MsgPackSerializer { public: - MsgPackSerializer(TPrint& output) : _output(&output), _bytesWritten(0) {} + MsgPackSerializer(TWriter& writer) : _writer(&writer), _bytesWritten(0) {} template typename enable_if::type acceptFloat(T value32) { @@ -91,7 +91,9 @@ class MsgPackSerializer { writeBytes(reinterpret_cast(value), n); } - void acceptRawJson(const char* /*value*/) {} + void acceptRawJson(const char* data, size_t size) { + writeBytes(reinterpret_cast(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 @@ -164,7 +165,7 @@ class MsgPackSerializer { writeBytes(reinterpret_cast(&value), sizeof(value)); } - TPrint* _output; + TWriter* _writer; size_t _bytesWritten; }; } // namespace Internals diff --git a/src/ArduinoJson/RawJson.hpp b/src/ArduinoJson/RawJson.hpp deleted file mode 100644 index 4beb980e..00000000 --- a/src/ArduinoJson/RawJson.hpp +++ /dev/null @@ -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 -class RawJsonString { - public: - explicit RawJsonString(T str) : _str(str) {} - operator T() const { - return _str; - } - - private: - T _str; -}; - -template -struct StringTraits, void> { - static bool is_null(RawJsonString source) { - return StringTraits::is_null(static_cast(source)); - } - - typedef RawJsonString duplicate_t; - - template - static duplicate_t duplicate(RawJsonString source, Buffer* buffer) { - return duplicate_t(StringTraits::duplicate(source, buffer)); - } - - static const bool has_append = false; - static const bool has_equals = false; - static const bool should_duplicate = StringTraits::should_duplicate; -}; -} - -template -inline Internals::RawJsonString RawJson(T str) { - return Internals::RawJsonString(str); -} -} diff --git a/src/ArduinoJson/Serialization/DummyPrint.hpp b/src/ArduinoJson/Serialization/DummyWriter.hpp similarity index 69% rename from src/ArduinoJson/Serialization/DummyPrint.hpp rename to src/ArduinoJson/Serialization/DummyWriter.hpp index 40a69706..c2c26a04 100644 --- a/src/ArduinoJson/Serialization/DummyPrint.hpp +++ b/src/ArduinoJson/Serialization/DummyWriter.hpp @@ -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 diff --git a/src/ArduinoJson/Serialization/DynamicStringBuilder.hpp b/src/ArduinoJson/Serialization/DynamicStringBuilder.hpp deleted file mode 100644 index 931066ae..00000000 --- a/src/ArduinoJson/Serialization/DynamicStringBuilder.hpp +++ /dev/null @@ -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 -class DynamicStringBuilder { - public: - DynamicStringBuilder(TString &str) : _str(str) {} - - size_t print(char c) { - StringTraits::append(_str, c); - return 1; - } - - size_t print(const char *s) { - size_t initialLen = _str.length(); - StringTraits::append(_str, s); - return _str.length() - initialLen; - } - - private: - DynamicStringBuilder &operator=(const DynamicStringBuilder &); - - TString &_str; -}; -} // namespace Internals -} // namespace ArduinoJson diff --git a/src/ArduinoJson/Serialization/DynamicStringWriter.hpp b/src/ArduinoJson/Serialization/DynamicStringWriter.hpp new file mode 100644 index 00000000..75879ced --- /dev/null +++ b/src/ArduinoJson/Serialization/DynamicStringWriter.hpp @@ -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 +#endif + +#if ARDUINOJSON_ENABLE_STD_STRING +#include +#endif + +namespace ArduinoJson { +namespace Internals { + +template +struct IsWriteableString : false_type {}; + +// A Print implementation that allows to write in a String +template +class DynamicStringWriter {}; + +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +template <> +struct IsWriteableString : true_type {}; + +template <> +class DynamicStringWriter { + public: + DynamicStringWriter(String &str) : _str(&str) {} + + size_t write(uint8_t c) { + _str->operator+=(static_cast(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(*s++)); + n--; + } + return n; + } + + private: + String *_str; +}; +#endif + +#if ARDUINOJSON_ENABLE_STD_STRING +template <> +struct IsWriteableString : true_type {}; + +template <> +class DynamicStringWriter { + public: + DynamicStringWriter(std::string &str) : _str(&str) {} + + size_t write(uint8_t c) { + _str->operator+=(static_cast(c)); + return 1; + } + + size_t write(const uint8_t *s, size_t n) { + _str->append(reinterpret_cast(s), n); + return n; + } + + private: + std::string *_str; +}; +#endif +} // namespace Internals +} // namespace ArduinoJson diff --git a/src/ArduinoJson/Serialization/StaticStringBuilder.hpp b/src/ArduinoJson/Serialization/StaticStringWriter.hpp similarity index 60% rename from src/ArduinoJson/Serialization/StaticStringBuilder.hpp rename to src/ArduinoJson/Serialization/StaticStringWriter.hpp index b604941e..0384b621 100644 --- a/src/ArduinoJson/Serialization/StaticStringBuilder.hpp +++ b/src/ArduinoJson/Serialization/StaticStringWriter.hpp @@ -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(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(*s++); + n--; + } *p = '\0'; return size_t(p - begin); } diff --git a/src/ArduinoJson/Serialization/StreamPrintAdapter.hpp b/src/ArduinoJson/Serialization/StreamWriter.hpp similarity index 51% rename from src/ArduinoJson/Serialization/StreamPrintAdapter.hpp rename to src/ArduinoJson/Serialization/StreamWriter.hpp index 60f0af4a..94cc39d1 100644 --- a/src/ArduinoJson/Serialization/StreamPrintAdapter.hpp +++ b/src/ArduinoJson/Serialization/StreamWriter.hpp @@ -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(s), + static_cast(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 diff --git a/src/ArduinoJson/Serialization/measure.hpp b/src/ArduinoJson/Serialization/measure.hpp index 133d45ca..395e8c3b 100644 --- a/src/ArduinoJson/Serialization/measure.hpp +++ b/src/ArduinoJson/Serialization/measure.hpp @@ -4,15 +4,15 @@ #pragma once -#include "./DummyPrint.hpp" +#include "./DummyWriter.hpp" namespace ArduinoJson { namespace Internals { template