Skip to content

Commit

Permalink
Added support for custom reader classes
Browse files Browse the repository at this point in the history
  • Loading branch information
bblanchon committed Oct 25, 2019
1 parent d4f819f commit 3a169df
Show file tree
Hide file tree
Showing 17 changed files with 261 additions and 189 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions extras/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ if(MSVC)
)
endif()

include_directories(Helpers)
add_subdirectory(ElementProxy)
add_subdirectory(IntegrationTests)
add_subdirectory(JsonArray)
Expand Down
26 changes: 26 additions & 0 deletions extras/tests/Helpers/CustomReader.hpp
Original file line number Diff line number Diff line change
@@ -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 changes: 13 additions & 0 deletions extras/tests/JsonDeserializer/input_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <catch.hpp>
#include <sstream>

#include "CustomReader.hpp"

TEST_CASE("deserializeJson(const std::string&)") {
DynamicJsonDocument doc(4096);

Expand Down Expand Up @@ -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);
}
26 changes: 13 additions & 13 deletions extras/tests/Misc/Readers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -48,17 +48,17 @@ 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);
REQUIRE(reader.read() == -1);
}

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);
Expand All @@ -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);
Expand All @@ -86,17 +86,17 @@ 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);
REQUIRE(reader.read() == 0x12);
}

SECTION("readBytes() all at once") {
UnsafeCharPointerReader reader("ABCD");
Reader<const char*> reader("ABCD");

char buffer[8] = "abcd";
REQUIRE(reader.readBytes(buffer, 3) == 3);
Expand All @@ -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);
Expand Down
20 changes: 10 additions & 10 deletions extras/tests/MixedConfiguration/enable_progmem_1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,19 +86,19 @@ 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);
REQUIRE(reader.read() == -1);
}

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);
Expand All @@ -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);
Expand All @@ -126,19 +126,19 @@ 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);
REQUIRE(reader.read() == 0x12);
}

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);
Expand All @@ -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);
Expand Down
13 changes: 13 additions & 0 deletions extras/tests/MsgPackDeserializer/input_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>

#include "CustomReader.hpp"

TEST_CASE("deserializeMsgPack(const std::string&)") {
DynamicJsonDocument doc(4096);

Expand Down Expand Up @@ -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");
}
65 changes: 0 additions & 65 deletions src/ArduinoJson/Deserialization/CharPointerReader.hpp

This file was deleted.

55 changes: 55 additions & 0 deletions src/ArduinoJson/Deserialization/Reader.hpp
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 3a169df

Please sign in to comment.