forked from bblanchon/ArduinoJson
Add deserializeXxx(JsonVariant, ...)
(resolves #1226)
This commit is contained in:
@ -24,3 +24,4 @@ HEAD
|
||||
* Show a link to the documentation when user passes an unsupported input type
|
||||
* Remove `JsonDocument::memoryUsage()`
|
||||
* Remove `JsonDocument::garbageCollect()`
|
||||
* Add `deserializeJson(JsonVariant, ...)` and `deserializeMsgPack(JsonVariant, ...)` (#1226)
|
||||
|
@ -5,6 +5,7 @@
|
||||
add_executable(JsonDeserializerTests
|
||||
array.cpp
|
||||
DeserializationError.cpp
|
||||
destination_types.cpp
|
||||
errors.cpp
|
||||
filter.cpp
|
||||
input_types.cpp
|
||||
|
104
extras/tests/JsonDeserializer/destination_types.cpp
Normal file
104
extras/tests/JsonDeserializer/destination_types.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
|
||||
TEST_CASE("deserializeJson(JsonDocument&)") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc.add(std::string("hello"));
|
||||
spy.clearLog();
|
||||
|
||||
auto err = deserializeJson(doc, "[42]");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "[42]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Deallocate(sizeofPool()),
|
||||
Deallocate(sizeofString("hello")),
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
TEST_CASE("deserializeJson(JsonVariant)") {
|
||||
SECTION("variant is bound") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc.add(std::string("hello"));
|
||||
spy.clearLog();
|
||||
|
||||
JsonVariant variant = doc[0];
|
||||
|
||||
auto err = deserializeJson(variant, "[42]");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "[[42]]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Deallocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("variant is unbound") {
|
||||
JsonVariant variant;
|
||||
|
||||
auto err = deserializeJson(variant, "[42]");
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("deserializeJson(ElementProxy)") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc.add(std::string("hello"));
|
||||
spy.clearLog();
|
||||
|
||||
SECTION("element already exists") {
|
||||
auto err = deserializeJson(doc[0], "[42]");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "[[42]]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Deallocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("element must be created exists") {
|
||||
auto err = deserializeJson(doc[1], "[42]");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "[\"hello\",[42]]");
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("deserializeJson(MemberProxy)") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc[std::string("hello")] = std::string("world");
|
||||
spy.clearLog();
|
||||
|
||||
SECTION("member already exists") {
|
||||
auto err = deserializeJson(doc["hello"], "[42]");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[42]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Deallocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("member must be created exists") {
|
||||
auto err = deserializeJson(doc["value"], "[42]");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\",\"value\":[42]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ add_executable(MsgPackDeserializerTests
|
||||
deserializeArray.cpp
|
||||
deserializeObject.cpp
|
||||
deserializeVariant.cpp
|
||||
destination_types.cpp
|
||||
doubleToFloat.cpp
|
||||
errors.cpp
|
||||
filter.cpp
|
||||
|
104
extras/tests/MsgPackDeserializer/destination_types.cpp
Normal file
104
extras/tests/MsgPackDeserializer/destination_types.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
|
||||
TEST_CASE("deserializeMsgPack(JsonDocument&)") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc.add(std::string("hello"));
|
||||
spy.clearLog();
|
||||
|
||||
auto err = deserializeMsgPack(doc, "\x91\x2A");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "[42]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Deallocate(sizeofPool()),
|
||||
Deallocate(sizeofString("hello")),
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
TEST_CASE("deserializeMsgPack(JsonVariant)") {
|
||||
SECTION("variant is bound") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc.add(std::string("hello"));
|
||||
spy.clearLog();
|
||||
|
||||
JsonVariant variant = doc[0];
|
||||
|
||||
auto err = deserializeMsgPack(variant, "\x91\x2A");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "[[42]]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Deallocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("variant is unbound") {
|
||||
JsonVariant variant;
|
||||
|
||||
auto err = deserializeMsgPack(variant, "\x91\x2A");
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("deserializeMsgPack(ElementProxy)") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc.add(std::string("hello"));
|
||||
spy.clearLog();
|
||||
|
||||
SECTION("element already exists") {
|
||||
auto err = deserializeMsgPack(doc[0], "\x91\x2A");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "[[42]]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Deallocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("element must be created exists") {
|
||||
auto err = deserializeMsgPack(doc[1], "\x91\x2A");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "[\"hello\",[42]]");
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("deserializeMsgPack(MemberProxy)") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc[std::string("hello")] = std::string("world");
|
||||
spy.clearLog();
|
||||
|
||||
SECTION("member already exists") {
|
||||
auto err = deserializeMsgPack(doc["hello"], "\x91\x2A");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[42]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Deallocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("member must be created exists") {
|
||||
auto err = deserializeMsgPack(doc["value"], "\x91\x2A");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\",\"value\":[42]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
}
|
@ -22,40 +22,37 @@ struct first_or_void<T, Rest...> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <template <typename> class TDeserializer, typename TReader>
|
||||
TDeserializer<TReader> makeDeserializer(ResourceManager* resources,
|
||||
TReader reader) {
|
||||
ARDUINOJSON_ASSERT(resources != 0);
|
||||
return TDeserializer<TReader>(resources, reader);
|
||||
template <template <typename> class TDeserializer, typename TDestination,
|
||||
typename TReader, typename TOptions>
|
||||
DeserializationError doDeserialize(TDestination&& dst, TReader reader,
|
||||
TOptions options) {
|
||||
auto data = VariantAttorney::getOrCreateData(dst);
|
||||
if (!data)
|
||||
return DeserializationError::NoMemory;
|
||||
auto resources = VariantAttorney::getResourceManager(dst);
|
||||
dst.clear();
|
||||
return TDeserializer<TReader>(resources, reader)
|
||||
.parse(*data, options.filter, options.nestingLimit);
|
||||
}
|
||||
|
||||
template <template <typename> class TDeserializer, typename TStream,
|
||||
typename... Args,
|
||||
template <template <typename> class TDeserializer, typename TDestination,
|
||||
typename TStream, typename... Args,
|
||||
typename = typename enable_if< // issue #1897
|
||||
!is_integral<typename first_or_void<Args...>::type>::value>::type>
|
||||
DeserializationError deserialize(JsonDocument& doc, TStream&& input,
|
||||
DeserializationError deserialize(TDestination&& dst, TStream&& input,
|
||||
Args... args) {
|
||||
auto reader = makeReader(detail::forward<TStream>(input));
|
||||
auto data = VariantAttorney::getData(doc);
|
||||
auto resources = VariantAttorney::getResourceManager(doc);
|
||||
auto options = makeDeserializationOptions(args...);
|
||||
doc.clear();
|
||||
return makeDeserializer<TDeserializer>(resources, reader)
|
||||
.parse(*data, options.filter, options.nestingLimit);
|
||||
return doDeserialize<TDeserializer>(
|
||||
dst, makeReader(detail::forward<TStream>(input)),
|
||||
makeDeserializationOptions(args...));
|
||||
}
|
||||
|
||||
template <template <typename> class TDeserializer, typename TChar,
|
||||
typename Size, typename... Args,
|
||||
template <template <typename> class TDeserializer, typename TDestination,
|
||||
typename TChar, typename Size, typename... Args,
|
||||
typename = typename enable_if<is_integral<Size>::value>::type>
|
||||
DeserializationError deserialize(JsonDocument& doc, TChar* input,
|
||||
DeserializationError deserialize(TDestination&& dst, TChar* input,
|
||||
Size inputSize, Args... args) {
|
||||
auto reader = makeReader(input, size_t(inputSize));
|
||||
auto data = VariantAttorney::getData(doc);
|
||||
auto resources = VariantAttorney::getResourceManager(doc);
|
||||
auto options = makeDeserializationOptions(args...);
|
||||
doc.clear();
|
||||
return makeDeserializer<TDeserializer>(resources, reader)
|
||||
.parse(*data, options.filter, options.nestingLimit);
|
||||
return doDeserialize<TDeserializer>(dst, makeReader(input, size_t(inputSize)),
|
||||
makeDeserializationOptions(args...));
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -670,20 +670,21 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v6/api/json/deserializejson/
|
||||
template <typename... Args>
|
||||
DeserializationError deserializeJson(JsonDocument& doc, Args&&... args) {
|
||||
template <typename TDestination, typename... Args>
|
||||
DeserializationError deserializeJson(TDestination&& dst, Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<JsonDeserializer>(doc, detail::forward<Args>(args)...);
|
||||
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
|
||||
detail::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v6/api/json/deserializejson/
|
||||
template <typename TChar, typename... Args>
|
||||
DeserializationError deserializeJson(JsonDocument& doc, TChar* input,
|
||||
template <typename TDestination, typename TChar, typename... Args>
|
||||
DeserializationError deserializeJson(TDestination&& dst, TChar* input,
|
||||
Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<JsonDeserializer>(doc, input,
|
||||
detail::forward<Args>(args)...);
|
||||
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
|
||||
input, detail::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
@ -560,19 +560,21 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
||||
template <typename... Args>
|
||||
DeserializationError deserializeMsgPack(JsonDocument& doc, Args&&... args) {
|
||||
template <typename TDestination, typename... Args>
|
||||
DeserializationError deserializeMsgPack(TDestination&& dst, Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<MsgPackDeserializer>(doc, detail::forward<Args>(args)...);
|
||||
return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
|
||||
detail::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
||||
template <typename TChar, typename... Args>
|
||||
DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input,
|
||||
template <typename TDestination, typename TChar, typename... Args>
|
||||
DeserializationError deserializeMsgPack(TDestination&& dst, TChar* input,
|
||||
Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<MsgPackDeserializer>(doc, input,
|
||||
return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
|
||||
input,
|
||||
detail::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user