diff --git a/extras/tests/JsonVariant/converters.cpp b/extras/tests/JsonVariant/converters.cpp index 259c8ac4..545c4beb 100644 --- a/extras/tests/JsonVariant/converters.cpp +++ b/extras/tests/JsonVariant/converters.cpp @@ -140,15 +140,3 @@ TEST_CASE("Custom converter with specialization") { REQUIRE(doc["value"]["imag"] == 3); } } - -TEST_CASE("ConverterNeedsWriteableRef") { - using namespace ArduinoJson::detail; - CHECK(ConverterNeedsWriteableRef::value == false); - CHECK(ConverterNeedsWriteableRef::value == false); - CHECK(ConverterNeedsWriteableRef::value == true); - CHECK(ConverterNeedsWriteableRef::value == false); - CHECK(ConverterNeedsWriteableRef::value == true); - CHECK(ConverterNeedsWriteableRef::value == false); - CHECK(ConverterNeedsWriteableRef::value == true); - CHECK(ConverterNeedsWriteableRef::value == false); -} diff --git a/extras/tests/JsonVariantConst/as.cpp b/extras/tests/JsonVariantConst/as.cpp index 6b86f156..d8046746 100644 --- a/extras/tests/JsonVariantConst/as.cpp +++ b/extras/tests/JsonVariantConst/as.cpp @@ -17,3 +17,24 @@ TEST_CASE("JsonVariantConst::as()") { REQUIRE(var.as() == std::string("hello")); REQUIRE(var.as() == std::string("hello")); } + +TEST_CASE("Invalid conversions") { + using namespace ArduinoJson::detail; + + JsonVariantConst variant; + + CHECK(is_same()), int>::value); + CHECK(is_same()), float>::value); + CHECK(is_same()), + JsonVariantConst>::value); + CHECK( + is_same()), JsonObjectConst>::value); + CHECK(is_same()), JsonArrayConst>::value); + + CHECK(is_same()), + InvalidConversion>::value); + CHECK(is_same()), + InvalidConversion>::value); + CHECK(is_same()), + InvalidConversion>::value); +} diff --git a/extras/tests/Misc/conflicts.cpp b/extras/tests/Misc/conflicts.cpp index d265f340..5ce6823c 100644 --- a/extras/tests/Misc/conflicts.cpp +++ b/extras/tests/Misc/conflicts.cpp @@ -58,5 +58,10 @@ // issue #1914 #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 #include "ArduinoJson.h" diff --git a/src/ArduinoJson/Polyfills/type_traits.hpp b/src/ArduinoJson/Polyfills/type_traits.hpp index 4256685b..293f3618 100644 --- a/src/ArduinoJson/Polyfills/type_traits.hpp +++ b/src/ArduinoJson/Polyfills/type_traits.hpp @@ -6,6 +6,7 @@ #include "type_traits/conditional.hpp" #include "type_traits/enable_if.hpp" +#include "type_traits/function_traits.hpp" #include "type_traits/integral_constant.hpp" #include "type_traits/is_array.hpp" #include "type_traits/is_base_of.hpp" diff --git a/src/ArduinoJson/Polyfills/type_traits/function_traits.hpp b/src/ArduinoJson/Polyfills/type_traits/function_traits.hpp new file mode 100644 index 00000000..3b798734 --- /dev/null +++ b/src/ArduinoJson/Polyfills/type_traits/function_traits.hpp @@ -0,0 +1,27 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2024, Benoit BLANCHON +// MIT License + +#pragma once + +#include + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + +template +struct function_traits; + +template +struct function_traits { + using return_type = ReturnType; + using arg1_type = Arg1; +}; + +template +struct function_traits { + using return_type = ReturnType; + using arg1_type = Arg1; + using arg2_type = Arg2; +}; + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Variant/Converter.hpp b/src/ArduinoJson/Variant/Converter.hpp index 7f8de24b..0275655e 100644 --- a/src/ArduinoJson/Variant/Converter.hpp +++ b/src/ArduinoJson/Variant/Converter.hpp @@ -20,7 +20,4 @@ template class InvalidConversion; // Error here? See https://arduinojson.org/v7/invalid-conversion/ // clang-format on -template -struct ConverterNeedsWriteableRef; - ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Variant/ConverterImpl.hpp b/src/ArduinoJson/Variant/ConverterImpl.hpp index 8e35f72b..788fa240 100644 --- a/src/ArduinoJson/Variant/ConverterImpl.hpp +++ b/src/ArduinoJson/Variant/ConverterImpl.hpp @@ -305,19 +305,6 @@ inline bool canConvertFromJson(JsonVariantConst src, const std::string_view&) { #endif -namespace detail { -template -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::fromJson)) == sizeof(int); -}; -} // namespace detail - template <> struct Converter : private detail::VariantAttorney { static void toJson(JsonArrayConst src, JsonVariant dst) { @@ -354,13 +341,6 @@ struct Converter : private detail::VariantAttorney { return JsonArray(data != 0 ? data->asArray() : 0, resources); } - static detail::InvalidConversion fromJson( - JsonVariantConst); - - static bool checkJson(JsonVariantConst) { - return false; - } - static bool checkJson(JsonVariant src) { auto data = getData(src); return data && data->isArray(); @@ -403,13 +383,6 @@ struct Converter : private detail::VariantAttorney { return JsonObject(data != 0 ? data->asObject() : 0, resources); } - static detail::InvalidConversion fromJson( - JsonVariantConst); - - static bool checkJson(JsonVariantConst) { - return false; - } - static bool checkJson(JsonVariant src) { auto data = getData(src); return data && data->isObject(); diff --git a/src/ArduinoJson/Variant/JsonVariant.hpp b/src/ArduinoJson/Variant/JsonVariant.hpp index 5039c38a..25fb3f2f 100644 --- a/src/ArduinoJson/Variant/JsonVariant.hpp +++ b/src/ArduinoJson/Variant/JsonVariant.hpp @@ -53,17 +53,10 @@ struct Converter : private detail::VariantAttorney { return src; } - static detail::InvalidConversion fromJson( - JsonVariantConst); - static bool checkJson(JsonVariant src) { auto data = getData(src); return !!data; } - - static bool checkJson(JsonVariantConst) { - return false; - } }; template <> diff --git a/src/ArduinoJson/Variant/JsonVariantConst.hpp b/src/ArduinoJson/Variant/JsonVariantConst.hpp index ac8aafff..60ee6015 100644 --- a/src/ArduinoJson/Variant/JsonVariantConst.hpp +++ b/src/ArduinoJson/Variant/JsonVariantConst.hpp @@ -27,6 +27,12 @@ class JsonVariantConst : public detail::VariantTag, public detail::VariantOperators { friend class detail::VariantAttorney; + template + using ConversionSupported = + detail::is_same::fromJson)>::arg1_type, + JsonVariantConst>; + public: // Creates an unbound reference. JsonVariantConst() : data_(nullptr), resources_(nullptr) {} @@ -62,23 +68,35 @@ class JsonVariantConst : public detail::VariantTag, // Casts the value to the specified type. // https://arduinojson.org/v7/api/jsonvariantconst/as/ template - typename detail::enable_if::value && - !detail::is_same::value, - T>::type - as() const { + typename detail::enable_if::value, T>::type as() + const { return Converter::fromJson(*this); } + // Casts the value to the specified type. + // https://arduinojson.org/v7/api/jsonvariantconst/as/ + template + typename detail::enable_if< + !ConversionSupported::value, + detail::InvalidConversion>::type + as() const; + // Returns true if the value is of the specified type. // https://arduinojson.org/v7/api/jsonvariantconst/is/ template - typename detail::enable_if::value && - !detail::is_same::value, - bool>::type - is() const { + typename detail::enable_if::value, bool>::type is() + const { return Converter::checkJson(*this); } + // Always returns false for the unsupported types. + // https://arduinojson.org/v7/api/jsonvariantconst/is/ + template + typename detail::enable_if::value, bool>::type is() + const { + return false; + } + template operator T() const { return as(); diff --git a/src/ArduinoJson/Variant/VariantRefBase.hpp b/src/ArduinoJson/Variant/VariantRefBase.hpp index 9dc06e48..62271a08 100644 --- a/src/ArduinoJson/Variant/VariantRefBase.hpp +++ b/src/ArduinoJson/Variant/VariantRefBase.hpp @@ -46,16 +46,7 @@ class VariantRefBase : public VariantTag { // Casts the value to the specified type. // https://arduinojson.org/v7/api/jsonvariant/as/ template - - typename enable_if::value, T>::type as() - const { - return Converter::fromJson(getVariantConst()); - } - - // Casts the value to the specified type. - // https://arduinojson.org/v7/api/jsonvariant/as/ - template - typename enable_if::value, T>::type as() const; + T as() const; template ::value>::type> @@ -83,18 +74,7 @@ class VariantRefBase : public VariantTag { // Returns true if the value is of the specified type. // https://arduinojson.org/v7/api/jsonvariant/is/ template - FORCE_INLINE - typename enable_if::value, bool>::type - is() const; - - // Returns true if the value is of the specified type. - // https://arduinojson.org/v7/api/jsonvariant/is/ - template - FORCE_INLINE - typename enable_if::value, bool>::type - is() const { - return Converter::checkJson(getVariantConst()); - } + FORCE_INLINE bool is() const; // Copies the specified value. // https://arduinojson.org/v7/api/jsonvariant/set/ @@ -298,6 +278,18 @@ class VariantRefBase : public VariantTag { return ArduinoJson::JsonVariantConst(getData(), getResourceManager()); } + template + FORCE_INLINE typename enable_if::value, T>::type + getVariant() const { + return getVariantConst(); + } + + template + FORCE_INLINE typename enable_if::value, T>::type + getVariant() const { + return getVariant(); + } + ArduinoJson::JsonVariant getOrCreateVariant() const; }; diff --git a/src/ArduinoJson/Variant/VariantRefBaseImpl.hpp b/src/ArduinoJson/Variant/VariantRefBaseImpl.hpp index f208907f..299cd13f 100644 --- a/src/ArduinoJson/Variant/VariantRefBaseImpl.hpp +++ b/src/ArduinoJson/Variant/VariantRefBaseImpl.hpp @@ -17,9 +17,10 @@ inline JsonVariant VariantRefBase::add() const { template template -inline typename enable_if::value, T>::type -VariantRefBase::as() const { - return Converter::fromJson(getVariant()); +inline T VariantRefBase::as() const { + using variant_type = // JsonVariantConst or JsonVariant? + typename function_traits::fromJson)>::arg1_type; + return Converter::fromJson(getVariant()); } template @@ -109,9 +110,10 @@ inline JsonVariant VariantRefBase::getOrCreateVariant() const { template template -inline typename enable_if::value, bool>::type -VariantRefBase::is() const { - return Converter::checkJson(getVariant()); +inline bool VariantRefBase::is() const { + using variant_type = // JsonVariantConst or JsonVariant? + typename function_traits::checkJson)>::arg1_type; + return Converter::checkJson(getVariant()); } template