Эх сурвалжийг харах

Added support for custom reader classes

Benoit Blanchon 6 жил өмнө
parent
commit
3a169df0a5

+ 1 - 1
CHANGELOG.md

@@ -4,7 +4,7 @@ ArduinoJson: change log
 HEAD
 ----
 
-* Added support for custom writer classes (issue #1088)
+* Added support for custom writer/reader classes (issue #1088)
 * Added conversion from `JsonArray` and `JsonObject` to `bool`, to be consistent with `JsonVariant`
 * Fixed `deserializeJson()` when input contains duplicate keys (issue #1095)
 * Improved `deserializeMsgPack()` speed by reading several bytes at once

+ 1 - 0
extras/tests/CMakeLists.txt

@@ -72,6 +72,7 @@ if(MSVC)
 	)
 endif()
 
+include_directories(Helpers)
 add_subdirectory(ElementProxy)
 add_subdirectory(IntegrationTests)
 add_subdirectory(JsonArray)

+ 26 - 0
extras/tests/Helpers/CustomReader.hpp

@@ -0,0 +1,26 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2019
+// MIT License
+
+#pragma once
+
+#include <sstream>
+
+class CustomReader {
+  std::stringstream _stream;
+
+ public:
+  CustomReader(const char* input) : _stream(input) {}
+
+  int read() {
+    return _stream.get();
+  }
+
+  size_t readBytes(char* buffer, size_t length) {
+    _stream.read(buffer, static_cast<std::streamsize>(length));
+    return static_cast<size_t>(_stream.gcount());
+  }
+
+ private:
+  CustomReader(const CustomReader&);
+};

+ 13 - 0
extras/tests/JsonDeserializer/input_types.cpp

@@ -6,6 +6,8 @@
 #include <catch.hpp>
 #include <sstream>
 
+#include "CustomReader.hpp"
+
 TEST_CASE("deserializeJson(const std::string&)") {
   DynamicJsonDocument doc(4096);
 
@@ -113,3 +115,14 @@ TEST_CASE("deserializeJson(VLA)") {
   REQUIRE(err == DeserializationError::Ok);
 }
 #endif
+
+TEST_CASE("deserializeJson(CustomReader)") {
+  DynamicJsonDocument doc(4096);
+  CustomReader reader("[4,2]");
+  DeserializationError err = deserializeJson(doc, reader);
+
+  REQUIRE(err == DeserializationError::Ok);
+  REQUIRE(doc.size() == 2);
+  REQUIRE(doc[0] == 4);
+  REQUIRE(doc[1] == 2);
+}

+ 13 - 13
extras/tests/Misc/Readers.cpp

@@ -2,15 +2,15 @@
 // Copyright Benoit Blanchon 2014-2019
 // MIT License
 
-#include <ArduinoJson.h>
+#include <ArduinoJson/Deserialization/Reader.hpp>
 #include <catch.hpp>
 
 using namespace ARDUINOJSON_NAMESPACE;
 
-TEST_CASE("StdStreamReader") {
+TEST_CASE("Reader<std::istringstream>") {
   SECTION("read()") {
     std::istringstream src("\x01\xFF");
-    StdStreamReader reader(src);
+    Reader<std::istringstream> reader(src);
 
     REQUIRE(reader.read() == 0x01);
     REQUIRE(reader.read() == 0xFF);
@@ -19,7 +19,7 @@ TEST_CASE("StdStreamReader") {
 
   SECTION("readBytes() all at once") {
     std::istringstream src("ABC");
-    StdStreamReader reader(src);
+    Reader<std::istringstream> reader(src);
 
     char buffer[8] = "abcd";
     REQUIRE(reader.readBytes(buffer, 4) == 3);
@@ -32,7 +32,7 @@ TEST_CASE("StdStreamReader") {
 
   SECTION("readBytes() in two parts") {
     std::istringstream src("ABCDEF");
-    StdStreamReader reader(src);
+    Reader<std::istringstream> reader(src);
 
     char buffer[12] = "abcdefg";
     REQUIRE(reader.readBytes(buffer, 4) == 4);
@@ -48,9 +48,9 @@ TEST_CASE("StdStreamReader") {
   }
 }
 
-TEST_CASE("SafeCharPointerReader") {
+TEST_CASE("BoundedReader<const char*>") {
   SECTION("read") {
-    SafeCharPointerReader reader("\x01\xFF", 2);
+    BoundedReader<const char*> reader("\x01\xFF", 2);
     REQUIRE(reader.read() == 0x01);
     REQUIRE(reader.read() == 0xFF);
     REQUIRE(reader.read() == -1);
@@ -58,7 +58,7 @@ TEST_CASE("SafeCharPointerReader") {
   }
 
   SECTION("readBytes() all at once") {
-    SafeCharPointerReader reader("ABCD", 3);
+    BoundedReader<const char*> reader("ABCD", 3);
 
     char buffer[8] = "abcd";
     REQUIRE(reader.readBytes(buffer, 4) == 3);
@@ -70,7 +70,7 @@ TEST_CASE("SafeCharPointerReader") {
   }
 
   SECTION("readBytes() in two parts") {
-    SafeCharPointerReader reader("ABCDEF", 6);
+    BoundedReader<const char*> reader("ABCDEF", 6);
 
     char buffer[8] = "abcdefg";
     REQUIRE(reader.readBytes(buffer, 4) == 4);
@@ -86,9 +86,9 @@ TEST_CASE("SafeCharPointerReader") {
   }
 }
 
-TEST_CASE("UnsafeCharPointerReader") {
+TEST_CASE("Reader<const char*>") {
   SECTION("read()") {
-    UnsafeCharPointerReader reader("\x01\xFF\x00\x12");
+    Reader<const char*> reader("\x01\xFF\x00\x12");
     REQUIRE(reader.read() == 0x01);
     REQUIRE(reader.read() == 0xFF);
     REQUIRE(reader.read() == 0);
@@ -96,7 +96,7 @@ TEST_CASE("UnsafeCharPointerReader") {
   }
 
   SECTION("readBytes() all at once") {
-    UnsafeCharPointerReader reader("ABCD");
+    Reader<const char*> reader("ABCD");
 
     char buffer[8] = "abcd";
     REQUIRE(reader.readBytes(buffer, 3) == 3);
@@ -108,7 +108,7 @@ TEST_CASE("UnsafeCharPointerReader") {
   }
 
   SECTION("readBytes() in two parts") {
-    UnsafeCharPointerReader reader("ABCDEF");
+    Reader<const char*> reader("ABCDEF");
 
     char buffer[8] = "abcdefg";
     REQUIRE(reader.readBytes(buffer, 4) == 4);

+ 10 - 10
extras/tests/MixedConfiguration/enable_progmem_1.cpp

@@ -86,11 +86,11 @@ TEST_CASE("memcpy_P") {
   CHECK(dst[3] == 0);
 }
 
-TEST_CASE("SafeCharPointerReader") {
-  using ARDUINOJSON_NAMESPACE::SafeFlashStringReader;
+TEST_CASE("BoundedReader<const __FlashStringHelper*>") {
+  using namespace ARDUINOJSON_NAMESPACE;
 
   SECTION("read") {
-    SafeFlashStringReader reader(F("\x01\xFF"), 2);
+    BoundedReader<const __FlashStringHelper*> reader(F("\x01\xFF"), 2);
     REQUIRE(reader.read() == 0x01);
     REQUIRE(reader.read() == 0xFF);
     REQUIRE(reader.read() == -1);
@@ -98,7 +98,7 @@ TEST_CASE("SafeCharPointerReader") {
   }
 
   SECTION("readBytes() all at once") {
-    SafeFlashStringReader reader(F("ABCD"), 3);
+    BoundedReader<const __FlashStringHelper*> reader(F("ABCD"), 3);
 
     char buffer[8] = "abcd";
     REQUIRE(reader.readBytes(buffer, 4) == 3);
@@ -110,7 +110,7 @@ TEST_CASE("SafeCharPointerReader") {
   }
 
   SECTION("readBytes() in two parts") {
-    SafeFlashStringReader reader(F("ABCDEF"), 6);
+    BoundedReader<const __FlashStringHelper*> reader(F("ABCDEF"), 6);
 
     char buffer[8] = "abcdefg";
     REQUIRE(reader.readBytes(buffer, 4) == 4);
@@ -126,11 +126,11 @@ TEST_CASE("SafeCharPointerReader") {
   }
 }
 
-TEST_CASE("UnsafeFlashStringReader") {
-  using ARDUINOJSON_NAMESPACE::UnsafeFlashStringReader;
+TEST_CASE("Reader<const __FlashStringHelper*>") {
+  using namespace ARDUINOJSON_NAMESPACE;
 
   SECTION("read()") {
-    UnsafeFlashStringReader reader(F("\x01\xFF\x00\x12"));
+    Reader<const __FlashStringHelper*> reader(F("\x01\xFF\x00\x12"));
     REQUIRE(reader.read() == 0x01);
     REQUIRE(reader.read() == 0xFF);
     REQUIRE(reader.read() == 0);
@@ -138,7 +138,7 @@ TEST_CASE("UnsafeFlashStringReader") {
   }
 
   SECTION("readBytes() all at once") {
-    UnsafeFlashStringReader reader(F("ABCD"));
+    Reader<const __FlashStringHelper*> reader(F("ABCD"));
 
     char buffer[8] = "abcd";
     REQUIRE(reader.readBytes(buffer, 3) == 3);
@@ -150,7 +150,7 @@ TEST_CASE("UnsafeFlashStringReader") {
   }
 
   SECTION("readBytes() in two parts") {
-    UnsafeFlashStringReader reader(F("ABCDEF"));
+    Reader<const __FlashStringHelper*> reader(F("ABCDEF"));
 
     char buffer[8] = "abcdefg";
     REQUIRE(reader.readBytes(buffer, 4) == 4);

+ 13 - 0
extras/tests/MsgPackDeserializer/input_types.cpp

@@ -5,6 +5,8 @@
 #include <ArduinoJson.h>
 #include <catch.hpp>
 
+#include "CustomReader.hpp"
+
 TEST_CASE("deserializeMsgPack(const std::string&)") {
   DynamicJsonDocument doc(4096);
 
@@ -80,3 +82,14 @@ TEST_CASE("deserializeMsgPack(VLA)") {
   REQUIRE(err == DeserializationError::Ok);
 }
 #endif
+
+TEST_CASE("deserializeMsgPack(CustomReader)") {
+  DynamicJsonDocument doc(4096);
+  CustomReader reader("\x92\xA5Hello\xA5world");
+  DeserializationError err = deserializeMsgPack(doc, reader);
+
+  REQUIRE(err == DeserializationError::Ok);
+  REQUIRE(doc.size() == 2);
+  REQUIRE(doc[0] == "Hello");
+  REQUIRE(doc[1] == "world");
+}

+ 0 - 65
src/ArduinoJson/Deserialization/CharPointerReader.hpp

@@ -1,65 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2019
-// MIT License
-
-#pragma once
-
-#include <ArduinoJson/Deserialization/IteratorReader.hpp>
-#include <ArduinoJson/Namespace.hpp>
-
-namespace ARDUINOJSON_NAMESPACE {
-
-template <typename T>
-struct IsCharOrVoid {
-  static const bool value =
-      is_same<T, void>::value || is_same<T, char>::value ||
-      is_same<T, unsigned char>::value || is_same<T, signed char>::value;
-};
-
-template <typename T>
-struct IsCharOrVoid<const T> : IsCharOrVoid<T> {};
-
-class UnsafeCharPointerReader {
-  const char* _ptr;
-
- public:
-  explicit UnsafeCharPointerReader(const char* ptr)
-      : _ptr(ptr ? ptr : reinterpret_cast<const char*>("")) {}
-
-  int read() {
-    return static_cast<unsigned char>(*_ptr++);
-  }
-
-  size_t readBytes(char* buffer, size_t length) {
-    for (size_t i = 0; i < length; i++) buffer[i] = *_ptr++;
-    return length;
-  }
-};
-
-class SafeCharPointerReader : public IteratorReader<const char*> {
- public:
-  explicit SafeCharPointerReader(const char* ptr, size_t len)
-      : IteratorReader<const char*>(ptr, ptr + len) {}
-};
-
-template <typename TChar>
-inline typename enable_if<IsCharOrVoid<TChar>::value,
-                          UnsafeCharPointerReader>::type
-makeReader(TChar* input) {
-  return UnsafeCharPointerReader(reinterpret_cast<const char*>(input));
-}
-
-template <typename TChar>
-inline
-    typename enable_if<IsCharOrVoid<TChar>::value, SafeCharPointerReader>::type
-    makeReader(TChar* input, size_t n) {
-  return SafeCharPointerReader(reinterpret_cast<const char*>(input), n);
-}
-
-#if ARDUINOJSON_ENABLE_ARDUINO_STRING
-inline SafeCharPointerReader makeReader(const ::String& input) {
-  return SafeCharPointerReader(input.c_str(), input.length());
-}
-#endif
-
-}  // namespace ARDUINOJSON_NAMESPACE

+ 55 - 0
src/ArduinoJson/Deserialization/Reader.hpp

@@ -0,0 +1,55 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2019
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Namespace.hpp>
+
+#include <stdlib.h>  // for size_t
+
+namespace ARDUINOJSON_NAMESPACE {
+
+// The default reader is a simple wrapper for Readers that are not copiable
+template <typename TSource, typename Enable = void>
+struct Reader {
+ public:
+  Reader(TSource& source) : _source(&source) {}
+
+  int read() {
+    return _source->read();
+  }
+
+  size_t readBytes(char* buffer, size_t length) {
+    return _source->readBytes(buffer, length);
+  }
+
+ private:
+  TSource* _source;
+};
+
+template <typename TSource, typename Enable = void>
+struct BoundedReader {
+  // no default implementation because we need to pass the size to the
+  // constructor
+};
+}  // namespace ARDUINOJSON_NAMESPACE
+
+#include <ArduinoJson/Deserialization/Readers/IteratorReader.hpp>
+#include <ArduinoJson/Deserialization/Readers/RamReader.hpp>
+
+#if ARDUINOJSON_ENABLE_ARDUINO_STREAM
+#include <ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp>
+#endif
+
+#if ARDUINOJSON_ENABLE_ARDUINO_STRING
+#include <ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp>
+#endif
+
+#if ARDUINOJSON_ENABLE_PROGMEM
+#include <ArduinoJson/Deserialization/Readers/FlashReader.hpp>
+#endif
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+#include <ArduinoJson/Deserialization/Readers/StdStreamReader.hpp>
+#endif

+ 4 - 11
src/ArduinoJson/Deserialization/ArduinoStreamReader.hpp → src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp

@@ -4,19 +4,17 @@
 
 #pragma once
 
-#include <ArduinoJson/Namespace.hpp>
-
-#if ARDUINOJSON_ENABLE_ARDUINO_STREAM
-
 #include <Stream.h>
 
 namespace ARDUINOJSON_NAMESPACE {
 
-struct ArduinoStreamReader {
+template <typename TSource>
+struct Reader<TSource,
+              typename enable_if<is_base_of<Stream, TSource>::value>::type> {
   Stream& _stream;
 
  public:
-  explicit ArduinoStreamReader(Stream& stream) : _stream(stream) {}
+  explicit Reader(Stream& stream) : _stream(stream) {}
 
   int read() {
     // don't use _stream.read() as it ignores the timeout
@@ -29,9 +27,4 @@ struct ArduinoStreamReader {
   }
 };
 
-inline ArduinoStreamReader makeReader(Stream& input) {
-  return ArduinoStreamReader(input);
-}
 }  // namespace ARDUINOJSON_NAMESPACE
-
-#endif

+ 17 - 0
src/ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp

@@ -0,0 +1,17 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2019
+// MIT License
+
+#pragma once
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename TSource>
+struct Reader<TSource,
+              typename enable_if<is_base_of< ::String, TSource>::value>::type>
+    : BoundedReader<const char*> {
+  explicit Reader(const ::String& s)
+      : BoundedReader<const char*>(s.c_str(), s.length()) {}
+};
+
+}  // namespace ARDUINOJSON_NAMESPACE

+ 7 - 19
src/ArduinoJson/Deserialization/FlashStringReader.hpp → src/ArduinoJson/Deserialization/Readers/FlashReader.hpp

@@ -4,16 +4,14 @@
 
 #pragma once
 
-#include <ArduinoJson/Namespace.hpp>
-
-#if ARDUINOJSON_ENABLE_PROGMEM
-
 namespace ARDUINOJSON_NAMESPACE {
-class UnsafeFlashStringReader {
+
+template <>
+struct Reader<const __FlashStringHelper*, void> {
   const char* _ptr;
 
  public:
-  explicit UnsafeFlashStringReader(const __FlashStringHelper* ptr)
+  explicit Reader(const __FlashStringHelper* ptr)
       : _ptr(reinterpret_cast<const char*>(ptr)) {}
 
   int read() {
@@ -27,12 +25,13 @@ class UnsafeFlashStringReader {
   }
 };
 
-class SafeFlashStringReader {
+template <>
+struct BoundedReader<const __FlashStringHelper*, void> {
   const char* _ptr;
   const char* _end;
 
  public:
-  explicit SafeFlashStringReader(const __FlashStringHelper* ptr, size_t size)
+  explicit BoundedReader(const __FlashStringHelper* ptr, size_t size)
       : _ptr(reinterpret_cast<const char*>(ptr)), _end(_ptr + size) {}
 
   int read() {
@@ -50,15 +49,4 @@ class SafeFlashStringReader {
     return length;
   }
 };
-
-inline UnsafeFlashStringReader makeReader(const __FlashStringHelper* input) {
-  return UnsafeFlashStringReader(input);
-}
-
-inline SafeFlashStringReader makeReader(const __FlashStringHelper* input,
-                                        size_t size) {
-  return SafeFlashStringReader(input, size);
-}
 }  // namespace ARDUINOJSON_NAMESPACE
-
-#endif

+ 12 - 8
src/ArduinoJson/Deserialization/IteratorReader.hpp → src/ArduinoJson/Deserialization/Readers/IteratorReader.hpp

@@ -4,8 +4,6 @@
 
 #pragma once
 
-#include <ArduinoJson/Namespace.hpp>
-
 namespace ARDUINOJSON_NAMESPACE {
 
 template <typename TIterator>
@@ -30,10 +28,16 @@ class IteratorReader {
   }
 };
 
-template <typename TInput>
-inline IteratorReader<typename TInput::const_iterator> makeReader(
-    const TInput& input) {
-  return IteratorReader<typename TInput::const_iterator>(input.begin(),
-                                                         input.end());
-}
+template <typename T>
+struct void_ {
+  typedef void type;
+};
+
+template <typename TSource>
+struct Reader<TSource, typename void_<typename TSource::const_iterator>::type>
+    : IteratorReader<typename TSource::const_iterator> {
+  explicit Reader(const TSource& source)
+      : IteratorReader<typename TSource::const_iterator>(source.begin(),
+                                                         source.end()) {}
+};
 }  // namespace ARDUINOJSON_NAMESPACE

+ 50 - 0
src/ArduinoJson/Deserialization/Readers/RamReader.hpp

@@ -0,0 +1,50 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2019
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Polyfills/type_traits.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename T>
+struct IsCharOrVoid {
+  static const bool value =
+      is_same<T, void>::value || is_same<T, char>::value ||
+      is_same<T, unsigned char>::value || is_same<T, signed char>::value;
+};
+
+template <typename T>
+struct IsCharOrVoid<const T> : IsCharOrVoid<T> {};
+
+template <typename TSource>
+struct Reader<TSource*,
+              typename enable_if<IsCharOrVoid<TSource>::value>::type> {
+  const char* _ptr;
+
+ public:
+  explicit Reader(const void* ptr)
+      : _ptr(ptr ? reinterpret_cast<const char*>(ptr) : "") {}
+
+  int read() {
+    return static_cast<unsigned char>(*_ptr++);
+  }
+
+  size_t readBytes(char* buffer, size_t length) {
+    for (size_t i = 0; i < length; i++) buffer[i] = *_ptr++;
+    return length;
+  }
+};
+
+template <typename TSource>
+struct BoundedReader<TSource*,
+                     typename enable_if<IsCharOrVoid<TSource>::value>::type>
+    : public IteratorReader<const char*> {
+ public:
+  explicit BoundedReader(const void* ptr, size_t len)
+      : IteratorReader<const char*>(reinterpret_cast<const char*>(ptr),
+                                    reinterpret_cast<const char*>(ptr) + len) {}
+};
+
+}  // namespace ARDUINOJSON_NAMESPACE

+ 29 - 0
src/ArduinoJson/Deserialization/Readers/StdStreamReader.hpp

@@ -0,0 +1,29 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2019
+// MIT License
+
+#pragma once
+
+#include <istream>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename TSource>
+struct Reader<TSource, typename enable_if<
+                           is_base_of<std::istream, TSource>::value>::type> {
+ public:
+  explicit Reader(std::istream& stream) : _stream(&stream) {}
+
+  int read() {
+    return _stream->get();
+  }
+
+  size_t readBytes(char* buffer, size_t length) {
+    _stream->read(buffer, static_cast<std::streamsize>(length));
+    return static_cast<size_t>(_stream->gcount());
+  }
+
+ private:
+  std::istream* _stream;
+};
+}  // namespace ARDUINOJSON_NAMESPACE

+ 0 - 41
src/ArduinoJson/Deserialization/StdStreamReader.hpp

@@ -1,41 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2019
-// MIT License
-
-#pragma once
-
-#include <ArduinoJson/Namespace.hpp>
-
-#if ARDUINOJSON_ENABLE_STD_STREAM
-
-#include <istream>
-
-namespace ARDUINOJSON_NAMESPACE {
-
-class StdStreamReader {
-  std::istream& _stream;
-  char _current;
-
- public:
-  explicit StdStreamReader(std::istream& stream)
-      : _stream(stream), _current(0) {}
-
-  int read() {
-    return _stream.get();
-  }
-
-  size_t readBytes(char* buffer, size_t length) {
-    _stream.read(buffer, static_cast<std::streamsize>(length));
-    return static_cast<size_t>(_stream.gcount());
-  }
-
- private:
-  StdStreamReader& operator=(const StdStreamReader&);  // Visual Studio C4512
-};
-
-inline StdStreamReader makeReader(std::istream& input) {
-  return StdStreamReader(input);
-}
-}  // namespace ARDUINOJSON_NAMESPACE
-
-#endif

+ 10 - 21
src/ArduinoJson/Deserialization/deserialize.hpp

@@ -4,13 +4,9 @@
 
 #pragma once
 
-#include <ArduinoJson/Deserialization/ArduinoStreamReader.hpp>
-#include <ArduinoJson/Deserialization/CharPointerReader.hpp>
 #include <ArduinoJson/Deserialization/DeserializationError.hpp>
-#include <ArduinoJson/Deserialization/FlashStringReader.hpp>
-#include <ArduinoJson/Deserialization/IteratorReader.hpp>
 #include <ArduinoJson/Deserialization/NestingLimit.hpp>
-#include <ArduinoJson/Deserialization/StdStreamReader.hpp>
+#include <ArduinoJson/Deserialization/Reader.hpp>
 #include <ArduinoJson/StringStorage/StringStorage.hpp>
 
 namespace ARDUINOJSON_NAMESPACE {
@@ -25,26 +21,17 @@ TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool &pool,
 
 // deserialize(JsonDocument&, const std::string&);
 // deserialize(JsonDocument&, const String&);
+// deserialize(JsonDocument&, char*);
+// deserialize(JsonDocument&, const char*);
+// deserialize(JsonDocument&, const __FlashStringHelper*);
 template <template <typename, typename> class TDeserializer, typename TString>
 typename enable_if<!is_array<TString>::value, DeserializationError>::type
 deserialize(JsonDocument &doc, const TString &input,
             NestingLimit nestingLimit) {
+  Reader<TString> reader(input);
   doc.clear();
   return makeDeserializer<TDeserializer>(
-             doc.memoryPool(), makeReader(input),
-             makeStringStorage(doc.memoryPool(), input), nestingLimit.value)
-      .parse(doc.data());
-}
-//
-// deserialize(JsonDocument&, char*);
-// deserialize(JsonDocument&, const char*);
-// deserialize(JsonDocument&, const __FlashStringHelper*);
-template <template <typename, typename> class TDeserializer, typename TChar>
-DeserializationError deserialize(JsonDocument &doc, TChar *input,
-                                 NestingLimit nestingLimit) {
-  doc.clear();
-  return makeDeserializer<TDeserializer>(
-             doc.memoryPool(), makeReader(input),
+             doc.memoryPool(), reader,
              makeStringStorage(doc.memoryPool(), input), nestingLimit.value)
       .parse(doc.data());
 }
@@ -55,9 +42,10 @@ DeserializationError deserialize(JsonDocument &doc, TChar *input,
 template <template <typename, typename> class TDeserializer, typename TChar>
 DeserializationError deserialize(JsonDocument &doc, TChar *input,
                                  size_t inputSize, NestingLimit nestingLimit) {
+  BoundedReader<TChar *> reader(input, inputSize);
   doc.clear();
   return makeDeserializer<TDeserializer>(
-             doc.memoryPool(), makeReader(input, inputSize),
+             doc.memoryPool(), reader,
              makeStringStorage(doc.memoryPool(), input), nestingLimit.value)
       .parse(doc.data());
 }
@@ -67,9 +55,10 @@ DeserializationError deserialize(JsonDocument &doc, TChar *input,
 template <template <typename, typename> class TDeserializer, typename TStream>
 DeserializationError deserialize(JsonDocument &doc, TStream &input,
                                  NestingLimit nestingLimit) {
+  Reader<TStream> reader(input);
   doc.clear();
   return makeDeserializer<TDeserializer>(
-             doc.memoryPool(), makeReader(input),
+             doc.memoryPool(), reader,
              makeStringStorage(doc.memoryPool(), input), nestingLimit.value)
       .parse(doc.data());
 }