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
|
* Show a link to the documentation when user passes an unsupported input type
|
||||||
* Remove `JsonDocument::memoryUsage()`
|
* Remove `JsonDocument::memoryUsage()`
|
||||||
* Remove `JsonDocument::garbageCollect()`
|
* Remove `JsonDocument::garbageCollect()`
|
||||||
|
* Add `deserializeJson(JsonVariant, ...)` and `deserializeMsgPack(JsonVariant, ...)` (#1226)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
add_executable(JsonDeserializerTests
|
add_executable(JsonDeserializerTests
|
||||||
array.cpp
|
array.cpp
|
||||||
DeserializationError.cpp
|
DeserializationError.cpp
|
||||||
|
destination_types.cpp
|
||||||
errors.cpp
|
errors.cpp
|
||||||
filter.cpp
|
filter.cpp
|
||||||
input_types.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
|
deserializeArray.cpp
|
||||||
deserializeObject.cpp
|
deserializeObject.cpp
|
||||||
deserializeVariant.cpp
|
deserializeVariant.cpp
|
||||||
|
destination_types.cpp
|
||||||
doubleToFloat.cpp
|
doubleToFloat.cpp
|
||||||
errors.cpp
|
errors.cpp
|
||||||
filter.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;
|
using type = T;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <template <typename> class TDeserializer, typename TReader>
|
template <template <typename> class TDeserializer, typename TDestination,
|
||||||
TDeserializer<TReader> makeDeserializer(ResourceManager* resources,
|
typename TReader, typename TOptions>
|
||||||
TReader reader) {
|
DeserializationError doDeserialize(TDestination&& dst, TReader reader,
|
||||||
ARDUINOJSON_ASSERT(resources != 0);
|
TOptions options) {
|
||||||
return TDeserializer<TReader>(resources, reader);
|
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,
|
template <template <typename> class TDeserializer, typename TDestination,
|
||||||
typename... Args,
|
typename TStream, typename... Args,
|
||||||
typename = typename enable_if< // issue #1897
|
typename = typename enable_if< // issue #1897
|
||||||
!is_integral<typename first_or_void<Args...>::type>::value>::type>
|
!is_integral<typename first_or_void<Args...>::type>::value>::type>
|
||||||
DeserializationError deserialize(JsonDocument& doc, TStream&& input,
|
DeserializationError deserialize(TDestination&& dst, TStream&& input,
|
||||||
Args... args) {
|
Args... args) {
|
||||||
auto reader = makeReader(detail::forward<TStream>(input));
|
return doDeserialize<TDeserializer>(
|
||||||
auto data = VariantAttorney::getData(doc);
|
dst, makeReader(detail::forward<TStream>(input)),
|
||||||
auto resources = VariantAttorney::getResourceManager(doc);
|
makeDeserializationOptions(args...));
|
||||||
auto options = makeDeserializationOptions(args...);
|
|
||||||
doc.clear();
|
|
||||||
return makeDeserializer<TDeserializer>(resources, reader)
|
|
||||||
.parse(*data, options.filter, options.nestingLimit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <template <typename> class TDeserializer, typename TChar,
|
template <template <typename> class TDeserializer, typename TDestination,
|
||||||
typename Size, typename... Args,
|
typename TChar, typename Size, typename... Args,
|
||||||
typename = typename enable_if<is_integral<Size>::value>::type>
|
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) {
|
Size inputSize, Args... args) {
|
||||||
auto reader = makeReader(input, size_t(inputSize));
|
return doDeserialize<TDeserializer>(dst, makeReader(input, size_t(inputSize)),
|
||||||
auto data = VariantAttorney::getData(doc);
|
makeDeserializationOptions(args...));
|
||||||
auto resources = VariantAttorney::getResourceManager(doc);
|
|
||||||
auto options = makeDeserializationOptions(args...);
|
|
||||||
doc.clear();
|
|
||||||
return makeDeserializer<TDeserializer>(resources, reader)
|
|
||||||
.parse(*data, options.filter, options.nestingLimit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
@ -670,20 +670,21 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
|||||||
|
|
||||||
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||||
// https://arduinojson.org/v6/api/json/deserializejson/
|
// https://arduinojson.org/v6/api/json/deserializejson/
|
||||||
template <typename... Args>
|
template <typename TDestination, typename... Args>
|
||||||
DeserializationError deserializeJson(JsonDocument& doc, Args&&... args) {
|
DeserializationError deserializeJson(TDestination&& dst, Args&&... args) {
|
||||||
using namespace detail;
|
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.
|
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||||
// https://arduinojson.org/v6/api/json/deserializejson/
|
// https://arduinojson.org/v6/api/json/deserializejson/
|
||||||
template <typename TChar, typename... Args>
|
template <typename TDestination, typename TChar, typename... Args>
|
||||||
DeserializationError deserializeJson(JsonDocument& doc, TChar* input,
|
DeserializationError deserializeJson(TDestination&& dst, TChar* input,
|
||||||
Args&&... args) {
|
Args&&... args) {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return deserialize<JsonDeserializer>(doc, input,
|
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
|
||||||
detail::forward<Args>(args)...);
|
input, detail::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||||
|
@ -560,19 +560,21 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
|||||||
|
|
||||||
// Parses a MessagePack input and puts the result in a JsonDocument.
|
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||||
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
||||||
template <typename... Args>
|
template <typename TDestination, typename... Args>
|
||||||
DeserializationError deserializeMsgPack(JsonDocument& doc, Args&&... args) {
|
DeserializationError deserializeMsgPack(TDestination&& dst, Args&&... args) {
|
||||||
using namespace detail;
|
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.
|
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||||
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
||||||
template <typename TChar, typename... Args>
|
template <typename TDestination, typename TChar, typename... Args>
|
||||||
DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input,
|
DeserializationError deserializeMsgPack(TDestination&& dst, TChar* input,
|
||||||
Args&&... args) {
|
Args&&... args) {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return deserialize<MsgPackDeserializer>(doc, input,
|
return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
|
||||||
|
input,
|
||||||
detail::forward<Args>(args)...);
|
detail::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user