Przeglądaj źródła

Renamed function `RawJson()` to `serialized()`

Benoit Blanchon 7 lat temu
rodzic
commit
87fa87d87b
59 zmienionych plików z 842 dodań i 550 usunięć
  1. 18 0
      CHANGELOG.md
  2. 3 2
      examples/ProgmemExample/ProgmemExample.ino
  3. 2 2
      examples/StringExample/StringExample.ino
  4. 5 1
      src/ArduinoJson/Data/JsonVariantContent.hpp
  5. 18 17
      src/ArduinoJson/Data/ValueSaver.hpp
  6. 10 7
      src/ArduinoJson/Json/IndentedPrint.hpp
  7. 6 5
      src/ArduinoJson/Json/JsonSerializer.hpp
  8. 31 19
      src/ArduinoJson/Json/JsonWriter.hpp
  9. 34 22
      src/ArduinoJson/Json/Prettyfier.hpp
  10. 2 2
      src/ArduinoJson/JsonArray.hpp
  11. 0 1
      src/ArduinoJson/JsonArrayData.hpp
  12. 2 2
      src/ArduinoJson/JsonArraySubscript.hpp
  13. 4 4
      src/ArduinoJson/JsonObject.hpp
  14. 0 1
      src/ArduinoJson/JsonObjectData.hpp
  15. 6 5
      src/ArduinoJson/JsonObjectSubscript.hpp
  16. 8 8
      src/ArduinoJson/JsonVariant.hpp
  17. 6 9
      src/ArduinoJson/JsonVariantComparisons.hpp
  18. 6 17
      src/ArduinoJson/JsonVariantImpl.hpp
  19. 5 5
      src/ArduinoJson/JsonVariantSubscripts.hpp
  20. 9 8
      src/ArduinoJson/MsgPack/MsgPackSerializer.hpp
  21. 0 46
      src/ArduinoJson/RawJson.hpp
  22. 4 4
      src/ArduinoJson/Serialization/DummyWriter.hpp
  23. 0 35
      src/ArduinoJson/Serialization/DynamicStringBuilder.hpp
  24. 81 0
      src/ArduinoJson/Serialization/DynamicStringWriter.hpp
  25. 9 6
      src/ArduinoJson/Serialization/StaticStringWriter.hpp
  26. 10 9
      src/ArduinoJson/Serialization/StreamWriter.hpp
  27. 3 3
      src/ArduinoJson/Serialization/measure.hpp
  28. 13 13
      src/ArduinoJson/Serialization/serialize.hpp
  29. 70 0
      src/ArduinoJson/SerializedValue.hpp
  30. 60 0
      src/ArduinoJson/Strings/ArduinoString.hpp
  31. 0 44
      src/ArduinoJson/Strings/CharPointer.hpp
  32. 47 0
      src/ArduinoJson/Strings/FixedSizeFlashString.hpp
  33. 48 0
      src/ArduinoJson/Strings/FixedSizeRamString.hpp
  34. 0 41
      src/ArduinoJson/Strings/FlashString.hpp
  35. 0 73
      src/ArduinoJson/Strings/StdString.hpp
  36. 52 0
      src/ArduinoJson/Strings/StlString.hpp
  37. 0 30
      src/ArduinoJson/Strings/StringTraits.hpp
  38. 36 0
      src/ArduinoJson/Strings/StringTypes.hpp
  39. 48 0
      src/ArduinoJson/Strings/ZeroTerminatedFlashString.hpp
  40. 53 0
      src/ArduinoJson/Strings/ZeroTerminatedRamString.hpp
  41. 3 2
      test/JsonArray/CMakeLists.txt
  42. 16 4
      test/JsonArray/add.cpp
  43. 0 8
      test/JsonArray/createNested.cpp
  44. 25 0
      test/JsonArray/isNull.cpp
  45. 17 13
      test/JsonArray/size.cpp
  46. 0 0
      test/JsonArray/undefined.cpp
  47. 1 1
      test/JsonObject/CMakeLists.txt
  48. 0 15
      test/JsonObject/basics.cpp
  49. 25 0
      test/JsonObject/isNull.cpp
  50. 4 4
      test/JsonSerializer/JsonArray.cpp
  51. 3 3
      test/JsonSerializer/JsonObject.cpp
  52. 0 17
      test/JsonVariant/is.cpp
  53. 3 3
      test/JsonWriter/writeFloat.cpp
  54. 3 3
      test/JsonWriter/writeString.cpp
  55. 1 2
      test/Misc/CMakeLists.txt
  56. 0 22
      test/Misc/StringTraits.cpp
  57. 17 12
      test/Misc/StringWriter.cpp
  58. 10 0
      test/MsgPackSerializer/serializeObject.cpp
  59. 5 0
      test/MsgPackSerializer/serializeVariant.cpp

