mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-29 10:17:39 +02:00
Replace ConverterNeedsWriteableRef
with function_traits
This commit is contained in:
@ -140,15 +140,3 @@ TEST_CASE("Custom converter with specialization") {
|
|||||||
REQUIRE(doc["value"]["imag"] == 3);
|
REQUIRE(doc["value"]["imag"] == 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("ConverterNeedsWriteableRef") {
|
|
||||||
using namespace ArduinoJson::detail;
|
|
||||||
CHECK(ConverterNeedsWriteableRef<int>::value == false);
|
|
||||||
CHECK(ConverterNeedsWriteableRef<float>::value == false);
|
|
||||||
CHECK(ConverterNeedsWriteableRef<JsonVariant>::value == true);
|
|
||||||
CHECK(ConverterNeedsWriteableRef<JsonVariantConst>::value == false);
|
|
||||||
CHECK(ConverterNeedsWriteableRef<JsonObject>::value == true);
|
|
||||||
CHECK(ConverterNeedsWriteableRef<JsonObjectConst>::value == false);
|
|
||||||
CHECK(ConverterNeedsWriteableRef<JsonArray>::value == true);
|
|
||||||
CHECK(ConverterNeedsWriteableRef<JsonArrayConst>::value == false);
|
|
||||||
}
|
|
||||||
|
@ -17,3 +17,24 @@ TEST_CASE("JsonVariantConst::as<T>()") {
|
|||||||
REQUIRE(var.as<const char*>() == std::string("hello"));
|
REQUIRE(var.as<const char*>() == std::string("hello"));
|
||||||
REQUIRE(var.as<std::string>() == std::string("hello"));
|
REQUIRE(var.as<std::string>() == std::string("hello"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Invalid conversions") {
|
||||||
|
using namespace ArduinoJson::detail;
|
||||||
|
|
||||||
|
JsonVariantConst variant;
|
||||||
|
|
||||||
|
CHECK(is_same<decltype(variant.as<int>()), int>::value);
|
||||||
|
CHECK(is_same<decltype(variant.as<float>()), float>::value);
|
||||||
|
CHECK(is_same<decltype(variant.as<JsonVariantConst>()),
|
||||||
|
JsonVariantConst>::value);
|
||||||
|
CHECK(
|
||||||
|
is_same<decltype(variant.as<JsonObjectConst>()), JsonObjectConst>::value);
|
||||||
|
CHECK(is_same<decltype(variant.as<JsonArrayConst>()), JsonArrayConst>::value);
|
||||||
|
|
||||||
|
CHECK(is_same<decltype(variant.as<JsonVariant>()),
|
||||||
|
InvalidConversion<JsonVariantConst, JsonVariant>>::value);
|
||||||
|
CHECK(is_same<decltype(variant.as<JsonObject>()),
|
||||||
|
InvalidConversion<JsonVariantConst, JsonObject>>::value);
|
||||||
|
CHECK(is_same<decltype(variant.as<JsonArray>()),
|
||||||
|
InvalidConversion<JsonVariantConst, JsonArray>>::value);
|
||||||
|
}
|
||||||
|
@ -58,5 +58,10 @@
|
|||||||
// issue #1914
|
// issue #1914
|
||||||
#define V7 7
|
#define V7 7
|
||||||
|
|
||||||
|
// STM32, Mbed, Particle
|
||||||
|
#define A0 16
|
||||||
|
#define A1 17
|
||||||
|
#define A2 18
|
||||||
|
|
||||||
// catch.hpp mutes several warnings, this file also allows to detect them
|
// catch.hpp mutes several warnings, this file also allows to detect them
|
||||||
#include "ArduinoJson.h"
|
#include "ArduinoJson.h"
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "type_traits/conditional.hpp"
|
#include "type_traits/conditional.hpp"
|
||||||
#include "type_traits/enable_if.hpp"
|
#include "type_traits/enable_if.hpp"
|
||||||
|
#include "type_traits/function_traits.hpp"
|
||||||
#include "type_traits/integral_constant.hpp"
|
#include "type_traits/integral_constant.hpp"
|
||||||
#include "type_traits/is_array.hpp"
|
#include "type_traits/is_array.hpp"
|
||||||
#include "type_traits/is_base_of.hpp"
|
#include "type_traits/is_base_of.hpp"
|
||||||
|
27
src/ArduinoJson/Polyfills/type_traits/function_traits.hpp
Normal file
27
src/ArduinoJson/Polyfills/type_traits/function_traits.hpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2024, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename Sig>
|
||||||
|
struct function_traits;
|
||||||
|
|
||||||
|
template <typename ReturnType, typename Arg1>
|
||||||
|
struct function_traits<ReturnType (*)(Arg1)> {
|
||||||
|
using return_type = ReturnType;
|
||||||
|
using arg1_type = Arg1;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ReturnType, typename Arg1, typename Arg2>
|
||||||
|
struct function_traits<ReturnType (*)(Arg1, Arg2)> {
|
||||||
|
using return_type = ReturnType;
|
||||||
|
using arg1_type = Arg1;
|
||||||
|
using arg2_type = Arg2;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -20,7 +20,4 @@ template <typename T1, typename T2>
|
|||||||
class InvalidConversion; // Error here? See https://arduinojson.org/v7/invalid-conversion/
|
class InvalidConversion; // Error here? See https://arduinojson.org/v7/invalid-conversion/
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct ConverterNeedsWriteableRef;
|
|
||||||
|
|
||||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
@ -305,19 +305,6 @@ inline bool canConvertFromJson(JsonVariantConst src, const std::string_view&) {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template <typename T>
|
|
||||||
struct ConverterNeedsWriteableRef {
|
|
||||||
protected: // <- to avoid GCC's "all member functions in class are private"
|
|
||||||
static int probe(T (*f)(ArduinoJson::JsonVariant));
|
|
||||||
static char probe(T (*f)(ArduinoJson::JsonVariantConst));
|
|
||||||
|
|
||||||
public:
|
|
||||||
static const bool value =
|
|
||||||
sizeof(probe(Converter<T>::fromJson)) == sizeof(int);
|
|
||||||
};
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct Converter<JsonArrayConst> : private detail::VariantAttorney {
|
struct Converter<JsonArrayConst> : private detail::VariantAttorney {
|
||||||
static void toJson(JsonArrayConst src, JsonVariant dst) {
|
static void toJson(JsonArrayConst src, JsonVariant dst) {
|
||||||
@ -354,13 +341,6 @@ struct Converter<JsonArray> : private detail::VariantAttorney {
|
|||||||
return JsonArray(data != 0 ? data->asArray() : 0, resources);
|
return JsonArray(data != 0 ? data->asArray() : 0, resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
static detail::InvalidConversion<JsonVariantConst, JsonArray> fromJson(
|
|
||||||
JsonVariantConst);
|
|
||||||
|
|
||||||
static bool checkJson(JsonVariantConst) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool checkJson(JsonVariant src) {
|
static bool checkJson(JsonVariant src) {
|
||||||
auto data = getData(src);
|
auto data = getData(src);
|
||||||
return data && data->isArray();
|
return data && data->isArray();
|
||||||
@ -403,13 +383,6 @@ struct Converter<JsonObject> : private detail::VariantAttorney {
|
|||||||
return JsonObject(data != 0 ? data->asObject() : 0, resources);
|
return JsonObject(data != 0 ? data->asObject() : 0, resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
static detail::InvalidConversion<JsonVariantConst, JsonObject> fromJson(
|
|
||||||
JsonVariantConst);
|
|
||||||
|
|
||||||
static bool checkJson(JsonVariantConst) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool checkJson(JsonVariant src) {
|
static bool checkJson(JsonVariant src) {
|
||||||
auto data = getData(src);
|
auto data = getData(src);
|
||||||
return data && data->isObject();
|
return data && data->isObject();
|
||||||
|
@ -53,17 +53,10 @@ struct Converter<JsonVariant> : private detail::VariantAttorney {
|
|||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
static detail::InvalidConversion<JsonVariantConst, JsonVariant> fromJson(
|
|
||||||
JsonVariantConst);
|
|
||||||
|
|
||||||
static bool checkJson(JsonVariant src) {
|
static bool checkJson(JsonVariant src) {
|
||||||
auto data = getData(src);
|
auto data = getData(src);
|
||||||
return !!data;
|
return !!data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool checkJson(JsonVariantConst) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -27,6 +27,12 @@ class JsonVariantConst : public detail::VariantTag,
|
|||||||
public detail::VariantOperators<JsonVariantConst> {
|
public detail::VariantOperators<JsonVariantConst> {
|
||||||
friend class detail::VariantAttorney;
|
friend class detail::VariantAttorney;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using ConversionSupported =
|
||||||
|
detail::is_same<typename detail::function_traits<
|
||||||
|
decltype(&Converter<T>::fromJson)>::arg1_type,
|
||||||
|
JsonVariantConst>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Creates an unbound reference.
|
// Creates an unbound reference.
|
||||||
JsonVariantConst() : data_(nullptr), resources_(nullptr) {}
|
JsonVariantConst() : data_(nullptr), resources_(nullptr) {}
|
||||||
@ -62,23 +68,35 @@ class JsonVariantConst : public detail::VariantTag,
|
|||||||
// Casts the value to the specified type.
|
// Casts the value to the specified type.
|
||||||
// https://arduinojson.org/v7/api/jsonvariantconst/as/
|
// https://arduinojson.org/v7/api/jsonvariantconst/as/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename detail::enable_if<!detail::is_same<T, char*>::value &&
|
typename detail::enable_if<ConversionSupported<T>::value, T>::type as()
|
||||||
!detail::is_same<T, char>::value,
|
const {
|
||||||
T>::type
|
|
||||||
as() const {
|
|
||||||
return Converter<T>::fromJson(*this);
|
return Converter<T>::fromJson(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Casts the value to the specified type.
|
||||||
|
// https://arduinojson.org/v7/api/jsonvariantconst/as/
|
||||||
|
template <typename T>
|
||||||
|
typename detail::enable_if<
|
||||||
|
!ConversionSupported<T>::value,
|
||||||
|
detail::InvalidConversion<JsonVariantConst, T>>::type
|
||||||
|
as() const;
|
||||||
|
|
||||||
// Returns true if the value is of the specified type.
|
// Returns true if the value is of the specified type.
|
||||||
// https://arduinojson.org/v7/api/jsonvariantconst/is/
|
// https://arduinojson.org/v7/api/jsonvariantconst/is/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename detail::enable_if<!detail::is_same<T, char*>::value &&
|
typename detail::enable_if<ConversionSupported<T>::value, bool>::type is()
|
||||||
!detail::is_same<T, char>::value,
|
const {
|
||||||
bool>::type
|
|
||||||
is() const {
|
|
||||||
return Converter<T>::checkJson(*this);
|
return Converter<T>::checkJson(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always returns false for the unsupported types.
|
||||||
|
// https://arduinojson.org/v7/api/jsonvariantconst/is/
|
||||||
|
template <typename T>
|
||||||
|
typename detail::enable_if<!ConversionSupported<T>::value, bool>::type is()
|
||||||
|
const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
operator T() const {
|
operator T() const {
|
||||||
return as<T>();
|
return as<T>();
|
||||||
|
@ -46,16 +46,7 @@ class VariantRefBase : public VariantTag {
|
|||||||
// Casts the value to the specified type.
|
// Casts the value to the specified type.
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/as/
|
// https://arduinojson.org/v7/api/jsonvariant/as/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
T as() const;
|
||||||
typename enable_if<!ConverterNeedsWriteableRef<T>::value, T>::type as()
|
|
||||||
const {
|
|
||||||
return Converter<T>::fromJson(getVariantConst());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Casts the value to the specified type.
|
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/as/
|
|
||||||
template <typename T>
|
|
||||||
typename enable_if<ConverterNeedsWriteableRef<T>::value, T>::type as() const;
|
|
||||||
|
|
||||||
template <typename T,
|
template <typename T,
|
||||||
typename = typename enable_if<!is_same<T, TDerived>::value>::type>
|
typename = typename enable_if<!is_same<T, TDerived>::value>::type>
|
||||||
@ -83,18 +74,7 @@ class VariantRefBase : public VariantTag {
|
|||||||
// Returns true if the value is of the specified type.
|
// Returns true if the value is of the specified type.
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/is/
|
// https://arduinojson.org/v7/api/jsonvariant/is/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE
|
FORCE_INLINE bool is() const;
|
||||||
typename enable_if<ConverterNeedsWriteableRef<T>::value, bool>::type
|
|
||||||
is() const;
|
|
||||||
|
|
||||||
// Returns true if the value is of the specified type.
|
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/is/
|
|
||||||
template <typename T>
|
|
||||||
FORCE_INLINE
|
|
||||||
typename enable_if<!ConverterNeedsWriteableRef<T>::value, bool>::type
|
|
||||||
is() const {
|
|
||||||
return Converter<T>::checkJson(getVariantConst());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copies the specified value.
|
// Copies the specified value.
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/set/
|
// https://arduinojson.org/v7/api/jsonvariant/set/
|
||||||
@ -298,6 +278,18 @@ class VariantRefBase : public VariantTag {
|
|||||||
return ArduinoJson::JsonVariantConst(getData(), getResourceManager());
|
return ArduinoJson::JsonVariantConst(getData(), getResourceManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE typename enable_if<is_same<T, JsonVariantConst>::value, T>::type
|
||||||
|
getVariant() const {
|
||||||
|
return getVariantConst();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE typename enable_if<is_same<T, JsonVariant>::value, T>::type
|
||||||
|
getVariant() const {
|
||||||
|
return getVariant();
|
||||||
|
}
|
||||||
|
|
||||||
ArduinoJson::JsonVariant getOrCreateVariant() const;
|
ArduinoJson::JsonVariant getOrCreateVariant() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,9 +17,10 @@ inline JsonVariant VariantRefBase<TDerived>::add() const {
|
|||||||
|
|
||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline typename enable_if<ConverterNeedsWriteableRef<T>::value, T>::type
|
inline T VariantRefBase<TDerived>::as() const {
|
||||||
VariantRefBase<TDerived>::as() const {
|
using variant_type = // JsonVariantConst or JsonVariant?
|
||||||
return Converter<T>::fromJson(getVariant());
|
typename function_traits<decltype(&Converter<T>::fromJson)>::arg1_type;
|
||||||
|
return Converter<T>::fromJson(getVariant<variant_type>());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
@ -109,9 +110,10 @@ inline JsonVariant VariantRefBase<TDerived>::getOrCreateVariant() const {
|
|||||||
|
|
||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline typename enable_if<ConverterNeedsWriteableRef<T>::value, bool>::type
|
inline bool VariantRefBase<TDerived>::is() const {
|
||||||
VariantRefBase<TDerived>::is() const {
|
using variant_type = // JsonVariantConst or JsonVariant?
|
||||||
return Converter<T>::checkJson(getVariant());
|
typename function_traits<decltype(&Converter<T>::checkJson)>::arg1_type;
|
||||||
|
return Converter<T>::checkJson(getVariant<variant_type>());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
|
Reference in New Issue
Block a user