From 2996503b27ef16503a35c96120e1a95c358262d6 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Wed, 26 Feb 2020 16:16:20 +0100 Subject: [PATCH] Fixed enums serialized as booleans (fixes #1197) --- CHANGELOG.md | 1 + extras/tests/JsonVariant/set.cpp | 11 ++++++ extras/tests/Misc/TypeTraits.cpp | 27 +++++++++++++++ src/ArduinoJson/Polyfills/type_traits.hpp | 3 ++ .../Polyfills/type_traits/declval.hpp | 14 ++++++++ .../Polyfills/type_traits/is_class.hpp | 26 ++++++++++++++ .../Polyfills/type_traits/is_convertible.hpp | 34 +++++++++++++++++++ .../Polyfills/type_traits/is_enum.hpp | 23 +++++++++++++ src/ArduinoJson/Variant/VariantRef.hpp | 11 +++++- 9 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 src/ArduinoJson/Polyfills/type_traits/declval.hpp create mode 100644 src/ArduinoJson/Polyfills/type_traits/is_class.hpp create mode 100644 src/ArduinoJson/Polyfills/type_traits/is_convertible.hpp create mode 100644 src/ArduinoJson/Polyfills/type_traits/is_enum.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cb2707c..68c99db2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ HEAD * Changed the array subscript operator to automatically add missing elements * Fixed "deprecated-copy" warning on GCC 9 (fixes #1184) * Fixed `MemberProxy::set(char[])` not duplicating the string (issue #1191) +* Fixed enums serialized as booleans (issue #1197) v6.14.1 (2020-01-27) ------- diff --git a/extras/tests/JsonVariant/set.cpp b/extras/tests/JsonVariant/set.cpp index f2cdb51c..eeb9088b 100644 --- a/extras/tests/JsonVariant/set.cpp +++ b/extras/tests/JsonVariant/set.cpp @@ -5,6 +5,8 @@ #include #include +enum ErrorCode { ERROR_01 = 1, ERROR_10 = 10 }; + TEST_CASE("JsonVariant and strings") { DynamicJsonDocument doc(4096); JsonVariant variant = doc.to(); @@ -91,6 +93,15 @@ TEST_CASE("JsonVariant and strings") { REQUIRE(variant == "hello"); } + + SECTION("stores an enum as an integer") { + ErrorCode code = ERROR_10; + + variant.set(code); + + REQUIRE(variant.is() == true); + REQUIRE(variant.as() == 10); + } } TEST_CASE("JsonVariant with not enough memory") { diff --git a/extras/tests/Misc/TypeTraits.cpp b/extras/tests/Misc/TypeTraits.cpp index 50b2c40f..4566a26a 100644 --- a/extras/tests/Misc/TypeTraits.cpp +++ b/extras/tests/Misc/TypeTraits.cpp @@ -7,6 +7,9 @@ using namespace ARDUINOJSON_NAMESPACE; +class EmptyClass {}; +enum EmptyEnum {}; + TEST_CASE("Polyfills/type_traits") { SECTION("is_base_of") { REQUIRE_FALSE( @@ -48,6 +51,30 @@ TEST_CASE("Polyfills/type_traits") { CHECK(is_unsigned::value == false); } + SECTION("is_convertible") { + CHECK((is_convertible::value == true)); + CHECK((is_convertible::value == true)); + CHECK((is_convertible::value == true)); + CHECK((is_convertible::value == false)); + CHECK((is_convertible::value == false)); + } + + SECTION("is_class") { + CHECK((is_class::value == false)); + CHECK((is_class::value == false)); + CHECK((is_class::value == false)); + CHECK((is_class::value == true)); + } + + SECTION("is_enum") { + CHECK(is_enum::value == false); + CHECK(is_enum::value == true); + CHECK(is_enum::value == false); + CHECK(is_enum::value == false); + CHECK(is_enum::value == false); + CHECK(is_enum::value == false); + } + SECTION("IsVisitable") { CHECK(IsVisitable::value == false); CHECK(IsVisitable::value == false); diff --git a/src/ArduinoJson/Polyfills/type_traits.hpp b/src/ArduinoJson/Polyfills/type_traits.hpp index 8e34fc1a..324f1444 100644 --- a/src/ArduinoJson/Polyfills/type_traits.hpp +++ b/src/ArduinoJson/Polyfills/type_traits.hpp @@ -9,7 +9,10 @@ #include "type_traits/integral_constant.hpp" #include "type_traits/is_array.hpp" #include "type_traits/is_base_of.hpp" +#include "type_traits/is_class.hpp" #include "type_traits/is_const.hpp" +#include "type_traits/is_convertible.hpp" +#include "type_traits/is_enum.hpp" #include "type_traits/is_floating_point.hpp" #include "type_traits/is_integral.hpp" #include "type_traits/is_same.hpp" diff --git a/src/ArduinoJson/Polyfills/type_traits/declval.hpp b/src/ArduinoJson/Polyfills/type_traits/declval.hpp new file mode 100644 index 00000000..2e2e034f --- /dev/null +++ b/src/ArduinoJson/Polyfills/type_traits/declval.hpp @@ -0,0 +1,14 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include + +namespace ARDUINOJSON_NAMESPACE { + +template +T declval(); + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Polyfills/type_traits/is_class.hpp b/src/ArduinoJson/Polyfills/type_traits/is_class.hpp new file mode 100644 index 00000000..d2f2e85e --- /dev/null +++ b/src/ArduinoJson/Polyfills/type_traits/is_class.hpp @@ -0,0 +1,26 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "declval.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +template +struct is_class { + protected: // <- to avoid GCC's "all member functions in class are private" + typedef char Yes[1]; + typedef char No[2]; + + template + static Yes &probe(void (U::*)(void)); + template + static No &probe(...); + + public: + static const bool value = sizeof(probe(0)) == sizeof(Yes); +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Polyfills/type_traits/is_convertible.hpp b/src/ArduinoJson/Polyfills/type_traits/is_convertible.hpp new file mode 100644 index 00000000..e0232aae --- /dev/null +++ b/src/ArduinoJson/Polyfills/type_traits/is_convertible.hpp @@ -0,0 +1,34 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "declval.hpp" + +#ifdef _MSC_VER +#pragma warning(push) +// conversion from 'T' to 'To', possible loss of data +#pragma warning(disable : 4244) +#endif + +namespace ARDUINOJSON_NAMESPACE { + +template +struct is_convertible { + protected: // <- to avoid GCC's "all member functions in class are private" + typedef char Yes[1]; + typedef char No[2]; + + static Yes &probe(To); + static No &probe(...); + + public: + static const bool value = sizeof(probe(declval())) == sizeof(Yes); +}; + +} // namespace ARDUINOJSON_NAMESPACE + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp b/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp new file mode 100644 index 00000000..8ef57d8f --- /dev/null +++ b/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp @@ -0,0 +1,23 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "is_class.hpp" +#include "is_convertible.hpp" +#include "is_floating_point.hpp" +#include "is_integral.hpp" +#include "is_same.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +template +struct is_enum { + static const bool value = is_convertible::value && + !is_class::value && !is_integral::value && + !is_floating_point::value && + !is_same::value; +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantRef.hpp b/src/ArduinoJson/Variant/VariantRef.hpp index a71908dc..c8655345 100644 --- a/src/ArduinoJson/Variant/VariantRef.hpp +++ b/src/ArduinoJson/Variant/VariantRef.hpp @@ -153,7 +153,9 @@ class VariantRef : public VariantRefBase, } // set(bool value) - FORCE_INLINE bool set(bool value) const { + template + FORCE_INLINE bool set( + T value, typename enable_if::value>::type * = 0) const { return variantSetBoolean(_data, value); } @@ -237,6 +239,13 @@ class VariantRef : public VariantRefBase, typename enable_if::value, bool>::type set( const TVariant &value) const; + // set(enum value) + template + FORCE_INLINE bool set( + T value, typename enable_if::value>::type * = 0) const { + return variantSetSignedInteger(_data, static_cast(value)); + } + // Get the variant as the specified type. // // std::string as() const;