+ 18 - 0
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
 -----------

+ 3 - 2
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")) {

+ 2 - 2
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.

+ 5 - 1
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

+ 18 - 17
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 <typename Source>
+// We duplicate all strings except const char*
+template <typename TString>
 struct ValueSaver<
-    Source, typename enable_if<StringTraits<Source>::should_duplicate>::type> {
+    TString, typename enable_if<IsString<TString>::value &&
+                                !is_same<const char*, TString>::value>::type> {
   template <typename Destination>
-  static bool save(JsonBuffer* buffer, Destination& dest, Source source) {
-    if (!StringTraits<Source>::is_null(source)) {
-      typename StringTraits<Source>::duplicate_t dup =
-          StringTraits<Source>::duplicate(source, buffer);
-      if (!dup) return false;
-      dest = dup;
-    } else {
-      dest = reinterpret_cast<const char*>(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 <typename Char>
+// We duplicate all SerializedValue<T> except SerializedValue<const char*>
+template <typename TString>
 struct ValueSaver<
-    Char*, typename enable_if<!StringTraits<Char*>::should_duplicate>::type> {
+    const SerializedValue<TString>&,
+    typename enable_if<!is_same<const char*, TString>::value>::type> {
   template <typename Destination>
-  static bool save(JsonBuffer*, Destination& dest, Char* source) {
-    dest = reinterpret_cast<const char*>(source);
+  static bool save(JsonBuffer* buffer, Destination& dest,
+                   const SerializedValue<TString>& source) {
+    const char* dup = makeString(source.data(), source.size()).save(buffer);
+    if (!dup) return false;
+    dest = SerializedValue<const char*>(dup, source.size());
     return true;
   }
 };

+ 10 - 7
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;
   }
 

+ 6 - 5
src/ArduinoJson/Json/JsonSerializer.hpp

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

+ 31 - 19
src/ArduinoJson/Json/JsonWriter.hpp

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

+ 34 - 22
src/ArduinoJson/Json/Prettyfier.hpp

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

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

+ 0 - 1
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.

+ 2 - 2
src/ArduinoJson/JsonArraySubscript.hpp

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

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

+ 0 - 1
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.

+ 6 - 5
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 <typename TValue>
   FORCE_INLINE typename enable_if<!is_array<TValue>::value, bool>::type set(
@@ -94,7 +95,7 @@ class JsonObjectSubscript
 
 template <typename TImpl>
 template <typename TString>
-inline typename enable_if<StringTraits<TString>::has_equals,
+inline typename enable_if<IsString<TString>::value,
                           const JsonObjectSubscript<const TString &> >::type
     JsonVariantSubscripts<TImpl>::operator[](const TString &key) const {
   return impl()->template as<JsonObject>()[key];
@@ -102,7 +103,7 @@ inline typename enable_if<StringTraits<TString>::has_equals,
 
 template <typename TImpl>
 template <typename TString>
-inline typename enable_if<StringTraits<TString>::has_equals,
+inline typename enable_if<IsString<TString>::value,
                           JsonObjectSubscript<const TString &> >::type
     JsonVariantSubscripts<TImpl>::operator[](const TString &key) {
   return impl()->template as<JsonObject>()[key];
@@ -110,7 +111,7 @@ inline typename enable_if<StringTraits<TString>::has_equals,
 
 template <typename TImpl>
 template <typename TString>
-inline typename enable_if<StringTraits<const TString *>::has_equals,
+inline typename enable_if<IsString<const TString *>::value,
                           JsonObjectSubscript<const TString *> >::type
     JsonVariantSubscripts<TImpl>::operator[](const TString *key) {
   return impl()->template as<JsonObject>()[key];
@@ -118,7 +119,7 @@ inline typename enable_if<StringTraits<const TString *>::has_equals,
 
 template <typename TImpl>
 template <typename TString>
-inline typename enable_if<StringTraits<TString *>::has_equals,
+inline typename enable_if<IsString<TString *>::value,
                           const JsonObjectSubscript<const TString *> >::type
     JsonVariantSubscripts<TImpl>::operator[](const TString *key) const {
   return impl()->template as<JsonObject>()[key];

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

+ 6 - 9
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 TString>
-  typename enable_if<StringTraits<TString>::has_equals, bool>::type equals(
+  typename enable_if<IsString<TString>::value, bool>::type equals(
       const TString &comparand) const {
-    const char *value = as<const char *>();
-    return StringTraits<TString>::equals(comparand, value);
+    return makeString(comparand).equals(as<const char *>());
   }
 
   template <typename TComparand>
-  typename enable_if<!IsVariant<TComparand>::value &&
-                         !StringTraits<TComparand>::has_equals,
-                     bool>::type
+  typename enable_if<
+      !IsVariant<TComparand>::value && !IsString<TComparand>::value, bool>::type
   equals(const TComparand &comparand) const {
     return as<TComparand>() == comparand;
   }
@@ -132,8 +130,7 @@ class JsonVariantComparisons {
     if (is<JsonObject>() && right.template is<JsonObject>())
       return as<JsonObject>() == right.template as<JsonObject>();
     if (is<char *>() && right.template is<char *>())
-      return StringTraits<const char *>::equals(as<char *>(),
-                                                right.template as<char *>());
+      return makeString(as<char *>()).equals(right.template as<char *>());
 
     return false;
   }

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

+ 5 - 5
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 <typename TString>
   FORCE_INLINE
-      typename enable_if<StringTraits<TString>::has_equals,
+      typename enable_if<IsString<TString>::value,
                          const JsonObjectSubscript<const TString &> >::type
       operator[](const TString &key) const;
   //
   // const JsonObjectSubscript operator[](TKey) const;
   // TKey = const std::string&, const String&
   template <typename TString>
-  FORCE_INLINE typename enable_if<StringTraits<TString>::has_equals,
+  FORCE_INLINE typename enable_if<IsString<TString>::value,
                                   JsonObjectSubscript<const TString &> >::type
   operator[](const TString &key);
   //
   // JsonObjectSubscript operator[](TKey);
   // TKey = const char*, const char[N], const FlashStringHelper*
   template <typename TString>
-  FORCE_INLINE typename enable_if<StringTraits<const TString *>::has_equals,
+  FORCE_INLINE typename enable_if<IsString<const TString *>::value,
                                   JsonObjectSubscript<const TString *> >::type
   operator[](const TString *key);
   //
@@ -65,7 +65,7 @@ class JsonVariantSubscripts {
   // TKey = const char*, const char[N], const FlashStringHelper*
   template <typename TString>
   FORCE_INLINE
-      typename enable_if<StringTraits<TString *>::has_equals,
+      typename enable_if<IsString<TString *>::value,
                          const JsonObjectSubscript<const TString *> >::type
       operator[](const TString *key) const;
 

+ 9 - 8
src/ArduinoJson/MsgPack/MsgPackSerializer.hpp

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

+ 0 - 46
src/ArduinoJson/RawJson.hpp

@@ -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);
-}
-}

+ 4 - 4
src/ArduinoJson/Serialization/DummyPrint.hpp → 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

+ 0 - 35
src/ArduinoJson/Serialization/DynamicStringBuilder.hpp

@@ -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

+ 81 - 0
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 <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

+ 9 - 6
src/ArduinoJson/Serialization/StaticStringBuilder.hpp → 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<char>(c);
     *p = '\0';
     return 1;
   }
 
-  size_t print(const char *s) {
+  size_t write(const uint8_t *s, size_t n) {
     char *begin = p;
-    while (p < end && *s) *p++ = *s++;
+    while (p < end && n > 0) {
+      *p++ = static_cast<char>(*s++);
+      n--;
+    }
     *p = '\0';
     return size_t(p - begin);
   }

+ 10 - 9
src/ArduinoJson/Serialization/StreamPrintAdapter.hpp → 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<const char*>(s),
+              static_cast<std::streamsize>(n));
+    return n;
   }
 
  private:
   // cannot be assigned
-  StreamPrintAdapter& operator=(const StreamPrintAdapter&);
+  StreamWriter& operator=(const StreamWriter&);
 
   std::ostream& _os;
 };
-}
-}
+}  // namespace Internals
+}  // namespace ArduinoJson
 
 #endif  // ARDUINOJSON_ENABLE_STD_STREAM

+ 3 - 3
src/ArduinoJson/Serialization/measure.hpp

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

+ 13 - 13
src/ArduinoJson/Serialization/serialize.hpp

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

+ 70 - 0
src/ArduinoJson/SerializedValue.hpp

@@ -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

+ 60 - 0
src/ArduinoJson/Strings/ArduinoString.hpp

@@ -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

+ 0 - 44
src/ArduinoJson/Strings/CharPointer.hpp

@@ -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

+ 47 - 0
src/ArduinoJson/Strings/FixedSizeFlashString.hpp

@@ -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

+ 48 - 0
src/ArduinoJson/Strings/FixedSizeRamString.hpp

@@ -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

+ 0 - 41
src/ArduinoJson/Strings/FlashString.hpp

@@ -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

+ 0 - 73
src/ArduinoJson/Strings/StdString.hpp

@@ -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

+ 52 - 0
src/ArduinoJson/Strings/StlString.hpp

@@ -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

+ 0 - 30
src/ArduinoJson/Strings/StringTraits.hpp

@@ -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"

+ 36 - 0
src/ArduinoJson/Strings/StringTypes.hpp

@@ -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

+ 48 - 0
src/ArduinoJson/Strings/ZeroTerminatedFlashString.hpp

@@ -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

+ 53 - 0
src/ArduinoJson/Strings/ZeroTerminatedRamString.hpp

@@ -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

+ 3 - 2
test/JsonArray/CMakeLists.txt

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

+ 16 - 4
test/JsonArray/add.cpp

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

+ 0 - 8
test/JsonArray/basics.cpp → test/JsonArray/createNested.cpp

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

+ 25 - 0
test/JsonArray/isNull.cpp

@@ -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);
+  }
+}

+ 17 - 13
test/JsonArray/size.cpp

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

+ 0 - 0
test/JsonArray/invalid.cpp → test/JsonArray/undefined.cpp


+ 1 - 1
test/JsonObject/CMakeLists.txt

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

+ 0 - 15
test/JsonObject/basics.cpp

@@ -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);
-  }
-}

+ 25 - 0
test/JsonObject/isNull.cpp

@@ -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);
+  }
+}

+ 4 - 4
test/JsonSerializer/JsonArray.cpp

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

+ 3 - 3
test/JsonSerializer/JsonObject.cpp

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

+ 0 - 17
test/JsonVariant/is.cpp

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

+ 3 - 3
test/JsonWriter/writeFloat.cpp

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

+ 3 - 3
test/JsonWriter/writeString.cpp

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

+ 1 - 2
test/Misc/CMakeLists.txt

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

+ 0 - 22
test/Misc/StringTraits.cpp

@@ -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*> >());
-  }
-}

+ 17 - 12
test/Misc/StringBuilder.cpp → test/Misc/StringWriter.cpp

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

+ 10 - 0
test/MsgPackSerializer/serializeObject.cpp

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

+ 5 - 0
test/MsgPackSerializer/serializeVariant.cpp

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