diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d12d6e8..a5273c70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ArduinoJson: change log * Add MsgPack bin8/bin16/bin32 support (PR #2078 by @Sanae6) * Make string support even more generic (PR #2084 by @d-a-v) * Optimize `deserializeMsgPack()` +* Allow using a `JsonVariant` as a key or index (issue #2080) + Note: works only for reading, not for writing v7.0.4 (2024-03-12) ------ diff --git a/extras/tests/JsonArray/remove.cpp b/extras/tests/JsonArray/remove.cpp index 6e671300..9cbd90bb 100644 --- a/extras/tests/JsonArray/remove.cpp +++ b/extras/tests/JsonArray/remove.cpp @@ -88,6 +88,15 @@ TEST_CASE("JsonArray::remove()") { JsonArray unboundArray; unboundArray.remove(unboundArray.begin()); } + + SECTION("use JsonVariant as index") { + array.remove(array[3]); // no effect with null variant + array.remove(array[0]); // remove element at index 1 + + REQUIRE(2 == array.size()); + REQUIRE(array[0] == 1); + REQUIRE(array[1] == 3); + } } TEST_CASE("Removed elements are recycled") { diff --git a/extras/tests/JsonArray/subscript.cpp b/extras/tests/JsonArray/subscript.cpp index fde76177..c79dc67f 100644 --- a/extras/tests/JsonArray/subscript.cpp +++ b/extras/tests/JsonArray/subscript.cpp @@ -164,4 +164,13 @@ TEST_CASE("JsonArray::operator[]") { REQUIRE(std::string("world") == array[0]); } #endif + + SECTION("Use a JsonVariant as index") { + array[0] = 1; + array[1] = 2; + array[2] = 3; + + REQUIRE(array[array[1]] == 3); + REQUIRE(array[array[3]] == nullptr); + } } diff --git a/extras/tests/JsonArrayConst/subscript.cpp b/extras/tests/JsonArrayConst/subscript.cpp index 4525287d..28512b20 100644 --- a/extras/tests/JsonArrayConst/subscript.cpp +++ b/extras/tests/JsonArrayConst/subscript.cpp @@ -13,8 +13,15 @@ TEST_CASE("JsonArrayConst::operator[]") { doc.add(2); doc.add(3); - REQUIRE(1 == arr[0].as()); - REQUIRE(2 == arr[1].as()); - REQUIRE(3 == arr[2].as()); - REQUIRE(0 == arr[3].as()); + SECTION("int") { + REQUIRE(1 == arr[0].as()); + REQUIRE(2 == arr[1].as()); + REQUIRE(3 == arr[2].as()); + REQUIRE(0 == arr[3].as()); + } + + SECTION("JsonVariant") { + REQUIRE(2 == arr[arr[0]].as()); + REQUIRE(0 == arr[arr[3]].as()); + } } diff --git a/extras/tests/JsonDocument/containsKey.cpp b/extras/tests/JsonDocument/containsKey.cpp index 9425e019..c62cb35c 100644 --- a/extras/tests/JsonDocument/containsKey.cpp +++ b/extras/tests/JsonDocument/containsKey.cpp @@ -41,4 +41,12 @@ TEST_CASE("JsonDocument::containsKey()") { SECTION("returns false on null") { REQUIRE(doc.containsKey("hello") == false); } + + SECTION("support JsonVariant") { + doc["hello"] = "world"; + doc["key"] = "hello"; + + REQUIRE(doc.containsKey(doc["key"]) == true); + REQUIRE(doc.containsKey(doc["foo"]) == false); + } } diff --git a/extras/tests/JsonDocument/remove.cpp b/extras/tests/JsonDocument/remove.cpp index 26048e30..87a4b04c 100644 --- a/extras/tests/JsonDocument/remove.cpp +++ b/extras/tests/JsonDocument/remove.cpp @@ -49,4 +49,25 @@ TEST_CASE("JsonDocument::remove()") { REQUIRE(doc.as() == "{\"a\":1}"); } #endif + + SECTION("remove(JsonVariant) from object") { + doc["a"] = 1; + doc["b"] = 2; + doc["c"] = "b"; + + doc.remove(doc["c"]); + + REQUIRE(doc.as() == "{\"a\":1,\"c\":\"b\"}"); + } + + SECTION("remove(JsonVariant) from array") { + doc[0] = 3; + doc[1] = 2; + doc[2] = 1; + + doc.remove(doc[2]); + doc.remove(doc[3]); // noop + + REQUIRE(doc.as() == "[3,1]"); + } } diff --git a/extras/tests/JsonDocument/subscript.cpp b/extras/tests/JsonDocument/subscript.cpp index ed8a6956..4796c06c 100644 --- a/extras/tests/JsonDocument/subscript.cpp +++ b/extras/tests/JsonDocument/subscript.cpp @@ -22,6 +22,12 @@ TEST_CASE("JsonDocument::operator[]") { REQUIRE(cdoc[std::string("hello")] == "world"); } + SECTION("JsonVariant") { + doc["key"] = "hello"; + REQUIRE(doc[doc["key"]] == "world"); + REQUIRE(cdoc[cdoc["key"]] == "world"); + } + SECTION("supports operator|") { REQUIRE((doc["hello"] | "nope") == std::string("world")); REQUIRE((doc["world"] | "nope") == std::string("nope")); @@ -31,8 +37,16 @@ TEST_CASE("JsonDocument::operator[]") { SECTION("array") { deserializeJson(doc, "[\"hello\",\"world\"]"); - REQUIRE(doc[1] == "world"); - REQUIRE(cdoc[1] == "world"); + SECTION("int") { + REQUIRE(doc[1] == "world"); + REQUIRE(cdoc[1] == "world"); + } + + SECTION("JsonVariant") { + doc[2] = 1; + REQUIRE(doc[doc[2]] == "world"); + REQUIRE(cdoc[doc[2]] == "world"); + } } } diff --git a/extras/tests/JsonObject/containsKey.cpp b/extras/tests/JsonObject/containsKey.cpp index a5e20e95..d7dd8d1e 100644 --- a/extras/tests/JsonObject/containsKey.cpp +++ b/extras/tests/JsonObject/containsKey.cpp @@ -30,4 +30,10 @@ TEST_CASE("JsonObject::containsKey()") { REQUIRE(true == obj.containsKey(vla)); } #endif + + SECTION("key is a JsonVariant") { + doc["key"] = "hello"; + REQUIRE(true == obj.containsKey(obj["key"])); + REQUIRE(false == obj.containsKey(obj["hello"])); + } } diff --git a/extras/tests/JsonObject/remove.cpp b/extras/tests/JsonObject/remove.cpp index 0124c4a8..4c3e35d7 100644 --- a/extras/tests/JsonObject/remove.cpp +++ b/extras/tests/JsonObject/remove.cpp @@ -80,4 +80,10 @@ TEST_CASE("JsonObject::remove()") { JsonObject unboundObject; unboundObject.remove(unboundObject.begin()); } + + SECTION("remove(JsonVariant)") { + obj["key"] = "b"; + obj.remove(obj["key"]); + REQUIRE("{\"a\":0,\"c\":2,\"key\":\"b\"}" == doc.as()); + } } diff --git a/extras/tests/JsonObject/subscript.cpp b/extras/tests/JsonObject/subscript.cpp index 2f8c95f9..d5684b8e 100644 --- a/extras/tests/JsonObject/subscript.cpp +++ b/extras/tests/JsonObject/subscript.cpp @@ -249,4 +249,12 @@ TEST_CASE("JsonObject::operator[]") { REQUIRE(true == obj["hello"]["world"].is()); REQUIRE(false == obj["hello"]["world"].is()); } + + SECTION("JsonVariant") { + obj["hello"] = "world"; + doc["key"] = "hello"; + + REQUIRE(obj[obj["key"]] == "world"); + REQUIRE(obj[obj["foo"]] == nullptr); + } } diff --git a/extras/tests/JsonObjectConst/containsKey.cpp b/extras/tests/JsonObjectConst/containsKey.cpp index 3b639417..8f70877d 100644 --- a/extras/tests/JsonObjectConst/containsKey.cpp +++ b/extras/tests/JsonObjectConst/containsKey.cpp @@ -29,4 +29,10 @@ TEST_CASE("JsonObjectConst::containsKey()") { REQUIRE(true == obj.containsKey(vla)); } #endif + + SECTION("supports JsonVariant") { + doc["key"] = "hello"; + REQUIRE(true == obj.containsKey(obj["key"])); + REQUIRE(false == obj.containsKey(obj["hello"])); + } } diff --git a/extras/tests/JsonObjectConst/subscript.cpp b/extras/tests/JsonObjectConst/subscript.cpp index 917b54a6..a4bacfd5 100644 --- a/extras/tests/JsonObjectConst/subscript.cpp +++ b/extras/tests/JsonObjectConst/subscript.cpp @@ -30,4 +30,10 @@ TEST_CASE("JsonObjectConst::operator[]") { REQUIRE(std::string("world") == obj[vla]); } #endif + + SECTION("supports JsonVariant") { + doc["key"] = "hello"; + REQUIRE(obj[obj["key"]] == "world"); + REQUIRE(obj[obj["foo"]] == nullptr); + } } diff --git a/extras/tests/JsonVariant/containsKey.cpp b/extras/tests/JsonVariant/containsKey.cpp index 45af06d3..62536ce6 100644 --- a/extras/tests/JsonVariant/containsKey.cpp +++ b/extras/tests/JsonVariant/containsKey.cpp @@ -23,4 +23,12 @@ TEST_CASE("JsonVariant::containsKey()") { REQUIRE(var.containsKey(std::string("hello")) == true); REQUIRE(var.containsKey(std::string("world")) == false); } + + SECTION("containsKey(JsonVariant)") { + var["hello"] = "world"; + var["key"] = "hello"; + + REQUIRE(var.containsKey(doc["key"]) == true); + REQUIRE(var.containsKey(doc["foo"]) == false); + } } diff --git a/extras/tests/JsonVariant/remove.cpp b/extras/tests/JsonVariant/remove.cpp index 3412bc0c..ee557c1e 100644 --- a/extras/tests/JsonVariant/remove.cpp +++ b/extras/tests/JsonVariant/remove.cpp @@ -81,3 +81,30 @@ TEST_CASE("JsonVariant::remove(std::string)") { REQUIRE(var.as() == "{\"a\":1}"); } + +TEST_CASE("JsonVariant::remove(JsonVariant) from object") { + JsonDocument doc; + JsonVariant var = doc.to(); + + var["a"] = "a"; + var["b"] = 2; + var["c"] = "b"; + + var.remove(var["c"]); + + REQUIRE(var.as() == "{\"a\":\"a\",\"c\":\"b\"}"); +} + +TEST_CASE("JsonVariant::remove(JsonVariant) from array") { + JsonDocument doc; + JsonVariant var = doc.to(); + + var[0] = 3; + var[1] = 2; + var[2] = 1; + + var.remove(var[2]); + var.remove(var[3]); // noop + + REQUIRE(var.as() == "[3,1]"); +} diff --git a/extras/tests/JsonVariant/subscript.cpp b/extras/tests/JsonVariant/subscript.cpp index 9f2e9129..72de1ee5 100644 --- a/extras/tests/JsonVariant/subscript.cpp +++ b/extras/tests/JsonVariant/subscript.cpp @@ -67,6 +67,15 @@ TEST_CASE("JsonVariant::operator[]") { REQUIRE(var.is()); REQUIRE(var.as() == 123); } + + SECTION("use JsonVariant as index") { + array.add("A"); + array.add("B"); + array.add(1); + + REQUIRE(var[var[2]] == "B"); + REQUIRE(var[var[3]].isNull()); + } } SECTION("The JsonVariant is a JsonObject") { @@ -103,6 +112,15 @@ TEST_CASE("JsonVariant::operator[]") { JsonArray arr = var["hello"].to(); REQUIRE(arr.isNull() == false); } + + SECTION("use JsonVariant as key") { + object["a"] = "a"; + object["b"] = "b"; + object["c"] = "b"; + + REQUIRE(var[var["c"]] == "b"); + REQUIRE(var[var["d"]].isNull()); + } } #if defined(HAS_VARIABLE_LENGTH_ARRAY) && \ diff --git a/extras/tests/JsonVariantConst/containsKey.cpp b/extras/tests/JsonVariantConst/containsKey.cpp index 7ab96300..fc397249 100644 --- a/extras/tests/JsonVariantConst/containsKey.cpp +++ b/extras/tests/JsonVariantConst/containsKey.cpp @@ -30,4 +30,10 @@ TEST_CASE("JsonVariantConst::containsKey()") { REQUIRE(true == var.containsKey(vla)); } #endif + + SECTION("support JsonVariant") { + doc["key"] = "hello"; + REQUIRE(var.containsKey(var["key"]) == true); + REQUIRE(var.containsKey(var["foo"]) == false); + } } diff --git a/extras/tests/JsonVariantConst/subscript.cpp b/extras/tests/JsonVariantConst/subscript.cpp index 70a733b2..7bce52f7 100644 --- a/extras/tests/JsonVariantConst/subscript.cpp +++ b/extras/tests/JsonVariantConst/subscript.cpp @@ -27,13 +27,24 @@ TEST_CASE("JsonVariantConst::operator[]") { array.add("A"); array.add("B"); - REQUIRE(std::string("A") == var[0]); - REQUIRE(std::string("B") == var[1]); - REQUIRE(std::string("A") == - var[static_cast(0)]); // issue #381 - REQUIRE(var[666].isNull()); - REQUIRE(var[3].isNull()); - REQUIRE(var["0"].isNull()); + SECTION("int") { + REQUIRE(std::string("A") == var[0]); + REQUIRE(std::string("B") == var[1]); + REQUIRE(std::string("A") == + var[static_cast(0)]); // issue #381 + REQUIRE(var[666].isNull()); + REQUIRE(var[3].isNull()); + } + + SECTION("const char*") { + REQUIRE(var["0"].isNull()); + } + + SECTION("JsonVariant") { + array.add(1); + REQUIRE(var[var[2]] == std::string("B")); + REQUIRE(var[var[3]].isNull()); + } } SECTION("object") { @@ -64,5 +75,11 @@ TEST_CASE("JsonVariantConst::operator[]") { REQUIRE(std::string("A") == var[vla]); } #endif + + SECTION("supports JsonVariant") { + object["c"] = "b"; + REQUIRE(var[var["c"]] == "B"); + REQUIRE(var[var["d"]].isNull()); + } } } diff --git a/src/ArduinoJson/Array/JsonArray.hpp b/src/ArduinoJson/Array/JsonArray.hpp index 29233630..71b41ec1 100644 --- a/src/ArduinoJson/Array/JsonArray.hpp +++ b/src/ArduinoJson/Array/JsonArray.hpp @@ -114,6 +114,15 @@ class JsonArray : public detail::VariantOperators { detail::ArrayData::removeElement(data_, index, resources_); } + // Removes the element at the specified index. + // https://arduinojson.org/v7/api/jsonarray/remove/ + template + typename detail::enable_if::value>::type remove( + TVariant variant) const { + if (variant.template is()) + remove(variant.template as()); + } + // Removes all the elements of the array. // https://arduinojson.org/v7/api/jsonarray/clear/ void clear() const { @@ -122,8 +131,23 @@ class JsonArray : public detail::VariantOperators { // Gets or sets the element at the specified index. // https://arduinojson.org/v7/api/jsonarray/subscript/ - detail::ElementProxy operator[](size_t index) const { - return {*this, index}; + template + typename detail::enable_if::value, + detail::ElementProxy>::type + operator[](T index) const { + return {*this, size_t(index)}; + } + + // Gets or sets the element at the specified index. + // https://arduinojson.org/v7/api/jsonarray/subscript/ + template + typename detail::enable_if::value, + detail::ElementProxy>::type + operator[](const TVariant& variant) const { + if (variant.template is()) + return operator[](variant.template as()); + else + return {*this, size_t(-1)}; } operator JsonVariantConst() const { diff --git a/src/ArduinoJson/Array/JsonArrayConst.hpp b/src/ArduinoJson/Array/JsonArrayConst.hpp index 6c0d7db2..be7e999b 100644 --- a/src/ArduinoJson/Array/JsonArrayConst.hpp +++ b/src/ArduinoJson/Array/JsonArrayConst.hpp @@ -45,9 +45,25 @@ class JsonArrayConst : public detail::VariantOperators { // Returns the element at the specified index. // https://arduinojson.org/v7/api/jsonarrayconst/subscript/ - JsonVariantConst operator[](size_t index) const { + template + typename detail::enable_if::value, + JsonVariantConst>::type + operator[](T index) const { return JsonVariantConst( - detail::ArrayData::getElement(data_, index, resources_), resources_); + detail::ArrayData::getElement(data_, size_t(index), resources_), + resources_); + } + + // Returns the element at the specified index. + // https://arduinojson.org/v7/api/jsonarrayconst/subscript/ + template + typename detail::enable_if::value, + JsonVariantConst>::type + operator[](const TVariant& variant) const { + if (variant.template is()) + return operator[](variant.template as()); + else + return JsonVariantConst(); } operator JsonVariantConst() const { diff --git a/src/ArduinoJson/Document/JsonDocument.hpp b/src/ArduinoJson/Document/JsonDocument.hpp index 0f336f1a..979a1850 100644 --- a/src/ArduinoJson/Document/JsonDocument.hpp +++ b/src/ArduinoJson/Document/JsonDocument.hpp @@ -163,10 +163,19 @@ class JsonDocument : public detail::VariantOperators { // Returns true if the root object contains the specified key. // https://arduinojson.org/v7/api/jsondocument/containskey/ template - bool containsKey(const TString& key) const { + typename detail::enable_if::value, bool>::type + containsKey(const TString& key) const { return data_.getMember(detail::adaptString(key), &resources_) != 0; } + // Returns true if the root object contains the specified key. + // https://arduinojson.org/v7/api/jsondocument/containskey/ + template + typename detail::enable_if::value, bool>::type + containsKey(const TVariant& key) const { + return containsKey(key.template as()); + } + // Gets or sets a root object's member. // https://arduinojson.org/v7/api/jsondocument/subscript/ template @@ -207,8 +216,11 @@ class JsonDocument : public detail::VariantOperators { // Gets or sets a root array's element. // https://arduinojson.org/v7/api/jsondocument/subscript/ - detail::ElementProxy operator[](size_t index) { - return {*this, index}; + template + typename detail::enable_if::value, + detail::ElementProxy>::type + operator[](T index) { + return {*this, size_t(index)}; } // Gets a root array's member. @@ -217,6 +229,19 @@ class JsonDocument : public detail::VariantOperators { return JsonVariantConst(data_.getElement(index, &resources_), &resources_); } + // Gets or sets a root object's member. + // https://arduinojson.org/v7/api/jsondocument/subscript/ + template + typename detail::enable_if::value, + JsonVariantConst>::type + operator[](const TVariant& key) const { + if (key.template is()) + return operator[](key.template as()); + if (key.template is()) + return operator[](key.template as()); + return {}; + } + // Appends a new (empty) element to the root array. // Returns a reference to the new element. // https://arduinojson.org/v7/api/jsondocument/add/ @@ -251,8 +276,11 @@ class JsonDocument : public detail::VariantOperators { // Removes an element of the root array. // https://arduinojson.org/v7/api/jsondocument/remove/ - void remove(size_t index) { - detail::VariantData::removeElement(getData(), index, getResourceManager()); + template + typename detail::enable_if::value>::type remove( + T index) { + detail::VariantData::removeElement(getData(), size_t(index), + getResourceManager()); } // Removes a member of the root object. @@ -267,13 +295,23 @@ class JsonDocument : public detail::VariantOperators { // Removes a member of the root object. // https://arduinojson.org/v7/api/jsondocument/remove/ template - typename detail::enable_if::value>::type remove( const TString& key) { detail::VariantData::removeMember(getData(), detail::adaptString(key), getResourceManager()); } + // Removes a member of the root object or an element of the root array. + // https://arduinojson.org/v7/api/jsondocument/remove/ + template + typename detail::enable_if::value>::type remove( + const TVariant& key) { + if (key.template is()) + remove(key.template as()); + if (key.template is()) + remove(key.template as()); + } + operator JsonVariant() { return getVariant(); } diff --git a/src/ArduinoJson/Object/JsonObject.hpp b/src/ArduinoJson/Object/JsonObject.hpp index e4e7dee4..a7b9f5b3 100644 --- a/src/ArduinoJson/Object/JsonObject.hpp +++ b/src/ArduinoJson/Object/JsonObject.hpp @@ -102,7 +102,6 @@ class JsonObject : public detail::VariantOperators { // Gets or sets the member with specified key. // https://arduinojson.org/v7/api/jsonobject/subscript/ template - typename detail::enable_if::value, detail::MemberProxy>::type operator[](const TString& key) const { @@ -112,13 +111,24 @@ class JsonObject : public detail::VariantOperators { // Gets or sets the member with specified key. // https://arduinojson.org/v7/api/jsonobject/subscript/ template - typename detail::enable_if::value, detail::MemberProxy>::type operator[](TChar* key) const { return {*this, key}; } + // Gets or sets the member with specified key. + // https://arduinojson.org/v7/api/jsonobject/subscript/ + template + typename detail::enable_if::value, + detail::MemberProxy>::type + operator[](const TVariant& key) const { + if (key.template is()) + return {*this, key.template as()}; + else + return {*this, nullptr}; + } + // Removes the member at the specified iterator. // https://arduinojson.org/v7/api/jsonobject/remove/ FORCE_INLINE void remove(iterator it) const { @@ -128,11 +138,21 @@ class JsonObject : public detail::VariantOperators { // Removes the member with the specified key. // https://arduinojson.org/v7/api/jsonobject/remove/ template - FORCE_INLINE void remove(const TString& key) const { + typename detail::enable_if::value>::type remove( + const TString& key) const { detail::ObjectData::removeMember(data_, detail::adaptString(key), resources_); } + // Removes the member with the specified key. + // https://arduinojson.org/v7/api/jsonobject/remove/ + template + typename detail::enable_if::value>::type remove( + const TVariant& key) const { + if (key.template is()) + remove(key.template as()); + } + // Removes the member with the specified key. // https://arduinojson.org/v7/api/jsonobject/remove/ template @@ -144,7 +164,6 @@ class JsonObject : public detail::VariantOperators { // Returns true if the object contains the specified key. // https://arduinojson.org/v7/api/jsonobject/containskey/ template - typename detail::enable_if::value, bool>::type containsKey(const TString& key) const { return detail::ObjectData::getMember(data_, detail::adaptString(key), @@ -154,13 +173,20 @@ class JsonObject : public detail::VariantOperators { // Returns true if the object contains the specified key. // https://arduinojson.org/v7/api/jsonobject/containskey/ template - typename detail::enable_if::value, bool>::type containsKey(TChar* key) const { return detail::ObjectData::getMember(data_, detail::adaptString(key), resources_) != 0; } + // Returns true if the object contains the specified key. + // https://arduinojson.org/v7/api/jsonobject/containskey/ + template + typename detail::enable_if::value, bool>::type + containsKey(const TVariant& key) const { + return containsKey(key.template as()); + } + // DEPRECATED: use obj[key].to() instead template ARDUINOJSON_DEPRECATED("use obj[key].to() instead") diff --git a/src/ArduinoJson/Object/JsonObjectConst.hpp b/src/ArduinoJson/Object/JsonObjectConst.hpp index 908fa275..1c9e0270 100644 --- a/src/ArduinoJson/Object/JsonObjectConst.hpp +++ b/src/ArduinoJson/Object/JsonObjectConst.hpp @@ -71,7 +71,8 @@ class JsonObjectConst : public detail::VariantOperators { // Returns true if the object contains the specified key. // https://arduinojson.org/v7/api/jsonobjectconst/containskey/ template - bool containsKey(const TString& key) const { + typename detail::enable_if::value, bool>::type + containsKey(const TString& key) const { return detail::ObjectData::getMember(data_, detail::adaptString(key), resources_) != 0; } @@ -84,6 +85,14 @@ class JsonObjectConst : public detail::VariantOperators { resources_) != 0; } + // Returns true if the object contains the specified key. + // https://arduinojson.org/v7/api/jsonobjectconst/containskey/ + template + typename detail::enable_if::value, bool>::type + containsKey(const TVariant& key) const { + return containsKey(key.template as()); + } + // Gets the member with specified key. // https://arduinojson.org/v7/api/jsonobjectconst/subscript/ template @@ -106,6 +115,18 @@ class JsonObjectConst : public detail::VariantOperators { resources_); } + // Gets the member with specified key. + // https://arduinojson.org/v7/api/jsonobjectconst/subscript/ + template + typename detail::enable_if::value, + JsonVariantConst>::type + operator[](const TVariant& key) const { + if (key.template is()) + return operator[](key.template as()); + else + return JsonVariantConst(); + } + // DEPRECATED: always returns zero ARDUINOJSON_DEPRECATED("always returns zero") size_t memoryUsage() const { diff --git a/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp b/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp index 525ef247..58a05ba0 100644 --- a/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp +++ b/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp @@ -14,7 +14,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template struct is_enum { - static const bool value = is_convertible::value && + static const bool value = is_convertible::value && !is_class::value && !is_integral::value && !is_floating_point::value; }; diff --git a/src/ArduinoJson/Variant/JsonVariantConst.hpp b/src/ArduinoJson/Variant/JsonVariantConst.hpp index 7e7b8c0d..ac8aafff 100644 --- a/src/ArduinoJson/Variant/JsonVariantConst.hpp +++ b/src/ArduinoJson/Variant/JsonVariantConst.hpp @@ -86,9 +86,13 @@ class JsonVariantConst : public detail::VariantTag, // Gets array's element at specified index. // https://arduinojson.org/v7/api/jsonvariantconst/subscript/ - JsonVariantConst operator[](size_t index) const { + template + typename detail::enable_if::value, + JsonVariantConst>::type + operator[](T index) const { return JsonVariantConst( - detail::VariantData::getElement(data_, index, resources_), resources_); + detail::VariantData::getElement(data_, size_t(index), resources_), + resources_); } // Gets object's member with specified key. @@ -113,10 +117,22 @@ class JsonVariantConst : public detail::VariantTag, resources_); } + // Gets object's member with specified key or the array's element at the + // specified index. + // https://arduinojson.org/v7/api/jsonvariantconst/subscript/ + template + typename detail::enable_if::value, + JsonVariantConst>::type + operator[](const TVariant& key) const { + if (key.template is()) + return operator[](key.template as()); + else + return operator[](key.template as()); + } + // Returns true if tge object contains the specified key. // https://arduinojson.org/v7/api/jsonvariantconst/containskey/ template - typename detail::enable_if::value, bool>::type containsKey(const TString& key) const { return detail::VariantData::getMember(getData(), detail::adaptString(key), @@ -126,13 +142,18 @@ class JsonVariantConst : public detail::VariantTag, // Returns true if tge object contains the specified key. // https://arduinojson.org/v7/api/jsonvariantconst/containskey/ template - typename detail::enable_if::value, bool>::type containsKey(TChar* key) const { return detail::VariantData::getMember(getData(), detail::adaptString(key), resources_) != 0; } + template + typename detail::enable_if::value, bool>::type + containsKey(const TVariant& key) const { + return containsKey(key.template as()); + } + // DEPRECATED: always returns zero ARDUINOJSON_DEPRECATED("always returns zero") size_t memoryUsage() const { diff --git a/src/ArduinoJson/Variant/VariantRefBase.hpp b/src/ArduinoJson/Variant/VariantRefBase.hpp index 318915e8..9dc06e48 100644 --- a/src/ArduinoJson/Variant/VariantRefBase.hpp +++ b/src/ArduinoJson/Variant/VariantRefBase.hpp @@ -169,6 +169,17 @@ class VariantRefBase : public VariantTag { getResourceManager()); } + // Removes a member of the object or an element of the array. + // https://arduinojson.org/v7/api/jsonvariant/remove/ + template + typename enable_if::value>::type remove( + const TVariant& key) const { + if (key.template is()) + remove(key.template as()); + else + remove(key.template as()); + } + // Gets or sets an array element. // https://arduinojson.org/v7/api/jsonvariant/subscript/ ElementProxy operator[](size_t index) const; @@ -185,6 +196,12 @@ class VariantRefBase : public VariantTag { typename enable_if::value, bool>::type containsKey( TChar* key) const; + // Returns true if the object contains the specified key. + // https://arduinojson.org/v7/api/jsonvariant/containskey/ + template + typename enable_if::value, bool>::type containsKey( + const TVariant& key) const; + // Gets or sets an object member. // https://arduinojson.org/v7/api/jsonvariant/subscript/ template @@ -199,6 +216,17 @@ class VariantRefBase : public VariantTag { MemberProxy>::type operator[](TChar* key) const; + // Gets an object member or an array element. + // https://arduinojson.org/v7/api/jsonvariant/subscript/ + template + typename enable_if::value, JsonVariantConst>::type + operator[](const TVariant& key) const { + if (key.template is()) + return operator[](key.template as()); + else + return operator[](key.template as()); + } + // DEPRECATED: use add() instead ARDUINOJSON_DEPRECATED("use add() instead") JsonVariant add() const; diff --git a/src/ArduinoJson/Variant/VariantRefBaseImpl.hpp b/src/ArduinoJson/Variant/VariantRefBaseImpl.hpp index 89e0edec..f208907f 100644 --- a/src/ArduinoJson/Variant/VariantRefBaseImpl.hpp +++ b/src/ArduinoJson/Variant/VariantRefBaseImpl.hpp @@ -90,6 +90,13 @@ VariantRefBase::containsKey(TChar* key) const { getResourceManager()) != 0; } +template +template +inline typename enable_if::value, bool>::type +VariantRefBase::containsKey(const TVariant& key) const { + return containsKey(key.template as()); +} + template inline JsonVariant VariantRefBase::getVariant() const { return JsonVariant(getData(), getResourceManager());