forked from bblanchon/ArduinoJson
Compare commits
33 Commits
Author | SHA1 | Date | |
---|---|---|---|
8f7e793f37 | |||
254fa5712a | |||
de05814294 | |||
e33e78d202 | |||
ed5f890d28 | |||
8931651317 | |||
c078957282 | |||
cf084ae6b4 | |||
f02fcc96a2 | |||
594dc707cb | |||
5f8e3c0f0f | |||
afc0a29c2c | |||
a256ec7fff | |||
019e8326b7 | |||
bee1095042 | |||
de59dce527 | |||
57a9c50b38 | |||
5e7653b36a | |||
8110058729 | |||
7946ebe1a3 | |||
f9fe8557f1 | |||
e007d71b4f | |||
67a512a923 | |||
9cf4f3871d | |||
31253dbe13 | |||
1110d62128 | |||
c6c0649d70 | |||
61ec2c4f95 | |||
0dd6231b3f | |||
20219d74f0 | |||
64cbaa6ff7 | |||
2512993617 | |||
48ee4a178b |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -403,7 +403,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Particle CLI
|
||||
run: sudo npm install -g particle-cli particle-usb
|
||||
run: sudo npm install -g particle-cli
|
||||
- name: Login to Particle
|
||||
run: particle login -t "${{ secrets.PARTICLE_TOKEN }}"
|
||||
- name: Compile
|
||||
|
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@ -21,7 +21,13 @@ jobs:
|
||||
id: body
|
||||
run: |
|
||||
FILENAME=RELEASE.md
|
||||
extras/scripts/get-release-body.sh ${{ steps.init.outputs.tag }} CHANGELOG.md | tee $FILENAME
|
||||
tee $FILENAME <<END
|
||||
## Changes
|
||||
|
||||
$(extras/scripts/extract_changes.awk CHANGELOG.md)
|
||||
|
||||
[View version history](https://github.com/bblanchon/ArduinoJson/blob/${{ steps.init.outputs.tag }}/CHANGELOG.md)
|
||||
END
|
||||
echo "filename=$FILENAME" >> $GITHUB_OUTPUT
|
||||
- name: Amalgamate ArduinoJson.h
|
||||
id: amalgamate_h
|
||||
@ -61,7 +67,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install
|
||||
run: npm install -g particle-cli particle-usb
|
||||
run: npm install -g particle-cli
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Login
|
||||
|
47
CHANGELOG.md
47
CHANGELOG.md
@ -1,6 +1,53 @@
|
||||
ArduinoJson: change log
|
||||
=======================
|
||||
|
||||
v7.3.0 (2024-12-29)
|
||||
------
|
||||
|
||||
* Fix support for NUL characters in `deserializeJson()`
|
||||
* Make `ElementProxy` and `MemberProxy` non-copyable
|
||||
* Change string copy policy: only string literal are stored by pointer
|
||||
* `JsonString` is now stored by copy, unless specified otherwise
|
||||
* Replace undocumented `JsonString::Ownership` with `bool`
|
||||
* Rename undocumented `JsonString::isLinked()` to `isStatic()`
|
||||
* Move public facing SFINAEs to template declarations
|
||||
|
||||
> ### BREAKING CHANGES
|
||||
>
|
||||
> In previous versions, `MemberProxy` (the class returned by `operator[]`) could lead to dangling pointers when used with a temporary string.
|
||||
> To prevent this issue, `MemberProxy` and `ElementProxy` are now non-copyable.
|
||||
>
|
||||
> Your code is likely to be affected if you use `auto` to store the result of `operator[]`. For example, the following line won't compile anymore:
|
||||
>
|
||||
> ```cpp
|
||||
> auto value = doc["key"];
|
||||
> ```
|
||||
>
|
||||
> To fix the issue, you must append either `.as<T>()` or `.to<T>()`, depending on the situation.
|
||||
>
|
||||
> For example, if you are extracting values from a JSON document, you should update like this:
|
||||
>
|
||||
> ```diff
|
||||
> - auto config = doc["config"];
|
||||
> + auto config = doc["config"].as<JsonObject>();
|
||||
> const char* name = config["name"];
|
||||
> ```
|
||||
>
|
||||
> However, if you are building a JSON document, you should update like this:
|
||||
>
|
||||
> ```diff
|
||||
> - auto config = doc["config"];
|
||||
> + auto config = doc["config"].to<JsonObject>();
|
||||
> config["name"] = "ArduinoJson";
|
||||
> ```
|
||||
|
||||
v7.2.1 (2024-11-15)
|
||||
------
|
||||
|
||||
* Forbid `deserializeJson(JsonArray|JsonObject, ...)` (issue #2135)
|
||||
* Fix VLA support in `JsonDocument::set()`
|
||||
* Fix `operator[](variant)` ignoring NUL characters
|
||||
|
||||
v7.2.0 (2024-09-18)
|
||||
------
|
||||
|
||||
|
@ -10,7 +10,7 @@ if(ESP_PLATFORM)
|
||||
return()
|
||||
endif()
|
||||
|
||||
project(ArduinoJson VERSION 7.2.0)
|
||||
project(ArduinoJson VERSION 7.3.0)
|
||||
|
||||
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
|
||||
include(CTest)
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: 7.2.0.{build}
|
||||
version: 7.3.0.{build}
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
|
29
extras/scripts/extract_changes.awk
Executable file
29
extras/scripts/extract_changes.awk
Executable file
@ -0,0 +1,29 @@
|
||||
#!/usr/bin/awk -f
|
||||
|
||||
# Start echoing after the first list item
|
||||
/\* / {
|
||||
STARTED=1
|
||||
EMPTY_LINE=0
|
||||
}
|
||||
|
||||
# Remember if we have seen an empty line
|
||||
/^[[:space:]]*$/ {
|
||||
EMPTY_LINE=1
|
||||
}
|
||||
|
||||
# Exit when seeing a new version number
|
||||
/^v[[:digit:]]/ {
|
||||
if (STARTED) exit
|
||||
}
|
||||
|
||||
# Print if the line is not empty
|
||||
# and restore the empty line we have skipped
|
||||
!/^[[:space:]]*$/ {
|
||||
if (STARTED) {
|
||||
if (EMPTY_LINE) {
|
||||
print ""
|
||||
EMPTY_LINE=0
|
||||
}
|
||||
print
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
TAG="$1"
|
||||
CHANGELOG="$2"
|
||||
|
||||
cat << END
|
||||
## Changes
|
||||
|
||||
$(awk '/\* /{ FOUND=1 } /^[[:space:]]*$/ { if(FOUND) exit } { if(FOUND) print }' "$CHANGELOG")
|
||||
|
||||
[View version history](https://github.com/bblanchon/ArduinoJson/blob/$TAG/CHANGELOG.md)
|
||||
END
|
@ -14,5 +14,5 @@ date: '$(date +'%Y-%m-%d')'
|
||||
$(extras/scripts/wandbox/publish.sh "$ARDUINOJSON_H")
|
||||
---
|
||||
|
||||
$(awk '/\* /{ FOUND=1; print; next } { if (FOUND) exit}' "$CHANGELOG")
|
||||
$(extras/scripts/extract_changes.awk "$CHANGELOG")
|
||||
END
|
||||
|
@ -15,7 +15,7 @@ compile() {
|
||||
"code":$(read_string "$FILE_PATH"),
|
||||
"codes": [{"file":"ArduinoJson.h","code":$(read_string "$ARDUINOJSON_H")}],
|
||||
"options": "warning,c++11",
|
||||
"compiler": "gcc-5.5.0",
|
||||
"compiler": "gcc-head",
|
||||
"save": true
|
||||
}
|
||||
END
|
||||
|
@ -5,15 +5,18 @@
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
add_subdirectory(catch)
|
||||
link_libraries(ArduinoJson)
|
||||
|
||||
link_libraries(ArduinoJson catch)
|
||||
# Failing builds should only link with ArduinoJson, not catch
|
||||
add_subdirectory(FailingBuilds)
|
||||
|
||||
add_subdirectory(catch)
|
||||
link_libraries(catch)
|
||||
|
||||
include_directories(Helpers)
|
||||
add_subdirectory(Cpp17)
|
||||
add_subdirectory(Cpp20)
|
||||
add_subdirectory(Deprecated)
|
||||
add_subdirectory(FailingBuilds)
|
||||
add_subdirectory(IntegrationTests)
|
||||
add_subdirectory(JsonArray)
|
||||
add_subdirectory(JsonArrayConst)
|
||||
|
@ -44,18 +44,30 @@ TEST_CASE("JsonDocument::containsKey()") {
|
||||
REQUIRE(doc.containsKey("hello") == false);
|
||||
}
|
||||
|
||||
SECTION("support JsonVariant") {
|
||||
SECTION("supports JsonVariant") {
|
||||
doc["hello"] = "world";
|
||||
doc["key"] = "hello";
|
||||
|
||||
REQUIRE(doc.containsKey(doc["key"]) == true);
|
||||
REQUIRE(doc.containsKey(doc["foo"]) == false);
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("supports VLAs") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
doc["hello"] = "world";
|
||||
|
||||
REQUIRE(doc.containsKey(vla) == true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("MemberProxy::containsKey()") {
|
||||
JsonDocument doc;
|
||||
auto mp = doc["hello"];
|
||||
const auto& mp = doc["hello"];
|
||||
|
||||
SECTION("containsKey(const char*)") {
|
||||
mp["key"] = "value";
|
||||
@ -70,6 +82,18 @@ TEST_CASE("MemberProxy::containsKey()") {
|
||||
REQUIRE(mp.containsKey("key"_s) == true);
|
||||
REQUIRE(mp.containsKey("key"_s) == true);
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("supports VLAs") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
mp["hello"] = "world";
|
||||
|
||||
REQUIRE(mp.containsKey(vla) == true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("JsonObject::containsKey()") {
|
||||
@ -175,6 +199,18 @@ TEST_CASE("JsonVariant::containsKey()") {
|
||||
REQUIRE(var.containsKey(doc["key"]) == true);
|
||||
REQUIRE(var.containsKey(doc["foo"]) == false);
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("supports VLAs") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
var["hello"] = "world";
|
||||
|
||||
REQUIRE(var.containsKey(vla) == true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("JsonVariantConst::containsKey()") {
|
||||
|
@ -2,7 +2,11 @@
|
||||
# Copyright © 2014-2024, Benoit BLANCHON
|
||||
# MIT License
|
||||
|
||||
macro(build_should_fail target)
|
||||
macro(add_failing_build source_file)
|
||||
get_filename_component(target ${source_file} NAME_WE)
|
||||
|
||||
add_executable(${target} ${source_file})
|
||||
|
||||
set_target_properties(${target}
|
||||
PROPERTIES
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
@ -16,21 +20,13 @@ macro(build_should_fail target)
|
||||
set_tests_properties(${target}
|
||||
PROPERTIES
|
||||
WILL_FAIL TRUE
|
||||
LABELS "WillFail;Catch"
|
||||
LABELS "WillFail"
|
||||
)
|
||||
endmacro()
|
||||
|
||||
add_executable(Issue978 Issue978.cpp)
|
||||
build_should_fail(Issue978)
|
||||
|
||||
add_executable(read_long_long read_long_long.cpp)
|
||||
build_should_fail(read_long_long)
|
||||
|
||||
add_executable(write_long_long write_long_long.cpp)
|
||||
build_should_fail(write_long_long)
|
||||
|
||||
add_executable(variant_as_char variant_as_char.cpp)
|
||||
build_should_fail(variant_as_char)
|
||||
|
||||
add_executable(assign_char assign_char.cpp)
|
||||
build_should_fail(assign_char)
|
||||
add_failing_build(Issue978.cpp)
|
||||
add_failing_build(read_long_long.cpp)
|
||||
add_failing_build(write_long_long.cpp)
|
||||
add_failing_build(variant_as_char.cpp)
|
||||
add_failing_build(assign_char.cpp)
|
||||
add_failing_build(deserialize_object.cpp)
|
||||
|
12
extras/tests/FailingBuilds/deserialize_object.cpp
Normal file
12
extras/tests/FailingBuilds/deserialize_object.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
// See issue #2135
|
||||
|
||||
int main() {
|
||||
JsonObject obj;
|
||||
deserializeJson(obj, "");
|
||||
}
|
@ -13,7 +13,6 @@ add_executable(JsonArrayTests
|
||||
nesting.cpp
|
||||
remove.cpp
|
||||
size.cpp
|
||||
std_string.cpp
|
||||
subscript.cpp
|
||||
unbound.cpp
|
||||
)
|
||||
|
@ -17,31 +17,112 @@ TEST_CASE("JsonArray::add(T)") {
|
||||
|
||||
SECTION("int") {
|
||||
array.add(123);
|
||||
|
||||
REQUIRE(123 == array[0].as<int>());
|
||||
REQUIRE(array[0].is<int>());
|
||||
REQUIRE(array[0].is<double>());
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("double") {
|
||||
array.add(123.45);
|
||||
|
||||
REQUIRE(123.45 == array[0].as<double>());
|
||||
REQUIRE(array[0].is<double>());
|
||||
REQUIRE_FALSE(array[0].is<bool>());
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("bool") {
|
||||
array.add(true);
|
||||
REQUIRE(true == array[0].as<bool>());
|
||||
|
||||
REQUIRE(array[0].as<bool>() == true);
|
||||
REQUIRE(array[0].is<bool>());
|
||||
REQUIRE_FALSE(array[0].is<int>());
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("string literal") {
|
||||
array.add("hello");
|
||||
|
||||
REQUIRE(array[0].as<std::string>() == "hello");
|
||||
REQUIRE(array[0].is<const char*>());
|
||||
REQUIRE(array[0].is<int>() == false);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("std::string") {
|
||||
array.add("hello"_s);
|
||||
|
||||
REQUIRE(array[0].as<std::string>() == "hello");
|
||||
REQUIRE(array[0].is<const char*>() == true);
|
||||
REQUIRE(array[0].is<int>() == false);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
const char* str = "hello";
|
||||
array.add(str);
|
||||
REQUIRE(str == array[0].as<std::string>());
|
||||
REQUIRE(array[0].is<const char*>());
|
||||
REQUIRE_FALSE(array[0].is<int>());
|
||||
|
||||
REQUIRE(array[0].as<std::string>() == "hello");
|
||||
REQUIRE(array[0].as<const char*>() != str);
|
||||
REQUIRE(array[0].is<const char*>() == true);
|
||||
REQUIRE(array[0].is<int>() == false);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("serialized(const char*)") {
|
||||
array.add(serialized("{}"));
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[{}]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("{}")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("serialized(char*)") {
|
||||
array.add(serialized(const_cast<char*>("{}")));
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[{}]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("{}")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("serialized(std::string)") {
|
||||
array.add(serialized("{}"_s));
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[{}]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("{}")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("serialized(std::string)") {
|
||||
array.add(serialized("\0XX"_s));
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[\0XX]"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString(" XX")),
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
@ -52,7 +133,12 @@ TEST_CASE("JsonArray::add(T)") {
|
||||
|
||||
array.add(vla);
|
||||
|
||||
REQUIRE("world"_s == array[0]);
|
||||
strcpy(vla, "hello");
|
||||
REQUIRE(array[0] == "world"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -99,61 +185,6 @@ TEST_CASE("JsonArray::add(T)") {
|
||||
|
||||
REQUIRE(str == array[0]);
|
||||
}
|
||||
|
||||
SECTION("should not duplicate const char*") {
|
||||
array.add("world");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate char*") {
|
||||
array.add(const_cast<char*>("world"));
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate std::string") {
|
||||
array.add("world"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate serialized(const char*)") {
|
||||
array.add(serialized("{}"));
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("{}")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate serialized(char*)") {
|
||||
array.add(serialized(const_cast<char*>("{}")));
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("{}")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate serialized(std::string)") {
|
||||
array.add(serialized("{}"_s));
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("{}")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate serialized(std::string)") {
|
||||
array.add(serialized("\0XX"_s));
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString(" XX")),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JsonArray::add<T>()") {
|
||||
|
@ -1,34 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
static void eraseString(std::string& str) {
|
||||
char* p = const_cast<char*>(str.c_str());
|
||||
while (*p)
|
||||
*p++ = '*';
|
||||
}
|
||||
|
||||
TEST_CASE("std::string") {
|
||||
JsonDocument doc;
|
||||
JsonArray array = doc.to<JsonArray>();
|
||||
|
||||
SECTION("add()") {
|
||||
std::string value("hello");
|
||||
array.add(value);
|
||||
eraseString(value);
|
||||
REQUIRE("hello"_s == array[0]);
|
||||
}
|
||||
|
||||
SECTION("operator[]") {
|
||||
std::string value("world");
|
||||
array.add("hello");
|
||||
array[0] = value;
|
||||
eraseString(value);
|
||||
REQUIRE("world"_s == array[0]);
|
||||
}
|
||||
}
|
@ -59,15 +59,56 @@ TEST_CASE("JsonArray::operator[]") {
|
||||
REQUIRE(false == array[0].is<int>());
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
const char* str = "hello";
|
||||
SECTION("string literal") {
|
||||
array[0] = "hello";
|
||||
|
||||
array[0] = str;
|
||||
REQUIRE(str == array[0].as<const char*>());
|
||||
REQUIRE(array[0].as<std::string>() == "hello");
|
||||
REQUIRE(true == array[0].is<const char*>());
|
||||
REQUIRE(false == array[0].is<int>());
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
const char* str = "hello";
|
||||
array[0] = str;
|
||||
|
||||
REQUIRE(array[0].as<std::string>() == "hello");
|
||||
REQUIRE(true == array[0].is<const char*>());
|
||||
REQUIRE(false == array[0].is<int>());
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("std::string") {
|
||||
array[0] = "hello"_s;
|
||||
|
||||
REQUIRE(array[0].as<std::string>() == "hello");
|
||||
REQUIRE(true == array[0].is<const char*>());
|
||||
REQUIRE(false == array[0].is<int>());
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
array.add("hello");
|
||||
array[0] = vla;
|
||||
|
||||
REQUIRE(array[0] == "world"_s);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("nested array") {
|
||||
JsonDocument doc2;
|
||||
JsonArray arr2 = doc2.to<JsonArray>();
|
||||
@ -114,58 +155,11 @@ TEST_CASE("JsonArray::operator[]") {
|
||||
REQUIRE(str == array[0]);
|
||||
}
|
||||
|
||||
SECTION("should not duplicate const char*") {
|
||||
array[0] = "world";
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate char*") {
|
||||
array[0] = const_cast<char*>("world");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate std::string") {
|
||||
array[0] = "world"_s;
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("array[0].to<JsonObject>()") {
|
||||
JsonObject obj = array[0].to<JsonObject>();
|
||||
REQUIRE(obj.isNull() == false);
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("set(VLA)") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
array.add("hello");
|
||||
array[0].set(vla);
|
||||
|
||||
REQUIRE("world"_s == array[0]);
|
||||
}
|
||||
|
||||
SECTION("operator=(VLA)") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
array.add("hello");
|
||||
array[0] = vla;
|
||||
|
||||
REQUIRE("world"_s == array[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("Use a JsonVariant as index") {
|
||||
array[0] = 1;
|
||||
array[1] = 2;
|
||||
|
@ -693,6 +693,15 @@ TEST_CASE("Filtering") {
|
||||
"null",
|
||||
0,
|
||||
},
|
||||
{
|
||||
"NUL character in key",
|
||||
"{\"x\":0,\"x\\u0000a\":1,\"x\\u0000b\":2}",
|
||||
"{\"x\\u0000a\":true}",
|
||||
10,
|
||||
DeserializationError::Ok,
|
||||
"{\"x\\u0000a\":1}",
|
||||
sizeofObject(1) + sizeofString("x?a"),
|
||||
},
|
||||
};
|
||||
|
||||
for (auto& tc : testCases) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
using ArduinoJson::detail::sizeofObject;
|
||||
|
||||
@ -322,10 +323,11 @@ TEST_CASE("deserialize JSON object") {
|
||||
|
||||
SECTION("NUL in keys") {
|
||||
DeserializationError err =
|
||||
deserializeJson(doc, "{\"x\\u0000a\":1,\"x\\u0000b\":2}");
|
||||
deserializeJson(doc, "{\"x\":0,\"x\\u0000a\":1,\"x\\u0000b\":2}");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "{\"x\\u0000a\":1,\"x\\u0000b\":2}");
|
||||
REQUIRE(doc.as<std::string>() ==
|
||||
"{\"x\":0,\"x\\u0000a\":1,\"x\\u0000b\":2}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ add_executable(JsonDocumentTests
|
||||
nesting.cpp
|
||||
overflowed.cpp
|
||||
remove.cpp
|
||||
set.cpp
|
||||
shrinkToFit.cpp
|
||||
size.cpp
|
||||
subscript.cpp
|
||||
|
@ -5,40 +5,79 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
typedef ArduinoJson::detail::ElementProxy<JsonDocument&> ElementProxy;
|
||||
using ElementProxy = ArduinoJson::detail::ElementProxy<JsonDocument&>;
|
||||
|
||||
TEST_CASE("ElementProxy::add()") {
|
||||
JsonDocument doc;
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc.add<JsonVariant>();
|
||||
ElementProxy ep = doc[0];
|
||||
const ElementProxy& ep = doc[0];
|
||||
|
||||
SECTION("add(int)") {
|
||||
SECTION("integer") {
|
||||
ep.add(42);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[[42]]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("add(const char*)") {
|
||||
SECTION("string literal") {
|
||||
ep.add("world");
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[[\"world\"]]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("set(char[])") {
|
||||
SECTION("const char*") {
|
||||
const char* s = "world";
|
||||
ep.add(s);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[[\"world\"]]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("char[]") {
|
||||
char s[] = "world";
|
||||
ep.add(s);
|
||||
strcpy(s, "!!!!!");
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[[\"world\"]]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("VLA") {
|
||||
size_t i = 8;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
ep.add(vla);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[[\"world\"]]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("ElementProxy::clear()") {
|
||||
JsonDocument doc;
|
||||
doc.add<JsonVariant>();
|
||||
ElementProxy ep = doc[0];
|
||||
const ElementProxy& ep = doc[0];
|
||||
|
||||
SECTION("size goes back to zero") {
|
||||
ep.add(42);
|
||||
@ -98,7 +137,7 @@ TEST_CASE("ElementProxy::operator==()") {
|
||||
TEST_CASE("ElementProxy::remove()") {
|
||||
JsonDocument doc;
|
||||
doc.add<JsonVariant>();
|
||||
ElementProxy ep = doc[0];
|
||||
const ElementProxy& ep = doc[0];
|
||||
|
||||
SECTION("remove(int)") {
|
||||
ep.add(1);
|
||||
@ -145,7 +184,7 @@ TEST_CASE("ElementProxy::remove()") {
|
||||
|
||||
TEST_CASE("ElementProxy::set()") {
|
||||
JsonDocument doc;
|
||||
ElementProxy ep = doc[0];
|
||||
const ElementProxy& ep = doc[0];
|
||||
|
||||
SECTION("set(int)") {
|
||||
ep.set(42);
|
||||
@ -166,12 +205,24 @@ TEST_CASE("ElementProxy::set()") {
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[\"world\"]");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("set(VLA)") {
|
||||
size_t i = 8;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
ep.set(vla);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[\"world\"]");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("ElementProxy::size()") {
|
||||
JsonDocument doc;
|
||||
doc.add<JsonVariant>();
|
||||
ElementProxy ep = doc[0];
|
||||
const ElementProxy& ep = doc[0];
|
||||
|
||||
SECTION("returns 0") {
|
||||
REQUIRE(ep.size() == 0);
|
||||
@ -192,7 +243,7 @@ TEST_CASE("ElementProxy::size()") {
|
||||
|
||||
TEST_CASE("ElementProxy::operator[]") {
|
||||
JsonDocument doc;
|
||||
ElementProxy ep = doc[1];
|
||||
const ElementProxy& ep = doc[1];
|
||||
|
||||
SECTION("set member") {
|
||||
ep["world"] = 42;
|
||||
@ -205,13 +256,25 @@ TEST_CASE("ElementProxy::operator[]") {
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[null,[null,null,42]]");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("set VLA") {
|
||||
size_t i = 8;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
ep[0] = vla;
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[null,[\"world\"]]");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("ElementProxy cast to JsonVariantConst") {
|
||||
JsonDocument doc;
|
||||
doc[0] = "world";
|
||||
|
||||
const ElementProxy ep = doc[0];
|
||||
const ElementProxy& ep = doc[0];
|
||||
|
||||
JsonVariantConst var = ep;
|
||||
|
||||
@ -222,7 +285,7 @@ TEST_CASE("ElementProxy cast to JsonVariant") {
|
||||
JsonDocument doc;
|
||||
doc[0] = "world";
|
||||
|
||||
ElementProxy ep = doc[0];
|
||||
const ElementProxy& ep = doc[0];
|
||||
|
||||
JsonVariant var = ep;
|
||||
|
||||
|
@ -14,29 +14,72 @@
|
||||
using ArduinoJson::detail::sizeofArray;
|
||||
using ArduinoJson::detail::sizeofObject;
|
||||
|
||||
typedef ArduinoJson::detail::MemberProxy<JsonDocument&, const char*>
|
||||
MemberProxy;
|
||||
|
||||
TEST_CASE("MemberProxy::add()") {
|
||||
JsonDocument doc;
|
||||
MemberProxy mp = doc["hello"];
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
const auto& mp = doc["hello"];
|
||||
|
||||
SECTION("add(int)") {
|
||||
SECTION("integer") {
|
||||
mp.add(42);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[42]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("add(const char*)") {
|
||||
SECTION("string literal") {
|
||||
mp.add("world");
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
const char* temp = "world";
|
||||
mp.add(temp);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("char[]") {
|
||||
char temp[] = "world";
|
||||
mp.add(temp);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
mp.add(vla);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("MemberProxy::clear()") {
|
||||
JsonDocument doc;
|
||||
MemberProxy mp = doc["hello"];
|
||||
const auto& mp = doc["hello"];
|
||||
|
||||
SECTION("size goes back to zero") {
|
||||
mp.add(42);
|
||||
@ -127,7 +170,7 @@ TEST_CASE("MemberProxy::operator|()") {
|
||||
|
||||
TEST_CASE("MemberProxy::remove()") {
|
||||
JsonDocument doc;
|
||||
MemberProxy mp = doc["hello"];
|
||||
const auto& mp = doc["hello"];
|
||||
|
||||
SECTION("remove(int)") {
|
||||
mp.add(1);
|
||||
@ -174,7 +217,7 @@ TEST_CASE("MemberProxy::remove()") {
|
||||
|
||||
TEST_CASE("MemberProxy::set()") {
|
||||
JsonDocument doc;
|
||||
MemberProxy mp = doc["hello"];
|
||||
const auto& mp = doc["hello"];
|
||||
|
||||
SECTION("set(int)") {
|
||||
mp.set(42);
|
||||
@ -195,11 +238,23 @@ TEST_CASE("MemberProxy::set()") {
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("set(vla)") {
|
||||
size_t i = 8;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
mp.set(vla);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("MemberProxy::size()") {
|
||||
JsonDocument doc;
|
||||
MemberProxy mp = doc["hello"];
|
||||
const auto& mp = doc["hello"];
|
||||
|
||||
SECTION("returns 0") {
|
||||
REQUIRE(mp.size() == 0);
|
||||
@ -222,7 +277,7 @@ TEST_CASE("MemberProxy::size()") {
|
||||
|
||||
TEST_CASE("MemberProxy::operator[]") {
|
||||
JsonDocument doc;
|
||||
MemberProxy mp = doc["hello"];
|
||||
const auto& mp = doc["hello"];
|
||||
|
||||
SECTION("set member") {
|
||||
mp["world"] = 42;
|
||||
@ -241,7 +296,7 @@ TEST_CASE("MemberProxy cast to JsonVariantConst") {
|
||||
JsonDocument doc;
|
||||
doc["hello"] = "world";
|
||||
|
||||
const MemberProxy mp = doc["hello"];
|
||||
const auto& mp = doc["hello"];
|
||||
|
||||
JsonVariantConst var = mp;
|
||||
|
||||
@ -252,7 +307,7 @@ TEST_CASE("MemberProxy cast to JsonVariant") {
|
||||
JsonDocument doc;
|
||||
doc["hello"] = "world";
|
||||
|
||||
MemberProxy mp = doc["hello"];
|
||||
const auto& mp = doc["hello"];
|
||||
|
||||
JsonVariant var = mp;
|
||||
|
||||
|
@ -26,7 +26,7 @@ TEST_CASE("JsonDocument::add(T)") {
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
SECTION("string literal") {
|
||||
doc.add("hello");
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[\"hello\"]");
|
||||
@ -35,6 +35,17 @@ TEST_CASE("JsonDocument::add(T)") {
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
const char* value = "hello";
|
||||
doc.add(value);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[\"hello\"]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("std::string") {
|
||||
doc.add("example"_s);
|
||||
doc.add("example"_s);
|
||||
@ -79,6 +90,24 @@ TEST_CASE("JsonDocument::add(T)") {
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "example");
|
||||
|
||||
doc.add(vla);
|
||||
doc.add(vla);
|
||||
|
||||
CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
|
||||
REQUIRE("example"_s == doc[0]);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("JsonDocument::add<T>()") {
|
||||
|
@ -12,49 +12,41 @@ TEST_CASE("Issue #1120") {
|
||||
|
||||
SECTION("MemberProxy<std::string>::isNull()") {
|
||||
SECTION("returns false") {
|
||||
auto value = doc["contents"_s];
|
||||
CHECK(value.isNull() == false);
|
||||
CHECK(doc["contents"_s].isNull() == false);
|
||||
}
|
||||
|
||||
SECTION("returns true") {
|
||||
auto value = doc["zontents"_s];
|
||||
CHECK(value.isNull() == true);
|
||||
CHECK(doc["zontents"_s].isNull() == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("ElementProxy<MemberProxy<const char*> >::isNull()") {
|
||||
SECTION("returns false") { // Issue #1120
|
||||
auto value = doc["contents"][1];
|
||||
CHECK(value.isNull() == false);
|
||||
CHECK(doc["contents"][1].isNull() == false);
|
||||
}
|
||||
|
||||
SECTION("returns true") {
|
||||
auto value = doc["contents"][2];
|
||||
CHECK(value.isNull() == true);
|
||||
CHECK(doc["contents"][2].isNull() == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("MemberProxy<ElementProxy<MemberProxy>, const char*>::isNull()") {
|
||||
SECTION("returns false") {
|
||||
auto value = doc["contents"][1]["module"];
|
||||
CHECK(value.isNull() == false);
|
||||
CHECK(doc["contents"][1]["module"].isNull() == false);
|
||||
}
|
||||
|
||||
SECTION("returns true") {
|
||||
auto value = doc["contents"][1]["zodule"];
|
||||
CHECK(value.isNull() == true);
|
||||
CHECK(doc["contents"][1]["zodule"].isNull() == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("MemberProxy<ElementProxy<MemberProxy>, std::string>::isNull()") {
|
||||
SECTION("returns false") {
|
||||
auto value = doc["contents"][1]["module"_s];
|
||||
CHECK(value.isNull() == false);
|
||||
CHECK(doc["contents"][1]["module"_s].isNull() == false);
|
||||
}
|
||||
|
||||
SECTION("returns true") {
|
||||
auto value = doc["contents"][1]["zodule"_s];
|
||||
CHECK(value.isNull() == true);
|
||||
CHECK(doc["contents"][1]["zodule"_s].isNull() == true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,11 +20,21 @@ TEST_CASE("JsonDocument::remove()") {
|
||||
REQUIRE(doc.as<std::string>() == "[1,3]");
|
||||
}
|
||||
|
||||
SECTION("string literal") {
|
||||
doc["a"] = 1;
|
||||
doc["a\0b"_s] = 2;
|
||||
doc["b"] = 3;
|
||||
|
||||
doc.remove("a\0b");
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"a\":1,\"b\":3}");
|
||||
}
|
||||
|
||||
SECTION("remove(const char *)") {
|
||||
doc["a"] = 1;
|
||||
doc["b"] = 2;
|
||||
|
||||
doc.remove("a");
|
||||
doc.remove(static_cast<const char*>("a"));
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"b\":2}");
|
||||
}
|
||||
|
104
extras/tests/JsonDocument/set.cpp
Normal file
104
extras/tests/JsonDocument/set.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
|
||||
#define ARDUINOJSON_ENABLE_PROGMEM 1
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonDocument::set()") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
|
||||
SECTION("nullptr") {
|
||||
doc.set(nullptr);
|
||||
|
||||
REQUIRE(doc.isNull());
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("integer&") {
|
||||
int toto = 42;
|
||||
doc.set(toto);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "42");
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("integer") {
|
||||
doc.set(42);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "42");
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("string literal") {
|
||||
doc.set("example");
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
const char* value = "example";
|
||||
doc.set(value);
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("std::string") {
|
||||
doc.set("example"_s);
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("char*") {
|
||||
char value[] = "example";
|
||||
doc.set(value);
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("Arduino String") {
|
||||
doc.set(String("example"));
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("Flash string") {
|
||||
doc.set(F("example"));
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "example");
|
||||
|
||||
doc.set(vla);
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonDocument::operator[]") {
|
||||
@ -12,28 +13,63 @@ TEST_CASE("JsonDocument::operator[]") {
|
||||
const JsonDocument& cdoc = doc;
|
||||
|
||||
SECTION("object") {
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
doc["abc"_s] = "ABC";
|
||||
doc["abc\0d"_s] = "ABCD";
|
||||
|
||||
SECTION("const char*") {
|
||||
REQUIRE(doc["hello"] == "world");
|
||||
REQUIRE(cdoc["hello"] == "world");
|
||||
const char* key = "abc";
|
||||
REQUIRE(doc[key] == "ABC");
|
||||
REQUIRE(cdoc[key] == "ABC");
|
||||
}
|
||||
|
||||
SECTION("string literal") {
|
||||
REQUIRE(doc["abc"] == "ABC");
|
||||
REQUIRE(cdoc["abc"] == "ABC");
|
||||
REQUIRE(doc["abc\0d"] == "ABCD");
|
||||
REQUIRE(cdoc["abc\0d"] == "ABCD");
|
||||
}
|
||||
|
||||
SECTION("std::string") {
|
||||
REQUIRE(doc["hello"_s] == "world");
|
||||
REQUIRE(cdoc["hello"_s] == "world");
|
||||
REQUIRE(doc["abc"_s] == "ABC");
|
||||
REQUIRE(cdoc["abc"_s] == "ABC");
|
||||
REQUIRE(doc["abc\0d"_s] == "ABCD");
|
||||
REQUIRE(cdoc["abc\0d"_s] == "ABCD");
|
||||
}
|
||||
|
||||
SECTION("JsonVariant") {
|
||||
doc["key"] = "hello";
|
||||
REQUIRE(doc[doc["key"]] == "world");
|
||||
REQUIRE(cdoc[cdoc["key"]] == "world");
|
||||
doc["key1"] = "abc";
|
||||
doc["key2"] = "abc\0d"_s;
|
||||
doc["key3"] = "foo";
|
||||
|
||||
CHECK(doc[doc["key1"]] == "ABC");
|
||||
CHECK(doc[doc["key2"]] == "ABCD");
|
||||
CHECK(doc[doc["key3"]] == nullptr);
|
||||
CHECK(doc[doc["key4"]] == nullptr);
|
||||
|
||||
CHECK(cdoc[cdoc["key1"]] == "ABC");
|
||||
CHECK(cdoc[cdoc["key2"]] == "ABCD");
|
||||
CHECK(cdoc[cdoc["key3"]] == nullptr);
|
||||
CHECK(cdoc[cdoc["key4"]] == nullptr);
|
||||
}
|
||||
|
||||
SECTION("supports operator|") {
|
||||
REQUIRE((doc["hello"] | "nope") == "world"_s);
|
||||
REQUIRE((doc["world"] | "nope") == "nope"_s);
|
||||
REQUIRE((doc["abc"] | "nope") == "ABC"_s);
|
||||
REQUIRE((doc["def"] | "nope") == "nope"_s);
|
||||
}
|
||||
|
||||
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
|
||||
!defined(SUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR)
|
||||
SECTION("supports VLAs") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
doc[vla] = "world";
|
||||
|
||||
REQUIRE(doc[vla] == "world");
|
||||
REQUIRE(cdoc[vla] == "world");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("array") {
|
||||
@ -67,3 +103,65 @@ TEST_CASE("JsonDocument automatically promotes to array") {
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[null,null,2]");
|
||||
}
|
||||
|
||||
TEST_CASE("JsonDocument::operator[] key storage") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
|
||||
SECTION("string literal") {
|
||||
doc["hello"] = 0;
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":0}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
const char* key = "hello";
|
||||
doc[key] = 0;
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":0}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("char[]") {
|
||||
char key[] = "hello";
|
||||
doc[key] = 0;
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":0}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("std::string") {
|
||||
doc["hello"_s] = 0;
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":0}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
|
||||
!defined(SUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR)
|
||||
SECTION("VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
doc[vla] = 0;
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":0}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
}
|
||||
|
||||
SECTION("should duplicate a non-static JsonString key") {
|
||||
obj[JsonString("hello", JsonString::Copied)] = "world";
|
||||
obj[JsonString("hello", false)] = "world";
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
@ -166,7 +166,7 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
}
|
||||
|
||||
SECTION("should not duplicate a static JsonString key") {
|
||||
obj[JsonString("hello", JsonString::Linked)] = "world";
|
||||
obj[JsonString("hello", true)] = "world";
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
@ -253,9 +253,15 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
|
||||
SECTION("JsonVariant") {
|
||||
obj["hello"] = "world";
|
||||
doc["key"] = "hello";
|
||||
obj["a\0b"_s] = "ABC";
|
||||
|
||||
REQUIRE(obj[obj["key"]] == "world");
|
||||
REQUIRE(obj[obj["foo"]] == nullptr);
|
||||
doc["key1"] = "hello";
|
||||
doc["key2"] = "a\0b"_s;
|
||||
doc["key3"] = "foo";
|
||||
|
||||
REQUIRE(obj[obj["key1"]] == "world");
|
||||
REQUIRE(obj[obj["key2"]] == "ABC");
|
||||
REQUIRE(obj[obj["key3"]] == nullptr);
|
||||
REQUIRE(obj[obj["key4"]] == nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
TEST_CASE("JsonObjectConst::operator[]") {
|
||||
JsonDocument doc;
|
||||
doc["hello"] = "world";
|
||||
doc["a\0b"_s] = "ABC";
|
||||
JsonObjectConst obj = doc.as<JsonObjectConst>();
|
||||
|
||||
SECTION("supports const char*") {
|
||||
@ -19,6 +20,7 @@ TEST_CASE("JsonObjectConst::operator[]") {
|
||||
|
||||
SECTION("supports std::string") {
|
||||
REQUIRE(obj["hello"_s] == "world"); // issue #2019
|
||||
REQUIRE(obj["a\0b"_s] == "ABC");
|
||||
}
|
||||
|
||||
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
|
||||
@ -28,13 +30,17 @@ TEST_CASE("JsonObjectConst::operator[]") {
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
REQUIRE("world"_s == obj[vla]);
|
||||
REQUIRE(obj[vla] == "world"_s);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("supports JsonVariant") {
|
||||
doc["key"] = "hello";
|
||||
REQUIRE(obj[obj["key"]] == "world");
|
||||
REQUIRE(obj[obj["foo"]] == nullptr);
|
||||
doc["key1"] = "hello";
|
||||
doc["key2"] = "a\0b"_s;
|
||||
doc["key3"] = "foo";
|
||||
REQUIRE(obj[obj["key1"]] == "world");
|
||||
REQUIRE(obj[obj["key2"]] == "ABC");
|
||||
REQUIRE(obj[obj["key3"]] == nullptr);
|
||||
REQUIRE(obj[obj["key4"]] == nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,18 @@ TEST_CASE("JsonVariant::add(T)") {
|
||||
|
||||
REQUIRE(var.as<std::string>() == "{\"val\":123}");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("supports VLAs") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
var.add(vla);
|
||||
|
||||
REQUIRE(var.as<std::string>() == "[\"hello\"]");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("JsonVariant::add<T>()") {
|
||||
|
@ -184,7 +184,7 @@ TEST_CASE("JsonVariant::as()") {
|
||||
|
||||
REQUIRE(variant.as<long>() == 42L);
|
||||
REQUIRE(variant.as<JsonString>() == "42");
|
||||
REQUIRE(variant.as<JsonString>().isLinked() == true);
|
||||
REQUIRE(variant.as<JsonString>().isStatic() == true);
|
||||
}
|
||||
|
||||
SECTION("set(\"hello\")") {
|
||||
@ -207,7 +207,7 @@ TEST_CASE("JsonVariant::as()") {
|
||||
REQUIRE(variant.as<const char*>() == "4.2"_s);
|
||||
REQUIRE(variant.as<std::string>() == "4.2"_s);
|
||||
REQUIRE(variant.as<JsonString>() == "4.2");
|
||||
REQUIRE(variant.as<JsonString>().isLinked() == false);
|
||||
REQUIRE(variant.as<JsonString>().isStatic() == false);
|
||||
}
|
||||
|
||||
SECTION("set(\"true\")") {
|
||||
|
@ -83,6 +83,23 @@ TEST_CASE("JsonVariant::remove(std::string)") {
|
||||
REQUIRE(var.as<std::string>() == "{\"a\":1}");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
TEST_CASE("JsonVariant::remove(VLA)") {
|
||||
JsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
|
||||
var["a"] = 1;
|
||||
var["b"] = 2;
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "b");
|
||||
|
||||
var.remove("b"_s);
|
||||
|
||||
REQUIRE(var.as<std::string>() == "{\"a\":1}");
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("JsonVariant::remove(JsonVariant) from object") {
|
||||
JsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
|
@ -17,6 +17,15 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
JsonDocument doc(&spy);
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
SECTION("string literal") {
|
||||
bool result = variant.set("hello\0world");
|
||||
|
||||
REQUIRE(result == true);
|
||||
CHECK(variant ==
|
||||
"hello"_s); // linked string cannot contain '\0' at the moment
|
||||
CHECK(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
char str[16];
|
||||
|
||||
@ -25,8 +34,10 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
strcpy(str, "world");
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant == "world"); // stores by pointer
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
REQUIRE(variant == "hello"); // stores by copy
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("(const char*)0") {
|
||||
@ -34,6 +45,7 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant.isNull());
|
||||
REQUIRE(variant.as<const char*>() == nullptr);
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
@ -105,16 +117,14 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
#endif
|
||||
|
||||
SECTION("std::string") {
|
||||
std::string str;
|
||||
|
||||
str = "hello";
|
||||
std::string str = "hello\0world"_s;
|
||||
bool result = variant.set(str);
|
||||
str.replace(0, 5, "world");
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant == "hello"); // stores by copy
|
||||
REQUIRE(variant == "hello\0world"_s); // stores by copy
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofString("hello?world")),
|
||||
});
|
||||
}
|
||||
|
||||
@ -122,7 +132,7 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
char str[16];
|
||||
|
||||
strcpy(str, "hello");
|
||||
bool result = variant.set(JsonString(str, JsonString::Linked));
|
||||
bool result = variant.set(JsonString(str, true));
|
||||
strcpy(str, "world");
|
||||
|
||||
REQUIRE(result == true);
|
||||
@ -134,7 +144,7 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
char str[16];
|
||||
|
||||
strcpy(str, "hello");
|
||||
bool result = variant.set(JsonString(str, JsonString::Copied));
|
||||
bool result = variant.set(JsonString(str));
|
||||
strcpy(str, "world");
|
||||
|
||||
REQUIRE(result == true);
|
||||
|
@ -99,7 +99,7 @@ TEST_CASE("vector<int>") {
|
||||
}
|
||||
|
||||
TEST_CASE("array<int, 2>") {
|
||||
typedef std::array<int, 2> array_type;
|
||||
using array_type = std::array<int, 2>;
|
||||
|
||||
SECTION("toJson") {
|
||||
array_type v;
|
||||
|
@ -116,12 +116,19 @@ TEST_CASE("JsonVariant::operator[]") {
|
||||
}
|
||||
|
||||
SECTION("use JsonVariant as key") {
|
||||
object["a"] = "a";
|
||||
object["b"] = "b";
|
||||
object["c"] = "b";
|
||||
object["a"] = "A";
|
||||
object["ab"] = "AB";
|
||||
object["ab\0c"_s] = "ABC";
|
||||
object["key1"] = "a";
|
||||
object["key2"] = "ab";
|
||||
object["key3"] = "ab\0c"_s;
|
||||
object["key4"] = "foo";
|
||||
|
||||
REQUIRE(var[var["c"]] == "b");
|
||||
REQUIRE(var[var["d"]].isNull());
|
||||
REQUIRE(var[var["key1"]] == "A");
|
||||
REQUIRE(var[var["key2"]] == "AB");
|
||||
REQUIRE(var[var["key3"]] == "ABC");
|
||||
REQUIRE(var[var["key4"]].isNull());
|
||||
REQUIRE(var[var["key5"]].isNull());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,14 +7,8 @@
|
||||
#include <catch.hpp>
|
||||
#include <limits>
|
||||
|
||||
template <typename T>
|
||||
void checkValue(T expected) {
|
||||
JsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
variant.set(expected);
|
||||
REQUIRE(expected == variant.as<T>());
|
||||
}
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
template <typename T>
|
||||
void checkReference(T& expected) {
|
||||
@ -39,27 +33,29 @@ void checkNumericType() {
|
||||
}
|
||||
|
||||
TEST_CASE("JsonVariant set()/get()") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
SECTION("SizeOfJsonInteger") {
|
||||
REQUIRE(8 == sizeof(JsonInteger));
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("Null") {
|
||||
checkValue<const char*>(NULL);
|
||||
}
|
||||
SECTION("const char*") {
|
||||
checkValue<const char*>("hello");
|
||||
}
|
||||
SECTION("std::string") {
|
||||
checkValue<std::string>("hello");
|
||||
}
|
||||
// /!\ Most test were moved to `JsonVariant/set.cpp`
|
||||
// TODO: move the remaining tests too
|
||||
|
||||
SECTION("False") {
|
||||
checkValue<bool>(false);
|
||||
variant.set(false);
|
||||
REQUIRE(variant.as<bool>() == false);
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("True") {
|
||||
checkValue<bool>(true);
|
||||
variant.set(true);
|
||||
REQUIRE(variant.as<bool>() == true);
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("Double") {
|
||||
@ -129,10 +125,12 @@ TEST_CASE("JsonVariant set()/get()") {
|
||||
#endif
|
||||
|
||||
SECTION("CanStoreObject") {
|
||||
JsonDocument doc;
|
||||
JsonObject object = doc.to<JsonObject>();
|
||||
JsonDocument doc2;
|
||||
JsonObject object = doc2.to<JsonObject>();
|
||||
|
||||
checkValue<JsonObject>(object);
|
||||
variant.set(object);
|
||||
REQUIRE(variant.is<JsonObject>());
|
||||
REQUIRE(variant.as<JsonObject>() == object);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,20 +50,31 @@ TEST_CASE("JsonVariantConst::operator[]") {
|
||||
|
||||
SECTION("object") {
|
||||
JsonObject object = doc.to<JsonObject>();
|
||||
object["a"] = "A";
|
||||
object["b"] = "B";
|
||||
object["ab"_s] = "AB";
|
||||
object["abc"_s] = "ABC";
|
||||
object["abc\0d"_s] = "ABCD";
|
||||
|
||||
SECTION("supports const char*") {
|
||||
REQUIRE("A"_s == var["a"]);
|
||||
REQUIRE("B"_s == var["b"]);
|
||||
REQUIRE(var["c"].isNull());
|
||||
SECTION("string literal") {
|
||||
REQUIRE(var["ab"] == "AB"_s);
|
||||
REQUIRE(var["abc"] == "ABC"_s);
|
||||
REQUIRE(var["abc\0d"] == "ABCD"_s);
|
||||
REQUIRE(var["def"].isNull());
|
||||
REQUIRE(var[0].isNull());
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
REQUIRE(var[static_cast<const char*>("ab")] == "AB"_s);
|
||||
REQUIRE(var[static_cast<const char*>("abc")] == "ABC"_s);
|
||||
REQUIRE(var[static_cast<const char*>("abc\0d")] == "ABC"_s);
|
||||
REQUIRE(var[static_cast<const char*>("def")].isNull());
|
||||
REQUIRE(var[static_cast<const char*>(0)].isNull());
|
||||
}
|
||||
|
||||
SECTION("supports std::string") {
|
||||
REQUIRE("A"_s == var["a"_s]);
|
||||
REQUIRE("B"_s == var["b"_s]);
|
||||
REQUIRE(var["c"_s].isNull());
|
||||
REQUIRE(var["ab"_s] == "AB"_s);
|
||||
REQUIRE(var["abc"_s] == "ABC"_s);
|
||||
REQUIRE(var["abc\0d"_s] == "ABCD"_s);
|
||||
REQUIRE(var["def"_s].isNull());
|
||||
}
|
||||
|
||||
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
|
||||
@ -71,16 +82,23 @@ TEST_CASE("JsonVariantConst::operator[]") {
|
||||
SECTION("supports VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "a");
|
||||
strcpy(vla, "abc");
|
||||
|
||||
REQUIRE("A"_s == var[vla]);
|
||||
REQUIRE(var[vla] == "ABC"_s);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("supports JsonVariant") {
|
||||
object["c"] = "b";
|
||||
REQUIRE(var[var["c"]] == "B");
|
||||
REQUIRE(var[var["d"]].isNull());
|
||||
object["key1"] = "ab";
|
||||
object["key2"] = "abc";
|
||||
object["key3"] = "abc\0d"_s;
|
||||
object["key4"] = "foo";
|
||||
|
||||
REQUIRE(var[var["key1"]] == "AB"_s);
|
||||
REQUIRE(var[var["key2"]] == "ABC"_s);
|
||||
REQUIRE(var[var["key3"]] == "ABCD"_s);
|
||||
REQUIRE(var[var["key4"]].isNull());
|
||||
REQUIRE(var[var["key5"]].isNull());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ add_executable(MiscTests
|
||||
arithmeticCompare.cpp
|
||||
conflicts.cpp
|
||||
issue1967.cpp
|
||||
issue2129.cpp
|
||||
JsonString.cpp
|
||||
NoArduinoHeader.cpp
|
||||
printable.cpp
|
||||
|
@ -13,7 +13,7 @@ TEST_CASE("JsonString") {
|
||||
|
||||
CHECK(s.isNull() == true);
|
||||
CHECK(s.c_str() == 0);
|
||||
CHECK(s.isLinked() == true);
|
||||
CHECK(s.isStatic() == true);
|
||||
CHECK(s == JsonString());
|
||||
CHECK(s != "");
|
||||
}
|
||||
@ -96,7 +96,7 @@ TEST_CASE("JsonString") {
|
||||
JsonString s("hello world", 5);
|
||||
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isLinked() == true);
|
||||
CHECK(s.isStatic() == false);
|
||||
CHECK(s == "hello");
|
||||
CHECK(s != "hello world");
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <ArduinoJson/Strings/IsString.hpp>
|
||||
#include <ArduinoJson/Strings/JsonString.hpp>
|
||||
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||
|
||||
#include <catch.hpp>
|
||||
@ -12,77 +13,110 @@
|
||||
#include "custom_string.hpp"
|
||||
#include "weird_strcmp.hpp"
|
||||
|
||||
using ArduinoJson::JsonString;
|
||||
using namespace ArduinoJson::detail;
|
||||
|
||||
TEST_CASE("ZeroTerminatedRamString") {
|
||||
SECTION("null") {
|
||||
ZeroTerminatedRamString s = adaptString(static_cast<const char*>(0));
|
||||
TEST_CASE("adaptString()") {
|
||||
SECTION("string literal") {
|
||||
auto s = adaptString("bravo\0alpha");
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 11);
|
||||
CHECK(s.isStatic() == true);
|
||||
}
|
||||
|
||||
SECTION("null const char*") {
|
||||
auto s = adaptString(static_cast<const char*>(0));
|
||||
|
||||
CHECK(s.isNull() == true);
|
||||
CHECK(s.size() == 0);
|
||||
}
|
||||
|
||||
SECTION("non-null") {
|
||||
ZeroTerminatedRamString s = adaptString("bravo");
|
||||
SECTION("non-null const char*") {
|
||||
const char* p = "bravo";
|
||||
auto s = adaptString(p);
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isStatic() == false);
|
||||
CHECK(s.data() == p);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("SizedRamString") {
|
||||
SECTION("null") {
|
||||
SizedRamString s = adaptString(static_cast<const char*>(0), 10);
|
||||
SECTION("null const char* + size") {
|
||||
auto s = adaptString(static_cast<const char*>(0), 10);
|
||||
|
||||
CHECK(s.isNull() == true);
|
||||
CHECK(s.isStatic() == false);
|
||||
}
|
||||
|
||||
SECTION("non-null") {
|
||||
SizedRamString s = adaptString("bravo", 5);
|
||||
SECTION("non-null const char* + size") {
|
||||
auto s = adaptString("bravo", 5);
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isStatic() == false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("FlashString") {
|
||||
SECTION("null") {
|
||||
FlashString s = adaptString(static_cast<const __FlashStringHelper*>(0));
|
||||
SECTION("null Flash string") {
|
||||
auto s = adaptString(static_cast<const __FlashStringHelper*>(0));
|
||||
|
||||
CHECK(s.isNull() == true);
|
||||
CHECK(s.size() == 0);
|
||||
CHECK(s.isStatic() == false);
|
||||
}
|
||||
|
||||
SECTION("non-null") {
|
||||
FlashString s = adaptString(F("bravo"));
|
||||
SECTION("non-null Flash string") {
|
||||
auto s = adaptString(F("bravo"));
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isStatic() == false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("std::string") {
|
||||
std::string orig("bravo");
|
||||
SizedRamString s = adaptString(orig);
|
||||
SECTION("std::string") {
|
||||
std::string orig("bravo");
|
||||
auto s = adaptString(orig);
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
}
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isStatic() == false);
|
||||
}
|
||||
|
||||
TEST_CASE("Arduino String") {
|
||||
::String orig("bravo");
|
||||
SizedRamString s = adaptString(orig);
|
||||
SECTION("Arduino String") {
|
||||
::String orig("bravo");
|
||||
auto s = adaptString(orig);
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
}
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isStatic() == false);
|
||||
}
|
||||
|
||||
TEST_CASE("custom_string") {
|
||||
custom_string orig("bravo");
|
||||
SizedRamString s = adaptString(orig);
|
||||
SECTION("custom_string") {
|
||||
custom_string orig("bravo");
|
||||
auto s = adaptString(orig);
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isStatic() == false);
|
||||
}
|
||||
|
||||
SECTION("JsonString linked") {
|
||||
JsonString orig("hello", true);
|
||||
auto s = adaptString(orig);
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isStatic() == true);
|
||||
}
|
||||
|
||||
SECTION("JsonString copied") {
|
||||
JsonString orig("hello", false);
|
||||
auto s = adaptString(orig);
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isStatic() == false);
|
||||
}
|
||||
}
|
||||
|
||||
struct EmptyStruct {};
|
||||
@ -97,6 +131,7 @@ TEST_CASE("IsString<T>") {
|
||||
CHECK(IsString<::String>::value == true);
|
||||
CHECK(IsString<::StringSumHelper>::value == true);
|
||||
CHECK(IsString<const EmptyStruct*>::value == false);
|
||||
CHECK(IsString<JsonString>::value == true);
|
||||
}
|
||||
|
||||
TEST_CASE("stringCompare") {
|
||||
|
@ -211,6 +211,23 @@ TEST_CASE("Polyfills/type_traits") {
|
||||
CHECK(is_enum<bool>::value == false);
|
||||
CHECK(is_enum<double>::value == false);
|
||||
}
|
||||
|
||||
SECTION("remove_cv") {
|
||||
CHECK(is_same<remove_cv_t<const int>, int>::value);
|
||||
CHECK(is_same<remove_cv_t<volatile int>, int>::value);
|
||||
CHECK(is_same<remove_cv_t<const volatile int>, int>::value);
|
||||
CHECK(is_same<remove_cv_t<int>, int>::value);
|
||||
CHECK(is_same<remove_cv_t<decltype("toto")>, decltype("toto")>::value);
|
||||
}
|
||||
|
||||
SECTION("decay") {
|
||||
CHECK(is_same<decay_t<int>, int>::value);
|
||||
CHECK(is_same<decay_t<int&>, int>::value);
|
||||
CHECK(is_same<decay_t<int&&>, int>::value);
|
||||
CHECK(is_same<decay_t<int[]>, int*>::value);
|
||||
CHECK(is_same<decay_t<int[10]>, int*>::value);
|
||||
CHECK(is_same<decay_t<decltype("toto")>, const char*>::value);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("is_std_string") {
|
||||
|
@ -8,4 +8,4 @@
|
||||
|
||||
struct custom_char_traits : std::char_traits<char> {};
|
||||
|
||||
typedef std::basic_string<char, custom_char_traits> custom_string;
|
||||
using custom_string = std::basic_string<char, custom_char_traits>;
|
||||
|
55
extras/tests/Misc/issue2129.cpp
Normal file
55
extras/tests/Misc/issue2129.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
template <typename T>
|
||||
class Nullable {
|
||||
public:
|
||||
Nullable() : value_{} {}
|
||||
Nullable(T value) : value_{value} {}
|
||||
|
||||
operator T() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
operator T&() {
|
||||
return value_;
|
||||
}
|
||||
|
||||
bool is_valid() const {
|
||||
return value_ != invalid_value_;
|
||||
}
|
||||
|
||||
T value() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
static T invalid_value_;
|
||||
};
|
||||
|
||||
template <>
|
||||
float Nullable<float>::invalid_value_ = std::numeric_limits<float>::lowest();
|
||||
|
||||
template <typename T>
|
||||
void convertToJson(const Nullable<T>& src, JsonVariant dst) {
|
||||
if (src.is_valid()) {
|
||||
dst.set(src.value());
|
||||
} else {
|
||||
dst.clear();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Issue #2129") {
|
||||
Nullable<float> nullable_value = Nullable<float>{123.4f};
|
||||
|
||||
JsonDocument doc;
|
||||
|
||||
doc["value"] = nullable_value;
|
||||
|
||||
REQUIRE(doc["value"].as<float>() == Approx(123.4f));
|
||||
}
|
@ -139,7 +139,8 @@ TEST_CASE("serialize MsgPack value") {
|
||||
|
||||
SECTION("str 32") {
|
||||
std::string shortest(65536, '?');
|
||||
checkVariant(shortest.c_str(), "\xDB\x00\x01\x00\x00"_s + shortest);
|
||||
checkVariant(JsonString(shortest.c_str(), true), // force store by pointer
|
||||
"\xDB\x00\x01\x00\x00"_s + shortest);
|
||||
}
|
||||
|
||||
SECTION("serialized(const char*)") {
|
||||
|
@ -1,7 +1,7 @@
|
||||
version: "7.2.0"
|
||||
version: "7.3.0"
|
||||
description: >-
|
||||
A simple and efficient JSON library for embedded C++.
|
||||
⭐ 6690 stars on GitHub!
|
||||
★ 6785 stars on GitHub!
|
||||
Supports serialization, deserialization, MessagePack, streams, filtering, and more.
|
||||
Fully tested and documented.
|
||||
url: https://arduinojson.org/
|
||||
|
@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "ArduinoJson",
|
||||
"keywords": "json, rest, http, web",
|
||||
"description": "A simple and efficient JSON library for embedded C++. ⭐ 6690 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.",
|
||||
"description": "A simple and efficient JSON library for embedded C++. ⭐ 6785 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.",
|
||||
"homepage": "https://arduinojson.org/?utm_source=meta&utm_medium=library.json",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bblanchon/ArduinoJson.git"
|
||||
},
|
||||
"version": "7.2.0",
|
||||
"version": "7.3.0",
|
||||
"authors": {
|
||||
"name": "Benoit Blanchon",
|
||||
"url": "https://blog.benoitblanchon.fr"
|
||||
|
@ -1,9 +1,9 @@
|
||||
name=ArduinoJson
|
||||
version=7.2.0
|
||||
version=7.3.0
|
||||
author=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
sentence=A simple and efficient JSON library for embedded C++.
|
||||
paragraph=⭐ 6690 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.
|
||||
paragraph=⭐ 6785 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.
|
||||
category=Data Processing
|
||||
url=https://arduinojson.org/?utm_source=meta&utm_medium=library.properties
|
||||
architectures=*
|
||||
|
@ -19,10 +19,10 @@ class ArrayData : public CollectionData {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool addValue(T&& value, ResourceManager* resources);
|
||||
bool addValue(const T& value, ResourceManager* resources);
|
||||
|
||||
template <typename T>
|
||||
static bool addValue(ArrayData* array, T&& value,
|
||||
static bool addValue(ArrayData* array, const T& value,
|
||||
ResourceManager* resources) {
|
||||
if (!array)
|
||||
return false;
|
||||
|
@ -57,13 +57,13 @@ inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool ArrayData::addValue(T&& value, ResourceManager* resources) {
|
||||
inline bool ArrayData::addValue(const T& value, ResourceManager* resources) {
|
||||
ARDUINOJSON_ASSERT(resources != nullptr);
|
||||
auto slot = resources->allocVariant();
|
||||
if (!slot)
|
||||
return false;
|
||||
JsonVariant variant(slot.ptr(), resources);
|
||||
if (!variant.set(detail::forward<T>(value))) {
|
||||
if (!variant.set(value)) {
|
||||
resources->freeVariant(slot);
|
||||
return false;
|
||||
}
|
||||
|
@ -15,13 +15,18 @@ class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
|
||||
public VariantOperators<ElementProxy<TUpstream>> {
|
||||
friend class VariantAttorney;
|
||||
|
||||
friend class VariantRefBase<ElementProxy<TUpstream>>;
|
||||
|
||||
template <typename, typename>
|
||||
friend class MemberProxy;
|
||||
|
||||
template <typename>
|
||||
friend class ElementProxy;
|
||||
|
||||
public:
|
||||
ElementProxy(TUpstream upstream, size_t index)
|
||||
: upstream_(upstream), index_(index) {}
|
||||
|
||||
ElementProxy(const ElementProxy& src)
|
||||
: upstream_(src.upstream_), index_(src.index_) {}
|
||||
|
||||
ElementProxy& operator=(const ElementProxy& src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
@ -40,6 +45,11 @@ class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
|
||||
}
|
||||
|
||||
private:
|
||||
// clang-format off
|
||||
ElementProxy(const ElementProxy& src) // Error here? See https://arduinojson.org/v7/proxy-non-copyable/
|
||||
: upstream_(src.upstream_), index_(src.index_) {}
|
||||
// clang-format on
|
||||
|
||||
ResourceManager* getResourceManager() const {
|
||||
return VariantAttorney::getResourceManager(upstream_);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
typedef JsonArrayIterator iterator;
|
||||
using iterator = JsonArrayIterator;
|
||||
|
||||
// Constructs an unbound reference.
|
||||
JsonArray() : data_(0), resources_(0) {}
|
||||
@ -43,16 +43,18 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
// Appends a new (empty) element to the array.
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||
template <typename T>
|
||||
detail::enable_if_t<!detail::is_same<T, JsonVariant>::value, T> add() const {
|
||||
template <typename T, detail::enable_if_t<
|
||||
!detail::is_same<T, JsonVariant>::value, int> = 0>
|
||||
T add() const {
|
||||
return add<JsonVariant>().to<T>();
|
||||
}
|
||||
|
||||
// Appends a new (null) element to the array.
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||
template <typename T>
|
||||
detail::enable_if_t<detail::is_same<T, JsonVariant>::value, T> add() const {
|
||||
template <typename T, detail::enable_if_t<
|
||||
detail::is_same<T, JsonVariant>::value, int> = 0>
|
||||
JsonVariant add() const {
|
||||
return JsonVariant(detail::ArrayData::addElement(data_, resources_),
|
||||
resources_);
|
||||
}
|
||||
@ -66,7 +68,8 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
|
||||
// Appends a value to the array.
|
||||
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||
template <typename T>
|
||||
template <typename T,
|
||||
detail::enable_if_t<!detail::is_const<T>::value, int> = 0>
|
||||
bool add(T* value) const {
|
||||
return detail::ArrayData::addValue(data_, value, resources_);
|
||||
}
|
||||
@ -114,9 +117,9 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
|
||||
// Removes the element at the specified index.
|
||||
// https://arduinojson.org/v7/api/jsonarray/remove/
|
||||
template <typename TVariant>
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value> remove(
|
||||
TVariant variant) const {
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
void remove(const TVariant& variant) const {
|
||||
if (variant.template is<size_t>())
|
||||
remove(variant.template as<size_t>());
|
||||
}
|
||||
@ -129,21 +132,19 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
|
||||
// Gets or sets the element at the specified index.
|
||||
// https://arduinojson.org/v7/api/jsonarray/subscript/
|
||||
template <typename T>
|
||||
detail::enable_if_t<detail::is_integral<T>::value,
|
||||
detail::ElementProxy<JsonArray>>
|
||||
operator[](T index) const {
|
||||
template <typename T,
|
||||
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||
detail::ElementProxy<JsonArray> 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 TVariant>
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value,
|
||||
detail::ElementProxy<JsonArray>>
|
||||
operator[](const TVariant& variant) const {
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
detail::ElementProxy<JsonArray> operator[](const TVariant& variant) const {
|
||||
if (variant.template is<size_t>())
|
||||
return operator[](variant.template as<size_t>());
|
||||
return {*this, variant.template as<size_t>()};
|
||||
else
|
||||
return {*this, size_t(-1)};
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
typedef JsonArrayConstIterator iterator;
|
||||
using iterator = JsonArrayConstIterator;
|
||||
|
||||
// Returns an iterator to the first element of the array.
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/begin/
|
||||
@ -45,9 +45,9 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
||||
|
||||
// Returns the element at the specified index.
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/subscript/
|
||||
template <typename T>
|
||||
detail::enable_if_t<detail::is_integral<T>::value, JsonVariantConst>
|
||||
operator[](T index) const {
|
||||
template <typename T,
|
||||
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||
JsonVariantConst operator[](T index) const {
|
||||
return JsonVariantConst(
|
||||
detail::ArrayData::getElement(data_, size_t(index), resources_),
|
||||
resources_);
|
||||
@ -55,9 +55,9 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
||||
|
||||
// Returns the element at the specified index.
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/subscript/
|
||||
template <typename TVariant>
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, JsonVariantConst>
|
||||
operator[](const TVariant& variant) const {
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
JsonVariantConst operator[](const TVariant& variant) const {
|
||||
if (variant.template is<size_t>())
|
||||
return operator[](variant.template as<size_t>());
|
||||
else
|
||||
|
@ -11,27 +11,26 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Copies a value to a JsonVariant.
|
||||
// This is a degenerated form of copyArray() to stop the recursion.
|
||||
template <typename T>
|
||||
inline detail::enable_if_t<!detail::is_array<T>::value, bool> copyArray(
|
||||
const T& src, JsonVariant dst) {
|
||||
template <typename T, detail::enable_if_t<!detail::is_array<T>::value, int> = 0>
|
||||
inline bool copyArray(const T& src, JsonVariant dst) {
|
||||
return dst.set(src);
|
||||
}
|
||||
|
||||
// Copies values from an array to a JsonArray or a JsonVariant.
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T, size_t N, typename TDestination>
|
||||
inline detail::enable_if_t<
|
||||
!detail::is_base_of<JsonDocument, TDestination>::value, bool>
|
||||
copyArray(T (&src)[N], const TDestination& dst) {
|
||||
template <typename T, size_t N, typename TDestination,
|
||||
detail::enable_if_t<
|
||||
!detail::is_base_of<JsonDocument, TDestination>::value, int> = 0>
|
||||
inline bool copyArray(T (&src)[N], const TDestination& dst) {
|
||||
return copyArray(src, N, dst);
|
||||
}
|
||||
|
||||
// Copies values from an array to a JsonArray or a JsonVariant.
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T, typename TDestination>
|
||||
inline detail::enable_if_t<
|
||||
!detail::is_base_of<JsonDocument, TDestination>::value, bool>
|
||||
copyArray(const T* src, size_t len, const TDestination& dst) {
|
||||
template <typename T, typename TDestination,
|
||||
detail::enable_if_t<
|
||||
!detail::is_base_of<JsonDocument, TDestination>::value, int> = 0>
|
||||
inline bool copyArray(const T* src, size_t len, const TDestination& dst) {
|
||||
bool ok = true;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
ok &= copyArray(src[i], dst.template add<JsonVariant>());
|
||||
@ -62,9 +61,8 @@ inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
|
||||
|
||||
// Copies a value from a JsonVariant.
|
||||
// This is a degenerated form of copyArray() to stop the recursion.
|
||||
template <typename T>
|
||||
inline detail::enable_if_t<!detail::is_array<T>::value, size_t> copyArray(
|
||||
JsonVariantConst src, T& dst) {
|
||||
template <typename T, detail::enable_if_t<!detail::is_array<T>::value, int> = 0>
|
||||
inline size_t copyArray(JsonVariantConst src, T& dst) {
|
||||
dst = src.as<T>();
|
||||
return 1;
|
||||
}
|
||||
@ -102,11 +100,12 @@ inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) {
|
||||
|
||||
// Copies values from a JsonDocument to an array.
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename TSource, typename T>
|
||||
inline detail::enable_if_t<detail::is_array<T>::value &&
|
||||
detail::is_base_of<JsonDocument, TSource>::value,
|
||||
size_t>
|
||||
copyArray(const TSource& src, T& dst) {
|
||||
template <
|
||||
typename TSource, typename T,
|
||||
detail::enable_if_t<detail::is_array<T>::value &&
|
||||
detail::is_base_of<JsonDocument, TSource>::value,
|
||||
int> = 0>
|
||||
inline size_t copyArray(const TSource& src, T& dst) {
|
||||
return copyArray(src.template as<JsonArrayConst>(), dst);
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// The default reader is a simple wrapper for Readers that are not copiable
|
||||
// The default reader is a simple wrapper for Readers that are not copyable
|
||||
template <typename TSource, typename Enable = void>
|
||||
struct Reader {
|
||||
public:
|
||||
|
@ -24,14 +24,10 @@ struct first_or_void<T, Rest...> {
|
||||
|
||||
// A meta-function that returns true if T is a valid destination type for
|
||||
// deserialize()
|
||||
template <class T, class = void>
|
||||
struct is_deserialize_destination : false_type {};
|
||||
|
||||
template <class T>
|
||||
struct is_deserialize_destination<
|
||||
T, enable_if_t<is_same<decltype(VariantAttorney::getResourceManager(
|
||||
detail::declval<T&>())),
|
||||
ResourceManager*>::value>> : true_type {};
|
||||
using is_deserialize_destination =
|
||||
bool_constant<is_base_of<JsonDocument, remove_cv_t<T>>::value ||
|
||||
IsVariant<T>::value>;
|
||||
|
||||
template <typename TDestination>
|
||||
inline void shrinkJsonDocument(TDestination&) {
|
||||
@ -59,10 +55,11 @@ DeserializationError doDeserialize(TDestination&& dst, TReader reader,
|
||||
return err;
|
||||
}
|
||||
|
||||
template <template <typename> class TDeserializer, typename TDestination,
|
||||
typename TStream, typename... Args,
|
||||
typename = enable_if_t< // issue #1897
|
||||
!is_integral<typename first_or_void<Args...>::type>::value>>
|
||||
template <
|
||||
template <typename> class TDeserializer, typename TDestination,
|
||||
typename TStream, typename... Args,
|
||||
enable_if_t< // issue #1897
|
||||
!is_integral<typename first_or_void<Args...>::type>::value, int> = 0>
|
||||
DeserializationError deserialize(TDestination&& dst, TStream&& input,
|
||||
Args... args) {
|
||||
return doDeserialize<TDeserializer>(
|
||||
@ -72,7 +69,7 @@ DeserializationError deserialize(TDestination&& dst, TStream&& input,
|
||||
|
||||
template <template <typename> class TDeserializer, typename TDestination,
|
||||
typename TChar, typename Size, typename... Args,
|
||||
typename = enable_if_t<is_integral<Size>::value>>
|
||||
enable_if_t<is_integral<Size>::value, int> = 0>
|
||||
DeserializationError deserialize(TDestination&& dst, TChar* input,
|
||||
Size inputSize, Args... args) {
|
||||
return doDeserialize<TDeserializer>(dst, makeReader(input, size_t(inputSize)),
|
||||
|
@ -36,14 +36,15 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
}
|
||||
|
||||
// Construct from variant, array, or object
|
||||
template <typename T>
|
||||
JsonDocument(
|
||||
const T& src, Allocator* alloc = detail::DefaultAllocator::instance(),
|
||||
detail::enable_if_t<detail::IsVariant<T>::value ||
|
||||
detail::is_same<T, JsonArray>::value ||
|
||||
detail::is_same<T, JsonArrayConst>::value ||
|
||||
detail::is_same<T, JsonObject>::value ||
|
||||
detail::is_same<T, JsonObjectConst>::value>* = 0)
|
||||
template <typename T,
|
||||
detail::enable_if_t<detail::IsVariant<T>::value ||
|
||||
detail::is_same<T, JsonArray>::value ||
|
||||
detail::is_same<T, JsonArrayConst>::value ||
|
||||
detail::is_same<T, JsonObject>::value ||
|
||||
detail::is_same<T, JsonObjectConst>::value,
|
||||
int> = 0>
|
||||
JsonDocument(const T& src,
|
||||
Allocator* alloc = detail::DefaultAllocator::instance())
|
||||
: JsonDocument(alloc) {
|
||||
set(src);
|
||||
}
|
||||
@ -136,9 +137,18 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
|
||||
// Replaces the root with the specified value.
|
||||
// https://arduinojson.org/v7/api/jsondocument/set/
|
||||
template <typename T>
|
||||
detail::enable_if_t<!detail::is_base_of<JsonDocument, T>::value, bool> set(
|
||||
const T& src) {
|
||||
template <
|
||||
typename T,
|
||||
detail::enable_if_t<!detail::is_base_of<JsonDocument, T>::value, int> = 0>
|
||||
bool set(const T& src) {
|
||||
return to<JsonVariant>().set(src);
|
||||
}
|
||||
|
||||
// Replaces the root with the specified value.
|
||||
// https://arduinojson.org/v7/api/jsondocument/set/
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<!detail::is_const<TChar>::value, int> = 0>
|
||||
bool set(TChar* src) {
|
||||
return to<JsonVariant>().set(src);
|
||||
}
|
||||
|
||||
@ -160,64 +170,67 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsondocument/containskey/
|
||||
template <typename TString>
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use doc[key].is<T>() instead")
|
||||
detail::enable_if_t<detail::IsString<TString>::value, bool> containsKey(
|
||||
const TString& key) const {
|
||||
bool containsKey(const TString& key) const {
|
||||
return data_.getMember(detail::adaptString(key), &resources_) != 0;
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsondocument/containskey/
|
||||
template <typename TVariant>
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use doc[key].is<T>() instead")
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, bool> containsKey(
|
||||
const TVariant& key) const {
|
||||
bool containsKey(const TVariant& key) const {
|
||||
return containsKey(key.template as<const char*>());
|
||||
}
|
||||
|
||||
// Gets or sets a root object's member.
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TString>
|
||||
detail::enable_if_t<detail::IsString<TString>::value,
|
||||
detail::MemberProxy<JsonDocument&, TString>>
|
||||
operator[](const TString& key) {
|
||||
return {*this, key};
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
detail::MemberProxy<JsonDocument&, detail::AdaptedString<TString>> operator[](
|
||||
const TString& key) {
|
||||
return {*this, detail::adaptString(key)};
|
||||
}
|
||||
|
||||
// Gets or sets a root object's member.
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TChar>
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value,
|
||||
detail::MemberProxy<JsonDocument&, TChar*>>
|
||||
operator[](TChar* key) {
|
||||
return {*this, key};
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
detail::MemberProxy<JsonDocument&, detail::AdaptedString<TChar*>> operator[](
|
||||
TChar* key) {
|
||||
return {*this, detail::adaptString(key)};
|
||||
}
|
||||
|
||||
// Gets a root object's member.
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TString>
|
||||
detail::enable_if_t<detail::IsString<TString>::value, JsonVariantConst>
|
||||
operator[](const TString& key) const {
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
JsonVariantConst operator[](const TString& key) const {
|
||||
return JsonVariantConst(
|
||||
data_.getMember(detail::adaptString(key), &resources_), &resources_);
|
||||
}
|
||||
|
||||
// Gets a root object's member.
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TChar>
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value, JsonVariantConst>
|
||||
operator[](TChar* key) const {
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
JsonVariantConst operator[](TChar* key) const {
|
||||
return JsonVariantConst(
|
||||
data_.getMember(detail::adaptString(key), &resources_), &resources_);
|
||||
}
|
||||
|
||||
// Gets or sets a root array's element.
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename T>
|
||||
detail::enable_if_t<detail::is_integral<T>::value,
|
||||
detail::ElementProxy<JsonDocument&>>
|
||||
operator[](T index) {
|
||||
template <typename T,
|
||||
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||
detail::ElementProxy<JsonDocument&> operator[](T index) {
|
||||
return {*this, size_t(index)};
|
||||
}
|
||||
|
||||
@ -229,11 +242,11 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
|
||||
// Gets or sets a root object's member.
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TVariant>
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, JsonVariantConst>
|
||||
operator[](const TVariant& key) const {
|
||||
if (key.template is<const char*>())
|
||||
return operator[](key.template as<const char*>());
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
JsonVariantConst operator[](const TVariant& key) const {
|
||||
if (key.template is<JsonString>())
|
||||
return operator[](key.template as<JsonString>());
|
||||
if (key.template is<size_t>())
|
||||
return operator[](key.template as<size_t>());
|
||||
return {};
|
||||
@ -242,16 +255,18 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
// Appends a new (empty) element to the root array.
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||
template <typename T>
|
||||
detail::enable_if_t<!detail::is_same<T, JsonVariant>::value, T> add() {
|
||||
template <typename T, detail::enable_if_t<
|
||||
!detail::is_same<T, JsonVariant>::value, int> = 0>
|
||||
T add() {
|
||||
return add<JsonVariant>().to<T>();
|
||||
}
|
||||
|
||||
// Appends a new (null) element to the root array.
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||
template <typename T>
|
||||
detail::enable_if_t<detail::is_same<T, JsonVariant>::value, T> add() {
|
||||
template <typename T, detail::enable_if_t<
|
||||
detail::is_same<T, JsonVariant>::value, int> = 0>
|
||||
JsonVariant add() {
|
||||
return JsonVariant(data_.addElement(&resources_), &resources_);
|
||||
}
|
||||
|
||||
@ -264,41 +279,46 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
|
||||
// Appends a value to the root array.
|
||||
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||
template <typename TChar>
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<!detail::is_const<TChar>::value, int> = 0>
|
||||
bool add(TChar* value) {
|
||||
return data_.addValue(value, &resources_);
|
||||
}
|
||||
|
||||
// Removes an element of the root array.
|
||||
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||
template <typename T>
|
||||
detail::enable_if_t<detail::is_integral<T>::value> remove(T index) {
|
||||
template <typename T,
|
||||
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||
void remove(T index) {
|
||||
detail::VariantData::removeElement(getData(), size_t(index),
|
||||
getResourceManager());
|
||||
}
|
||||
|
||||
// Removes a member of the root object.
|
||||
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||
template <typename TChar>
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value> remove(TChar* key) {
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
void remove(TChar* key) {
|
||||
detail::VariantData::removeMember(getData(), detail::adaptString(key),
|
||||
getResourceManager());
|
||||
}
|
||||
|
||||
// Removes a member of the root object.
|
||||
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||
template <typename TString>
|
||||
detail::enable_if_t<detail::IsString<TString>::value> remove(
|
||||
const TString& key) {
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
void 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 TVariant>
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value> remove(
|
||||
const TVariant& key) {
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
void remove(const TVariant& key) {
|
||||
if (key.template is<const char*>())
|
||||
remove(key.template as<const char*>());
|
||||
if (key.template is<size_t>())
|
||||
|
@ -270,10 +270,10 @@ class JsonDeserializer {
|
||||
|
||||
JsonString key = stringBuilder_.str();
|
||||
|
||||
TFilter memberFilter = filter[key.c_str()];
|
||||
TFilter memberFilter = filter[key];
|
||||
|
||||
if (memberFilter.allow()) {
|
||||
auto member = object.getMember(adaptString(key.c_str()), resources_);
|
||||
auto member = object.getMember(adaptString(key), resources_);
|
||||
if (!member) {
|
||||
// Save key in memory pool.
|
||||
auto savedKey = stringBuilder_.save();
|
||||
@ -697,10 +697,11 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v7/api/json/deserializejson/
|
||||
template <typename TDestination, typename... Args>
|
||||
detail::enable_if_t<detail::is_deserialize_destination<TDestination>::value,
|
||||
DeserializationError>
|
||||
deserializeJson(TDestination&& dst, Args&&... args) {
|
||||
template <typename TDestination, typename... Args,
|
||||
detail::enable_if_t<
|
||||
detail::is_deserialize_destination<TDestination>::value, int> = 0>
|
||||
inline DeserializationError deserializeJson(TDestination&& dst,
|
||||
Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
|
||||
detail::forward<Args>(args)...);
|
||||
@ -708,10 +709,11 @@ deserializeJson(TDestination&& dst, Args&&... args) {
|
||||
|
||||
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v7/api/json/deserializejson/
|
||||
template <typename TDestination, typename TChar, typename... Args>
|
||||
detail::enable_if_t<detail::is_deserialize_destination<TDestination>::value,
|
||||
DeserializationError>
|
||||
deserializeJson(TDestination&& dst, TChar* input, Args&&... args) {
|
||||
template <typename TDestination, typename TChar, typename... Args,
|
||||
detail::enable_if_t<
|
||||
detail::is_deserialize_destination<TDestination>::value, int> = 0>
|
||||
inline DeserializationError deserializeJson(TDestination&& dst, TChar* input,
|
||||
Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
|
||||
input, detail::forward<Args>(args)...);
|
||||
|
@ -129,9 +129,10 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Produces a minified JSON document.
|
||||
// https://arduinojson.org/v7/api/json/serializejson/
|
||||
template <typename TDestination>
|
||||
detail::enable_if_t<!detail::is_pointer<TDestination>::value, size_t>
|
||||
serializeJson(JsonVariantConst source, TDestination& destination) {
|
||||
template <
|
||||
typename TDestination,
|
||||
detail::enable_if_t<!detail::is_pointer<TDestination>::value, int> = 0>
|
||||
size_t serializeJson(JsonVariantConst source, TDestination& destination) {
|
||||
using namespace detail;
|
||||
return serialize<JsonSerializer>(source, destination);
|
||||
}
|
||||
@ -152,10 +153,10 @@ inline size_t measureJson(JsonVariantConst source) {
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||
template <typename T>
|
||||
inline detail::enable_if_t<detail::is_convertible<T, JsonVariantConst>::value,
|
||||
std::ostream&>
|
||||
operator<<(std::ostream& os, const T& source) {
|
||||
template <typename T,
|
||||
detail::enable_if_t<
|
||||
detail::is_convertible<T, JsonVariantConst>::value, int> = 0>
|
||||
inline std::ostream& operator<<(std::ostream& os, const T& source) {
|
||||
serializeJson(source, os);
|
||||
return os;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TWriter>
|
||||
class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
typedef JsonSerializer<TWriter> base;
|
||||
using base = JsonSerializer<TWriter>;
|
||||
|
||||
public:
|
||||
PrettyJsonSerializer(TWriter writer, const ResourceManager* resources)
|
||||
@ -83,9 +83,11 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Produces JsonDocument to create a prettified JSON document.
|
||||
// https://arduinojson.org/v7/api/json/serializejsonpretty/
|
||||
template <typename TDestination>
|
||||
detail::enable_if_t<!detail::is_pointer<TDestination>::value, size_t>
|
||||
serializeJsonPretty(JsonVariantConst source, TDestination& destination) {
|
||||
template <
|
||||
typename TDestination,
|
||||
detail::enable_if_t<!detail::is_pointer<TDestination>::value, int> = 0>
|
||||
inline size_t serializeJsonPretty(JsonVariantConst source,
|
||||
TDestination& destination) {
|
||||
using namespace ArduinoJson::detail;
|
||||
return serialize<PrettyJsonSerializer>(source, destination);
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ class TextFormatter {
|
||||
|
||||
template <typename T>
|
||||
enable_if_t<is_signed<T>::value> writeInteger(T value) {
|
||||
typedef make_unsigned_t<T> unsigned_type;
|
||||
using unsigned_type = make_unsigned_t<T>;
|
||||
unsigned_type unsigned_value;
|
||||
if (value < 0) {
|
||||
writeRaw('-');
|
||||
|
@ -55,7 +55,7 @@ class StringBuffer {
|
||||
JsonString str() const {
|
||||
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||
|
||||
return JsonString(node_->data, node_->length, JsonString::Copied);
|
||||
return JsonString(node_->data, node_->length);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -68,7 +68,7 @@ class StringBuilder {
|
||||
JsonString str() const {
|
||||
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||
node_->data[size_] = 0;
|
||||
return JsonString(node_->data, size_, JsonString::Copied);
|
||||
return JsonString(node_->data, size_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -464,10 +464,11 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
|
||||
template <typename TDestination, typename... Args>
|
||||
detail::enable_if_t<detail::is_deserialize_destination<TDestination>::value,
|
||||
DeserializationError>
|
||||
deserializeMsgPack(TDestination&& dst, Args&&... args) {
|
||||
template <typename TDestination, typename... Args,
|
||||
detail::enable_if_t<
|
||||
detail::is_deserialize_destination<TDestination>::value, int> = 0>
|
||||
inline DeserializationError deserializeMsgPack(TDestination&& dst,
|
||||
Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
|
||||
detail::forward<Args>(args)...);
|
||||
@ -475,10 +476,11 @@ deserializeMsgPack(TDestination&& dst, Args&&... args) {
|
||||
|
||||
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
|
||||
template <typename TDestination, typename TChar, typename... Args>
|
||||
detail::enable_if_t<detail::is_deserialize_destination<TDestination>::value,
|
||||
DeserializationError>
|
||||
deserializeMsgPack(TDestination&& dst, TChar* input, Args&&... args) {
|
||||
template <typename TDestination, typename TChar, typename... Args,
|
||||
detail::enable_if_t<
|
||||
detail::is_deserialize_destination<TDestination>::value, int> = 0>
|
||||
inline DeserializationError deserializeMsgPack(TDestination&& dst, TChar* input,
|
||||
Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
|
||||
input,
|
||||
|
@ -96,7 +96,7 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
|
||||
}
|
||||
|
||||
size_t visit(JsonString value) {
|
||||
ARDUINOJSON_ASSERT(value != NULL);
|
||||
ARDUINOJSON_ASSERT(!value.isNull());
|
||||
|
||||
auto n = value.size();
|
||||
|
||||
@ -218,9 +218,10 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Produces a MessagePack document.
|
||||
// https://arduinojson.org/v7/api/msgpack/serializemsgpack/
|
||||
template <typename TDestination>
|
||||
detail::enable_if_t<!detail::is_pointer<TDestination>::value, size_t>
|
||||
serializeMsgPack(JsonVariantConst source, TDestination& output) {
|
||||
template <
|
||||
typename TDestination,
|
||||
detail::enable_if_t<!detail::is_pointer<TDestination>::value, int> = 0>
|
||||
inline size_t serializeMsgPack(JsonVariantConst source, TDestination& output) {
|
||||
using namespace ArduinoJson::detail;
|
||||
return serialize<MsgPackSerializer>(source, output);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ struct FloatParts {
|
||||
|
||||
template <typename TFloat>
|
||||
inline int16_t normalize(TFloat& value) {
|
||||
typedef FloatTraits<TFloat> traits;
|
||||
using traits = FloatTraits<TFloat>;
|
||||
int16_t powersOf10 = 0;
|
||||
|
||||
int8_t index = sizeof(TFloat) == 8 ? 8 : 5;
|
||||
|
@ -21,12 +21,12 @@ struct FloatTraits {};
|
||||
|
||||
template <typename T>
|
||||
struct FloatTraits<T, 8 /*64bits*/> {
|
||||
typedef uint64_t mantissa_type;
|
||||
using mantissa_type = uint64_t;
|
||||
static const short mantissa_bits = 52;
|
||||
static const mantissa_type mantissa_max =
|
||||
(mantissa_type(1) << mantissa_bits) - 1;
|
||||
|
||||
typedef int16_t exponent_type;
|
||||
using exponent_type = int16_t;
|
||||
static const exponent_type exponent_max = 308;
|
||||
|
||||
static pgm_ptr<T> positiveBinaryPowersOfTen() {
|
||||
@ -105,12 +105,12 @@ struct FloatTraits<T, 8 /*64bits*/> {
|
||||
|
||||
template <typename T>
|
||||
struct FloatTraits<T, 4 /*32bits*/> {
|
||||
typedef uint32_t mantissa_type;
|
||||
using mantissa_type = uint32_t;
|
||||
static const short mantissa_bits = 23;
|
||||
static const mantissa_type mantissa_max =
|
||||
(mantissa_type(1) << mantissa_bits) - 1;
|
||||
|
||||
typedef int8_t exponent_type;
|
||||
using exponent_type = int8_t;
|
||||
static const exponent_type exponent_max = 38;
|
||||
|
||||
static pgm_ptr<T> positiveBinaryPowersOfTen() {
|
||||
|
@ -10,9 +10,9 @@
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
typedef double JsonFloat;
|
||||
using JsonFloat = double;
|
||||
#else
|
||||
typedef float JsonFloat;
|
||||
using JsonFloat = float;
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
@ -12,11 +12,11 @@
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
typedef int64_t JsonInteger;
|
||||
typedef uint64_t JsonUInt;
|
||||
using JsonInteger = int64_t;
|
||||
using JsonUInt = uint64_t;
|
||||
#else
|
||||
typedef long JsonInteger;
|
||||
typedef unsigned long JsonUInt;
|
||||
using JsonInteger = long;
|
||||
using JsonUInt = unsigned long;
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
@ -103,9 +103,9 @@ class Number {
|
||||
};
|
||||
|
||||
inline Number parseNumber(const char* s) {
|
||||
typedef FloatTraits<JsonFloat> traits;
|
||||
typedef largest_type<traits::mantissa_type, JsonUInt> mantissa_t;
|
||||
typedef traits::exponent_type exponent_t;
|
||||
using traits = FloatTraits<JsonFloat>;
|
||||
using mantissa_t = largest_type<traits::mantissa_type, JsonUInt>;
|
||||
using exponent_t = traits::exponent_type;
|
||||
|
||||
ARDUINOJSON_ASSERT(s != 0);
|
||||
|
||||
|
@ -17,7 +17,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
typedef JsonObjectIterator iterator;
|
||||
using iterator = JsonObjectIterator;
|
||||
|
||||
// Creates an unbound reference.
|
||||
JsonObject() : data_(0), resources_(0) {}
|
||||
@ -101,32 +101,31 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
|
||||
// Gets or sets the member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobject/subscript/
|
||||
template <typename TString>
|
||||
detail::enable_if_t<detail::IsString<TString>::value,
|
||||
detail::MemberProxy<JsonObject, TString>>
|
||||
operator[](const TString& key) const {
|
||||
return {*this, key};
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
detail::MemberProxy<JsonObject, detail::AdaptedString<TString>> operator[](
|
||||
const TString& key) const {
|
||||
return {*this, detail::adaptString(key)};
|
||||
}
|
||||
|
||||
// Gets or sets the member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobject/subscript/
|
||||
template <typename TChar>
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value,
|
||||
detail::MemberProxy<JsonObject, TChar*>>
|
||||
operator[](TChar* key) const {
|
||||
return {*this, key};
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
detail::MemberProxy<JsonObject, detail::AdaptedString<TChar*>> operator[](
|
||||
TChar* key) const {
|
||||
return {*this, detail::adaptString(key)};
|
||||
}
|
||||
|
||||
// Gets or sets the member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobject/subscript/
|
||||
template <typename TVariant>
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value,
|
||||
detail::MemberProxy<JsonObject, const char*>>
|
||||
operator[](const TVariant& key) const {
|
||||
if (key.template is<const char*>())
|
||||
return {*this, key.template as<const char*>()};
|
||||
else
|
||||
return {*this, nullptr};
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
detail::MemberProxy<JsonObject, detail::AdaptedString<JsonString>> operator[](
|
||||
const TVariant& key) const {
|
||||
return {*this, detail::adaptString(key.template as<JsonString>())};
|
||||
}
|
||||
|
||||
// Removes the member at the specified iterator.
|
||||
@ -137,18 +136,18 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
|
||||
// Removes the member with the specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobject/remove/
|
||||
template <typename TString>
|
||||
detail::enable_if_t<detail::IsString<TString>::value> remove(
|
||||
const TString& key) const {
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
void 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 TVariant>
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value> remove(
|
||||
const TVariant& key) const {
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
void remove(const TVariant& key) const {
|
||||
if (key.template is<const char*>())
|
||||
remove(key.template as<const char*>());
|
||||
}
|
||||
@ -163,30 +162,32 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonobject/containskey/
|
||||
template <typename TString>
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead")
|
||||
detail::enable_if_t<detail::IsString<TString>::value, bool> containsKey(
|
||||
const TString& key) const {
|
||||
bool containsKey(const TString& key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj["key"].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonobject/containskey/
|
||||
template <typename TChar>
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use obj[\"key\"].is<T>() instead")
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value, bool> containsKey(
|
||||
TChar* key) const {
|
||||
bool containsKey(TChar* key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonobject/containskey/
|
||||
template <typename TVariant>
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead")
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, bool> containsKey(
|
||||
const TVariant& key) const {
|
||||
bool containsKey(const TVariant& key) const {
|
||||
return containsKey(key.template as<const char*>());
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
typedef JsonObjectConstIterator iterator;
|
||||
using iterator = JsonObjectConstIterator;
|
||||
|
||||
// Creates an unbound reference.
|
||||
JsonObjectConst() : data_(0), resources_(0) {}
|
||||
@ -70,10 +70,10 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/containskey/
|
||||
template <typename TString>
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead")
|
||||
detail::enable_if_t<detail::IsString<TString>::value, bool> containsKey(
|
||||
const TString& key) const {
|
||||
bool containsKey(const TString& key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
@ -89,18 +89,18 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/containskey/
|
||||
template <typename TVariant>
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead")
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, bool> containsKey(
|
||||
const TVariant& key) const {
|
||||
bool containsKey(const TVariant& key) const {
|
||||
return containsKey(key.template as<const char*>());
|
||||
}
|
||||
|
||||
// Gets the member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/subscript/
|
||||
template <typename TString>
|
||||
detail::enable_if_t<detail::IsString<TString>::value, JsonVariantConst>
|
||||
operator[](const TString& key) const {
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
JsonVariantConst operator[](const TString& key) const {
|
||||
return JsonVariantConst(detail::ObjectData::getMember(
|
||||
data_, detail::adaptString(key), resources_),
|
||||
resources_);
|
||||
@ -108,9 +108,11 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||
|
||||
// Gets the member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/subscript/
|
||||
template <typename TChar>
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value, JsonVariantConst>
|
||||
operator[](TChar* key) const {
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
JsonVariantConst operator[](TChar* key) const {
|
||||
return JsonVariantConst(detail::ObjectData::getMember(
|
||||
data_, detail::adaptString(key), resources_),
|
||||
resources_);
|
||||
@ -118,11 +120,11 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||
|
||||
// Gets the member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/subscript/
|
||||
template <typename TVariant>
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, JsonVariantConst>
|
||||
operator[](const TVariant& key) const {
|
||||
if (key.template is<const char*>())
|
||||
return operator[](key.template as<const char*>());
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
JsonVariantConst operator[](const TVariant& key) const {
|
||||
if (key.template is<JsonString>())
|
||||
return operator[](key.template as<JsonString>());
|
||||
else
|
||||
return JsonVariantConst();
|
||||
}
|
||||
|
@ -10,18 +10,23 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// A proxy class to get or set a member of an object.
|
||||
// https://arduinojson.org/v7/api/jsonobject/subscript/
|
||||
template <typename TUpstream, typename TStringRef>
|
||||
template <typename TUpstream, typename AdaptedString>
|
||||
class MemberProxy
|
||||
: public VariantRefBase<MemberProxy<TUpstream, TStringRef>>,
|
||||
public VariantOperators<MemberProxy<TUpstream, TStringRef>> {
|
||||
: public VariantRefBase<MemberProxy<TUpstream, AdaptedString>>,
|
||||
public VariantOperators<MemberProxy<TUpstream, AdaptedString>> {
|
||||
friend class VariantAttorney;
|
||||
|
||||
public:
|
||||
MemberProxy(TUpstream upstream, TStringRef key)
|
||||
: upstream_(upstream), key_(key) {}
|
||||
friend class VariantRefBase<MemberProxy<TUpstream, AdaptedString>>;
|
||||
|
||||
MemberProxy(const MemberProxy& src)
|
||||
: upstream_(src.upstream_), key_(src.key_) {}
|
||||
template <typename, typename>
|
||||
friend class MemberProxy;
|
||||
|
||||
template <typename>
|
||||
friend class ElementProxy;
|
||||
|
||||
public:
|
||||
MemberProxy(TUpstream upstream, AdaptedString key)
|
||||
: upstream_(upstream), key_(key) {}
|
||||
|
||||
MemberProxy& operator=(const MemberProxy& src) {
|
||||
this->set(src);
|
||||
@ -34,20 +39,25 @@ class MemberProxy
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename T, enable_if_t<!is_const<T>::value, int> = 0>
|
||||
MemberProxy& operator=(T* src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// clang-format off
|
||||
MemberProxy(const MemberProxy& src) // Error here? See https://arduinojson.org/v7/proxy-non-copyable/
|
||||
: upstream_(src.upstream_), key_(src.key_) {}
|
||||
// clang-format on
|
||||
|
||||
ResourceManager* getResourceManager() const {
|
||||
return VariantAttorney::getResourceManager(upstream_);
|
||||
}
|
||||
|
||||
VariantData* getData() const {
|
||||
return VariantData::getMember(
|
||||
VariantAttorney::getData(upstream_), adaptString(key_),
|
||||
VariantAttorney::getData(upstream_), key_,
|
||||
VariantAttorney::getResourceManager(upstream_));
|
||||
}
|
||||
|
||||
@ -55,13 +65,13 @@ class MemberProxy
|
||||
auto data = VariantAttorney::getOrCreateData(upstream_);
|
||||
if (!data)
|
||||
return nullptr;
|
||||
return data->getOrAddMember(adaptString(key_),
|
||||
return data->getOrAddMember(key_,
|
||||
VariantAttorney::getResourceManager(upstream_));
|
||||
}
|
||||
|
||||
private:
|
||||
TUpstream upstream_;
|
||||
TStringRef key_;
|
||||
AdaptedString key_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -15,17 +15,17 @@ struct uint_;
|
||||
|
||||
template <>
|
||||
struct uint_<8> {
|
||||
typedef uint8_t type;
|
||||
using type = uint8_t;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct uint_<16> {
|
||||
typedef uint16_t type;
|
||||
using type = uint16_t;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct uint_<32> {
|
||||
typedef uint32_t type;
|
||||
using type = uint32_t;
|
||||
};
|
||||
|
||||
template <int Bits>
|
||||
|
@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "type_traits/conditional.hpp"
|
||||
#include "type_traits/decay.hpp"
|
||||
#include "type_traits/enable_if.hpp"
|
||||
#include "type_traits/function_traits.hpp"
|
||||
#include "type_traits/integral_constant.hpp"
|
||||
|
@ -10,12 +10,12 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <bool Condition, class TrueType, class FalseType>
|
||||
struct conditional {
|
||||
typedef TrueType type;
|
||||
using type = TrueType;
|
||||
};
|
||||
|
||||
template <class TrueType, class FalseType>
|
||||
struct conditional<false, TrueType, FalseType> {
|
||||
typedef FalseType type;
|
||||
using type = FalseType;
|
||||
};
|
||||
|
||||
template <bool Condition, class TrueType, class FalseType>
|
||||
|
33
src/ArduinoJson/Polyfills/type_traits/decay.hpp
Normal file
33
src/ArduinoJson/Polyfills/type_traits/decay.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename T>
|
||||
struct decay {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct decay<T&> : decay<T> {};
|
||||
|
||||
template <typename T>
|
||||
struct decay<T&&> : decay<T> {};
|
||||
|
||||
template <typename T>
|
||||
struct decay<T[]> : decay<T*> {};
|
||||
|
||||
template <typename T, size_t N>
|
||||
struct decay<T[N]> : decay<T*> {};
|
||||
|
||||
template <typename T>
|
||||
using decay_t = typename decay<T>::type;
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -14,7 +14,7 @@ struct enable_if {};
|
||||
|
||||
template <typename T>
|
||||
struct enable_if<true, T> {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <bool Condition, typename T = void>
|
||||
|
@ -13,7 +13,10 @@ struct integral_constant {
|
||||
static const T value = v;
|
||||
};
|
||||
|
||||
typedef integral_constant<bool, true> true_type;
|
||||
typedef integral_constant<bool, false> false_type;
|
||||
template <bool B>
|
||||
using bool_constant = integral_constant<bool, B>;
|
||||
|
||||
using true_type = bool_constant<true>;
|
||||
using false_type = bool_constant<false>;
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -27,7 +27,7 @@ struct is_convertible {
|
||||
static int probe(To);
|
||||
static char probe(...);
|
||||
|
||||
static From& from_;
|
||||
static const From& from_;
|
||||
|
||||
public:
|
||||
static const bool value = sizeof(probe(from_)) == sizeof(int);
|
||||
|
@ -11,11 +11,11 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
// A meta-function that return the type T without the const modifier
|
||||
template <typename T>
|
||||
struct remove_const {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
};
|
||||
template <typename T>
|
||||
struct remove_const<const T> {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -10,19 +10,19 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename T>
|
||||
struct remove_cv {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
};
|
||||
template <typename T>
|
||||
struct remove_cv<const T> {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
};
|
||||
template <typename T>
|
||||
struct remove_cv<volatile T> {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
};
|
||||
template <typename T>
|
||||
struct remove_cv<const volatile T> {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -11,11 +11,11 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
// A meta-function that return the type T without the reference modifier.
|
||||
template <typename T>
|
||||
struct remove_reference {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
};
|
||||
template <typename T>
|
||||
struct remove_reference<T&> {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -10,7 +10,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename T>
|
||||
struct type_identity {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// The default writer is a simple wrapper for Writers that are not copiable
|
||||
// The default writer is a simple wrapper for Writers that are not copyable
|
||||
template <typename TDestination, typename Enable = void>
|
||||
class Writer {
|
||||
public:
|
||||
|
@ -34,7 +34,7 @@ class FlashString {
|
||||
return size_;
|
||||
}
|
||||
|
||||
friend bool stringEquals(FlashString a, SizedRamString b) {
|
||||
friend bool stringEquals(FlashString a, RamString b) {
|
||||
ARDUINOJSON_ASSERT(a.typeSortKey < b.typeSortKey);
|
||||
ARDUINOJSON_ASSERT(!a.isNull());
|
||||
ARDUINOJSON_ASSERT(!b.isNull());
|
||||
@ -43,7 +43,7 @@ class FlashString {
|
||||
return ::memcmp_P(b.data(), a.str_, a.size_) == 0;
|
||||
}
|
||||
|
||||
friend int stringCompare(FlashString a, SizedRamString b) {
|
||||
friend int stringCompare(FlashString a, RamString b) {
|
||||
ARDUINOJSON_ASSERT(a.typeSortKey < b.typeSortKey);
|
||||
ARDUINOJSON_ASSERT(!a.isNull());
|
||||
ARDUINOJSON_ASSERT(!b.isNull());
|
||||
@ -63,7 +63,7 @@ class FlashString {
|
||||
::memcpy_P(p, s.str_, n);
|
||||
}
|
||||
|
||||
bool isLinked() const {
|
||||
bool isStatic() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ class FlashString {
|
||||
|
||||
template <>
|
||||
struct StringAdapter<const __FlashStringHelper*, void> {
|
||||
typedef FlashString AdaptedString;
|
||||
using AdaptedString = FlashString;
|
||||
|
||||
static AdaptedString adapt(const __FlashStringHelper* s) {
|
||||
return AdaptedString(s, s ? strlen_P(reinterpret_cast<const char*>(s)) : 0);
|
||||
@ -83,7 +83,7 @@ struct StringAdapter<const __FlashStringHelper*, void> {
|
||||
|
||||
template <>
|
||||
struct SizedStringAdapter<const __FlashStringHelper*, void> {
|
||||
typedef FlashString AdaptedString;
|
||||
using AdaptedString = FlashString;
|
||||
|
||||
static AdaptedString adapt(const __FlashStringHelper* s, size_t n) {
|
||||
return AdaptedString(s, n);
|
||||
|
@ -1,35 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Strings/Adapters/RamString.hpp>
|
||||
#include <ArduinoJson/Strings/JsonString.hpp>
|
||||
#include <ArduinoJson/Strings/StringAdapter.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class JsonStringAdapter : public SizedRamString {
|
||||
public:
|
||||
JsonStringAdapter(const JsonString& s)
|
||||
: SizedRamString(s.c_str(), s.size()), linked_(s.isLinked()) {}
|
||||
|
||||
bool isLinked() const {
|
||||
return linked_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool linked_;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct StringAdapter<JsonString> {
|
||||
typedef JsonStringAdapter AdaptedString;
|
||||
|
||||
static AdaptedString adapt(const JsonString& s) {
|
||||
return AdaptedString(s);
|
||||
}
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -17,91 +17,19 @@ template <typename T>
|
||||
struct IsChar
|
||||
: integral_constant<bool, is_integral<T>::value && sizeof(T) == 1> {};
|
||||
|
||||
class ZeroTerminatedRamString {
|
||||
public:
|
||||
static const size_t typeSortKey = 3;
|
||||
|
||||
ZeroTerminatedRamString(const char* str) : str_(str) {}
|
||||
|
||||
bool isNull() const {
|
||||
return !str_;
|
||||
}
|
||||
|
||||
FORCE_INLINE size_t size() const {
|
||||
return str_ ? ::strlen(str_) : 0;
|
||||
}
|
||||
|
||||
char operator[](size_t i) const {
|
||||
ARDUINOJSON_ASSERT(str_ != 0);
|
||||
ARDUINOJSON_ASSERT(i <= size());
|
||||
return str_[i];
|
||||
}
|
||||
|
||||
const char* data() const {
|
||||
return str_;
|
||||
}
|
||||
|
||||
friend int stringCompare(ZeroTerminatedRamString a,
|
||||
ZeroTerminatedRamString b) {
|
||||
ARDUINOJSON_ASSERT(!a.isNull());
|
||||
ARDUINOJSON_ASSERT(!b.isNull());
|
||||
return ::strcmp(a.str_, b.str_);
|
||||
}
|
||||
|
||||
friend bool stringEquals(ZeroTerminatedRamString a,
|
||||
ZeroTerminatedRamString b) {
|
||||
return stringCompare(a, b) == 0;
|
||||
}
|
||||
|
||||
bool isLinked() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
const char* str_;
|
||||
};
|
||||
|
||||
template <typename TChar>
|
||||
struct StringAdapter<TChar*, enable_if_t<IsChar<TChar>::value>> {
|
||||
typedef ZeroTerminatedRamString AdaptedString;
|
||||
|
||||
static AdaptedString adapt(const TChar* p) {
|
||||
return AdaptedString(reinterpret_cast<const char*>(p));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TChar, size_t N>
|
||||
struct StringAdapter<TChar[N], enable_if_t<IsChar<TChar>::value>> {
|
||||
typedef ZeroTerminatedRamString AdaptedString;
|
||||
|
||||
static AdaptedString adapt(const TChar* p) {
|
||||
return AdaptedString(reinterpret_cast<const char*>(p));
|
||||
}
|
||||
};
|
||||
|
||||
class StaticStringAdapter : public ZeroTerminatedRamString {
|
||||
public:
|
||||
StaticStringAdapter(const char* str) : ZeroTerminatedRamString(str) {}
|
||||
|
||||
bool isLinked() const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct StringAdapter<const char*, void> {
|
||||
typedef StaticStringAdapter AdaptedString;
|
||||
|
||||
static AdaptedString adapt(const char* p) {
|
||||
return AdaptedString(p);
|
||||
}
|
||||
};
|
||||
|
||||
class SizedRamString {
|
||||
class RamString {
|
||||
public:
|
||||
static const size_t typeSortKey = 2;
|
||||
#if ARDUINOJSON_SIZEOF_POINTER <= 2
|
||||
static constexpr size_t sizeMask = size_t(-1) >> 1;
|
||||
#else
|
||||
static constexpr size_t sizeMask = size_t(-1);
|
||||
#endif
|
||||
|
||||
SizedRamString(const char* str, size_t sz) : str_(str), size_(sz) {}
|
||||
RamString(const char* str, size_t sz, bool isStatic = false)
|
||||
: str_(str), size_(sz & sizeMask), static_(isStatic) {
|
||||
ARDUINOJSON_ASSERT(size_ == sz);
|
||||
}
|
||||
|
||||
bool isNull() const {
|
||||
return !str_;
|
||||
@ -121,18 +49,55 @@ class SizedRamString {
|
||||
return str_;
|
||||
}
|
||||
|
||||
bool isLinked() const {
|
||||
return false;
|
||||
bool isStatic() const {
|
||||
return static_;
|
||||
}
|
||||
|
||||
protected:
|
||||
const char* str_;
|
||||
|
||||
#if ARDUINOJSON_SIZEOF_POINTER <= 2
|
||||
// Use a bitfield only on 8-bit microcontrollers
|
||||
size_t size_ : sizeof(size_t) * 8 - 1;
|
||||
bool static_ : 1;
|
||||
#else
|
||||
size_t size_;
|
||||
bool static_;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename TChar>
|
||||
struct StringAdapter<TChar*, enable_if_t<IsChar<TChar>::value>> {
|
||||
using AdaptedString = RamString;
|
||||
|
||||
static AdaptedString adapt(const TChar* p) {
|
||||
auto str = reinterpret_cast<const char*>(p);
|
||||
return AdaptedString(str, str ? ::strlen(str) : 0);
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
struct StringAdapter<const char (&)[N]> {
|
||||
using AdaptedString = RamString;
|
||||
|
||||
static AdaptedString adapt(const char (&p)[N]) {
|
||||
return RamString(p, N - 1, true);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TChar, size_t N>
|
||||
struct StringAdapter<TChar[N], enable_if_t<IsChar<TChar>::value>> {
|
||||
using AdaptedString = RamString;
|
||||
|
||||
static AdaptedString adapt(const TChar* p) {
|
||||
auto str = reinterpret_cast<const char*>(p);
|
||||
return AdaptedString(str, str ? ::strlen(str) : 0);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TChar>
|
||||
struct SizedStringAdapter<TChar*, enable_if_t<IsChar<TChar>::value>> {
|
||||
typedef SizedRamString AdaptedString;
|
||||
using AdaptedString = RamString;
|
||||
|
||||
static AdaptedString adapt(const TChar* p, size_t n) {
|
||||
return AdaptedString(reinterpret_cast<const char*>(p), n);
|
||||
|
@ -15,7 +15,7 @@ struct StringAdapter<
|
||||
T,
|
||||
enable_if_t<(string_traits<T>::has_cstr || string_traits<T>::has_data) &&
|
||||
(string_traits<T>::has_length || string_traits<T>::has_size)>> {
|
||||
typedef SizedRamString AdaptedString;
|
||||
using AdaptedString = RamString;
|
||||
|
||||
static AdaptedString adapt(const T& s) {
|
||||
return AdaptedString(get_data(s), get_size(s));
|
||||
|
@ -13,7 +13,7 @@ template <typename T, typename Enable = void>
|
||||
struct IsString : false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct IsString<T, void_t<typename StringAdapter<T>::AdaptedString>>
|
||||
struct IsString<T, void_t<typename StringAdapterFor<T>::AdaptedString>>
|
||||
: true_type {};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -4,6 +4,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Strings/Adapters/RamString.hpp>
|
||||
|
||||
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||
# include <ostream>
|
||||
#endif
|
||||
@ -13,54 +16,58 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
// A string.
|
||||
// https://arduinojson.org/v7/api/jsonstring/
|
||||
class JsonString {
|
||||
friend struct detail::StringAdapter<JsonString>;
|
||||
|
||||
public:
|
||||
enum Ownership { Copied, Linked };
|
||||
JsonString() : str_(nullptr, 0, true) {}
|
||||
|
||||
JsonString() : data_(0), size_(0), ownership_(Linked) {}
|
||||
JsonString(const char* data, bool isStatic = false)
|
||||
: str_(data, data ? ::strlen(data) : 0, isStatic) {}
|
||||
|
||||
JsonString(const char* data, Ownership ownership = Linked)
|
||||
: data_(data), size_(data ? ::strlen(data) : 0), ownership_(ownership) {}
|
||||
|
||||
JsonString(const char* data, size_t sz, Ownership ownership = Linked)
|
||||
: data_(data), size_(sz), ownership_(ownership) {}
|
||||
template <typename TSize,
|
||||
detail::enable_if_t<detail::is_integral<TSize>::value &&
|
||||
!detail::is_same<TSize, bool>::value,
|
||||
int> = 0>
|
||||
JsonString(const char* data, TSize sz, bool isStatic = false)
|
||||
: str_(data, size_t(sz), isStatic) {}
|
||||
|
||||
// Returns a pointer to the characters.
|
||||
const char* c_str() const {
|
||||
return data_;
|
||||
return str_.data();
|
||||
}
|
||||
|
||||
// Returns true if the string is null.
|
||||
bool isNull() const {
|
||||
return !data_;
|
||||
return str_.isNull();
|
||||
}
|
||||
|
||||
// Returns true if the string is stored by address.
|
||||
// Returns false if the string is stored by copy.
|
||||
bool isLinked() const {
|
||||
return ownership_ == Linked;
|
||||
bool isStatic() const {
|
||||
return str_.isStatic();
|
||||
}
|
||||
|
||||
// Returns length of the string.
|
||||
size_t size() const {
|
||||
return size_;
|
||||
return str_.size();
|
||||
}
|
||||
|
||||
// Returns true if the string is non-null
|
||||
explicit operator bool() const {
|
||||
return data_ != 0;
|
||||
return str_.data() != 0;
|
||||
}
|
||||
|
||||
// Returns true if strings are equal.
|
||||
friend bool operator==(JsonString lhs, JsonString rhs) {
|
||||
if (lhs.size_ != rhs.size_)
|
||||
if (lhs.size() != rhs.size())
|
||||
return false;
|
||||
if (lhs.data_ == rhs.data_)
|
||||
if (lhs.c_str() == rhs.c_str())
|
||||
return true;
|
||||
if (!lhs.data_)
|
||||
if (!lhs.c_str())
|
||||
return false;
|
||||
if (!rhs.data_)
|
||||
if (!rhs.c_str())
|
||||
return false;
|
||||
return memcmp(lhs.data_, rhs.data_, lhs.size_) == 0;
|
||||
return memcmp(lhs.c_str(), rhs.c_str(), lhs.size()) == 0;
|
||||
}
|
||||
|
||||
// Returns true if strings differs.
|
||||
@ -76,9 +83,18 @@ class JsonString {
|
||||
#endif
|
||||
|
||||
private:
|
||||
const char* data_;
|
||||
size_t size_;
|
||||
Ownership ownership_;
|
||||
detail::RamString str_;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <>
|
||||
struct StringAdapter<JsonString> {
|
||||
using AdaptedString = RamString;
|
||||
|
||||
static const AdaptedString& adapt(const JsonString& s) {
|
||||
return s.str_;
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
@ -4,8 +4,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// a meta function that tells if the type is a string literal (const char[N])
|
||||
template <typename T>
|
||||
struct IsStringLiteral : false_type {};
|
||||
|
||||
template <size_t N>
|
||||
struct IsStringLiteral<const char (&)[N]> : true_type {};
|
||||
|
||||
template <typename TString, typename Enable = void>
|
||||
struct StringAdapter;
|
||||
|
||||
@ -13,18 +22,25 @@ template <typename TString, typename Enable = void>
|
||||
struct SizedStringAdapter;
|
||||
|
||||
template <typename TString>
|
||||
typename StringAdapter<TString>::AdaptedString adaptString(const TString& s) {
|
||||
return StringAdapter<TString>::adapt(s);
|
||||
using StringAdapterFor =
|
||||
StringAdapter<conditional_t<IsStringLiteral<TString>::value, TString,
|
||||
remove_cv_t<remove_reference_t<TString>>>>;
|
||||
|
||||
template <typename T>
|
||||
using AdaptedString = typename StringAdapterFor<T>::AdaptedString;
|
||||
|
||||
template <typename TString>
|
||||
AdaptedString<TString> adaptString(TString&& s) {
|
||||
return StringAdapterFor<TString>::adapt(detail::forward<TString>(s));
|
||||
}
|
||||
|
||||
template <typename TChar>
|
||||
typename StringAdapter<TChar*>::AdaptedString adaptString(TChar* p) {
|
||||
template <typename TChar, enable_if_t<!is_const<TChar>::value, int> = 0>
|
||||
AdaptedString<TChar*> adaptString(TChar* p) {
|
||||
return StringAdapter<TChar*>::adapt(p);
|
||||
}
|
||||
|
||||
template <typename TChar>
|
||||
typename SizedStringAdapter<TChar*>::AdaptedString adaptString(TChar* p,
|
||||
size_t n) {
|
||||
AdaptedString<TChar*> adaptString(TChar* p, size_t n) {
|
||||
return SizedStringAdapter<TChar*>::adapt(p, n);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Strings/Adapters/JsonString.hpp>
|
||||
#include <ArduinoJson/Strings/Adapters/RamString.hpp>
|
||||
#include <ArduinoJson/Strings/Adapters/StringObject.hpp>
|
||||
|
||||
|
@ -31,7 +31,7 @@ struct Converter {
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static T fromJson(JsonVariantConst src) {
|
||||
static detail::decay_t<T> fromJson(JsonVariantConst src) {
|
||||
static_assert(!detail::is_same<T, char*>::value,
|
||||
"type 'char*' is not supported, use 'const char*' instead");
|
||||
|
||||
@ -178,7 +178,7 @@ struct Converter<JsonString> : private detail::VariantAttorney {
|
||||
|
||||
static JsonString fromJson(JsonVariantConst src) {
|
||||
auto data = getData(src);
|
||||
return data ? data->asString() : 0;
|
||||
return data ? data->asString() : JsonString();
|
||||
}
|
||||
|
||||
static bool checkJson(JsonVariantConst src) {
|
||||
|
@ -68,27 +68,29 @@ class JsonVariantConst : public detail::VariantTag,
|
||||
// Casts the value to the specified type.
|
||||
// https://arduinojson.org/v7/api/jsonvariantconst/as/
|
||||
template <typename T,
|
||||
detail::enable_if_t<ConversionSupported<T>::value, bool> = true>
|
||||
detail::enable_if_t<ConversionSupported<T>::value, int> = 0>
|
||||
T as() const {
|
||||
return Converter<T>::fromJson(*this);
|
||||
}
|
||||
|
||||
// Invalid conversion. Will not compile.
|
||||
template <typename T,
|
||||
detail::enable_if_t<!ConversionSupported<T>::value, bool> = true>
|
||||
detail::enable_if_t<!ConversionSupported<T>::value, int> = 0>
|
||||
detail::InvalidConversion<JsonVariantConst, T> as() const;
|
||||
|
||||
// Returns true if the value is of the specified type.
|
||||
// https://arduinojson.org/v7/api/jsonvariantconst/is/
|
||||
template <typename T>
|
||||
detail::enable_if_t<ConversionSupported<T>::value, bool> is() const {
|
||||
template <typename T,
|
||||
detail::enable_if_t<ConversionSupported<T>::value, int> = 0>
|
||||
bool is() const {
|
||||
return Converter<T>::checkJson(*this);
|
||||
}
|
||||
|
||||
// Always returns false for the unsupported types.
|
||||
// https://arduinojson.org/v7/api/jsonvariantconst/is/
|
||||
template <typename T>
|
||||
detail::enable_if_t<!ConversionSupported<T>::value, bool> is() const {
|
||||
template <typename T,
|
||||
detail::enable_if_t<!ConversionSupported<T>::value, int> = 0>
|
||||
bool is() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -99,9 +101,9 @@ class JsonVariantConst : public detail::VariantTag,
|
||||
|
||||
// Gets array's element at specified index.
|
||||
// https://arduinojson.org/v7/api/jsonvariantconst/subscript/
|
||||
template <typename T>
|
||||
detail::enable_if_t<detail::is_integral<T>::value, JsonVariantConst>
|
||||
operator[](T index) const {
|
||||
template <typename T,
|
||||
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||
JsonVariantConst operator[](T index) const {
|
||||
return JsonVariantConst(
|
||||
detail::VariantData::getElement(data_, size_t(index), resources_),
|
||||
resources_);
|
||||
@ -109,9 +111,9 @@ class JsonVariantConst : public detail::VariantTag,
|
||||
|
||||
// Gets object's member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonvariantconst/subscript/
|
||||
template <typename TString>
|
||||
detail::enable_if_t<detail::IsString<TString>::value, JsonVariantConst>
|
||||
operator[](const TString& key) const {
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
JsonVariantConst operator[](const TString& key) const {
|
||||
return JsonVariantConst(detail::VariantData::getMember(
|
||||
data_, detail::adaptString(key), resources_),
|
||||
resources_);
|
||||
@ -119,9 +121,11 @@ class JsonVariantConst : public detail::VariantTag,
|
||||
|
||||
// Gets object's member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonvariantconst/subscript/
|
||||
template <typename TChar>
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value, JsonVariantConst>
|
||||
operator[](TChar* key) const {
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
JsonVariantConst operator[](TChar* key) const {
|
||||
return JsonVariantConst(detail::VariantData::getMember(
|
||||
data_, detail::adaptString(key), resources_),
|
||||
resources_);
|
||||
@ -130,41 +134,43 @@ class JsonVariantConst : public detail::VariantTag,
|
||||
// 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 TVariant>
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, JsonVariantConst>
|
||||
operator[](const TVariant& key) const {
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
JsonVariantConst operator[](const TVariant& key) const {
|
||||
if (key.template is<size_t>())
|
||||
return operator[](key.template as<size_t>());
|
||||
else
|
||||
return operator[](key.template as<const char*>());
|
||||
return operator[](key.template as<JsonString>());
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonvariantconst/containskey/
|
||||
template <typename TString>
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use var[key].is<T>() instead")
|
||||
detail::enable_if_t<detail::IsString<TString>::value, bool> containsKey(
|
||||
const TString& key) const {
|
||||
bool containsKey(const TString& key) const {
|
||||
return detail::VariantData::getMember(getData(), detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj["key"].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonvariantconst/containskey/
|
||||
template <typename TChar>
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use obj[\"key\"].is<T>() instead")
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value, bool> containsKey(
|
||||
TChar* key) const {
|
||||
bool containsKey(TChar* key) const {
|
||||
return detail::VariantData::getMember(getData(), detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonvariantconst/containskey/
|
||||
template <typename TVariant>
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use var[key].is<T>() instead")
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, bool> containsKey(
|
||||
const TVariant& key) const {
|
||||
bool containsKey(const TVariant& key) const {
|
||||
return containsKey(key.template as<const char*>());
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class JsonVariantCopier {
|
||||
public:
|
||||
typedef bool result_type;
|
||||
using result_type = bool;
|
||||
|
||||
JsonVariantCopier(JsonVariant dst) : dst_(dst) {}
|
||||
|
||||
|
@ -13,7 +13,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TResult>
|
||||
struct JsonVariantVisitor {
|
||||
typedef TResult result_type;
|
||||
using result_type = TResult;
|
||||
|
||||
template <typename T>
|
||||
TResult visit(const T&) {
|
||||
|
@ -64,12 +64,11 @@ class VariantData {
|
||||
return visit.visit(content_.asObject);
|
||||
|
||||
case VariantType::LinkedString:
|
||||
return visit.visit(JsonString(content_.asLinkedString));
|
||||
return visit.visit(JsonString(content_.asLinkedString, true));
|
||||
|
||||
case VariantType::OwnedString:
|
||||
return visit.visit(JsonString(content_.asOwnedString->data,
|
||||
content_.asOwnedString->length,
|
||||
JsonString::Copied));
|
||||
content_.asOwnedString->length));
|
||||
|
||||
case VariantType::RawString:
|
||||
return visit.visit(RawString(content_.asOwnedString->data,
|
||||
@ -119,14 +118,13 @@ class VariantData {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool addValue(T&& value, ResourceManager* resources) {
|
||||
bool addValue(const T& value, ResourceManager* resources) {
|
||||
auto array = isNull() ? &toArray() : asArray();
|
||||
return detail::ArrayData::addValue(array, detail::forward<T>(value),
|
||||
resources);
|
||||
return detail::ArrayData::addValue(array, value, resources);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool addValue(VariantData* var, T&& value,
|
||||
static bool addValue(VariantData* var, const T& value,
|
||||
ResourceManager* resources) {
|
||||
if (!var)
|
||||
return false;
|
||||
@ -262,7 +260,7 @@ class VariantData {
|
||||
switch (type_) {
|
||||
case VariantType::RawString:
|
||||
return JsonString(content_.asOwnedString->data,
|
||||
content_.asOwnedString->length, JsonString::Copied);
|
||||
content_.asOwnedString->length);
|
||||
default:
|
||||
return JsonString();
|
||||
}
|
||||
@ -271,10 +269,10 @@ class VariantData {
|
||||
JsonString asString() const {
|
||||
switch (type_) {
|
||||
case VariantType::LinkedString:
|
||||
return JsonString(content_.asLinkedString, JsonString::Linked);
|
||||
return JsonString(content_.asLinkedString, true);
|
||||
case VariantType::OwnedString:
|
||||
return JsonString(content_.asOwnedString->data,
|
||||
content_.asOwnedString->length, JsonString::Copied);
|
||||
content_.asOwnedString->length);
|
||||
default:
|
||||
return JsonString();
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TResult>
|
||||
struct VariantDataVisitor {
|
||||
typedef TResult result_type;
|
||||
using result_type = TResult;
|
||||
|
||||
template <typename T>
|
||||
TResult visit(const T&) {
|
||||
|
@ -26,7 +26,7 @@ inline bool VariantData::setString(TAdaptedString value,
|
||||
if (value.isNull())
|
||||
return false;
|
||||
|
||||
if (value.isLinked()) {
|
||||
if (value.isStatic()) {
|
||||
setLinkedString(value.data());
|
||||
return true;
|
||||
}
|
||||
|
@ -30,9 +30,9 @@ struct VariantOperators : VariantOperatorTag {
|
||||
// int operator|(JsonVariant, int)
|
||||
// float operator|(JsonVariant, float)
|
||||
// bool operator|(JsonVariant, bool)
|
||||
template <typename T>
|
||||
friend enable_if_t<!IsVariant<T>::value && !is_array<T>::value, T> operator|(
|
||||
const TVariant& variant, const T& defaultValue) {
|
||||
template <typename T,
|
||||
enable_if_t<!IsVariant<T>::value && !is_array<T>::value, int> = 0>
|
||||
friend T operator|(const TVariant& variant, const T& defaultValue) {
|
||||
if (variant.template is<T>())
|
||||
return variant.template as<T>();
|
||||
else
|
||||
@ -51,7 +51,7 @@ struct VariantOperators : VariantOperatorTag {
|
||||
// JsonVariant operator|(JsonVariant, JsonVariant)
|
||||
template <typename T>
|
||||
friend enable_if_t<IsVariant<T>::value, JsonVariantConst> operator|(
|
||||
const TVariant& variant, T defaultValue) {
|
||||
const TVariant& variant, const T& defaultValue) {
|
||||
if (variant)
|
||||
return variant;
|
||||
else
|
||||
@ -60,127 +60,127 @@ struct VariantOperators : VariantOperatorTag {
|
||||
|
||||
// value == TVariant
|
||||
template <typename T>
|
||||
friend bool operator==(T* lhs, TVariant rhs) {
|
||||
friend bool operator==(T* lhs, const TVariant& rhs) {
|
||||
return compare(rhs, lhs) == COMPARE_RESULT_EQUAL;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator==(const T& lhs, TVariant rhs) {
|
||||
friend bool operator==(const T& lhs, const TVariant& rhs) {
|
||||
return compare(rhs, lhs) == COMPARE_RESULT_EQUAL;
|
||||
}
|
||||
|
||||
// TVariant == value
|
||||
template <typename T>
|
||||
friend bool operator==(TVariant lhs, T* rhs) {
|
||||
friend bool operator==(const TVariant& lhs, T* rhs) {
|
||||
return compare(lhs, rhs) == COMPARE_RESULT_EQUAL;
|
||||
}
|
||||
template <typename T>
|
||||
friend enable_if_t<!is_base_of<VariantOperatorTag, T>::value, bool>
|
||||
operator==(TVariant lhs, const T& rhs) {
|
||||
template <typename T,
|
||||
enable_if_t<!is_base_of<VariantOperatorTag, T>::value, int> = 0>
|
||||
friend bool operator==(const TVariant& lhs, const T& rhs) {
|
||||
return compare(lhs, rhs) == COMPARE_RESULT_EQUAL;
|
||||
}
|
||||
|
||||
// value != TVariant
|
||||
template <typename T>
|
||||
friend bool operator!=(T* lhs, TVariant rhs) {
|
||||
friend bool operator!=(T* lhs, const TVariant& rhs) {
|
||||
return compare(rhs, lhs) != COMPARE_RESULT_EQUAL;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator!=(const T& lhs, TVariant rhs) {
|
||||
friend bool operator!=(const T& lhs, const TVariant& rhs) {
|
||||
return compare(rhs, lhs) != COMPARE_RESULT_EQUAL;
|
||||
}
|
||||
|
||||
// TVariant != value
|
||||
template <typename T>
|
||||
friend bool operator!=(TVariant lhs, T* rhs) {
|
||||
friend bool operator!=(const TVariant& lhs, T* rhs) {
|
||||
return compare(lhs, rhs) != COMPARE_RESULT_EQUAL;
|
||||
}
|
||||
template <typename T>
|
||||
friend enable_if_t<!is_base_of<VariantOperatorTag, T>::value, bool>
|
||||
operator!=(TVariant lhs, const T& rhs) {
|
||||
template <typename T,
|
||||
enable_if_t<!is_base_of<VariantOperatorTag, T>::value, int> = 0>
|
||||
friend bool operator!=(TVariant lhs, const T& rhs) {
|
||||
return compare(lhs, rhs) != COMPARE_RESULT_EQUAL;
|
||||
}
|
||||
|
||||
// value < TVariant
|
||||
template <typename T>
|
||||
friend bool operator<(T* lhs, TVariant rhs) {
|
||||
friend bool operator<(T* lhs, const TVariant& rhs) {
|
||||
return compare(rhs, lhs) == COMPARE_RESULT_GREATER;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator<(const T& lhs, TVariant rhs) {
|
||||
friend bool operator<(const T& lhs, const TVariant& rhs) {
|
||||
return compare(rhs, lhs) == COMPARE_RESULT_GREATER;
|
||||
}
|
||||
|
||||
// TVariant < value
|
||||
template <typename T>
|
||||
friend bool operator<(TVariant lhs, T* rhs) {
|
||||
friend bool operator<(const TVariant& lhs, T* rhs) {
|
||||
return compare(lhs, rhs) == COMPARE_RESULT_LESS;
|
||||
}
|
||||
template <typename T>
|
||||
friend enable_if_t<!is_base_of<VariantOperatorTag, T>::value, bool> operator<(
|
||||
TVariant lhs, const T& rhs) {
|
||||
template <typename T,
|
||||
enable_if_t<!is_base_of<VariantOperatorTag, T>::value, int> = 0>
|
||||
friend bool operator<(TVariant lhs, const T& rhs) {
|
||||
return compare(lhs, rhs) == COMPARE_RESULT_LESS;
|
||||
}
|
||||
|
||||
// value <= TVariant
|
||||
template <typename T>
|
||||
friend bool operator<=(T* lhs, TVariant rhs) {
|
||||
friend bool operator<=(T* lhs, const TVariant& rhs) {
|
||||
return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator<=(const T& lhs, TVariant rhs) {
|
||||
friend bool operator<=(const T& lhs, const TVariant& rhs) {
|
||||
return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
|
||||
}
|
||||
|
||||
// TVariant <= value
|
||||
template <typename T>
|
||||
friend bool operator<=(TVariant lhs, T* rhs) {
|
||||
friend bool operator<=(const TVariant& lhs, T* rhs) {
|
||||
return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend enable_if_t<!is_base_of<VariantOperatorTag, T>::value, bool>
|
||||
operator<=(TVariant lhs, const T& rhs) {
|
||||
template <typename T,
|
||||
enable_if_t<!is_base_of<VariantOperatorTag, T>::value, int> = 0>
|
||||
friend bool operator<=(TVariant lhs, const T& rhs) {
|
||||
return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
|
||||
}
|
||||
|
||||
// value > TVariant
|
||||
template <typename T>
|
||||
friend bool operator>(T* lhs, TVariant rhs) {
|
||||
friend bool operator>(T* lhs, const TVariant& rhs) {
|
||||
return compare(rhs, lhs) == COMPARE_RESULT_LESS;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator>(const T& lhs, TVariant rhs) {
|
||||
friend bool operator>(const T& lhs, const TVariant& rhs) {
|
||||
return compare(rhs, lhs) == COMPARE_RESULT_LESS;
|
||||
}
|
||||
|
||||
// TVariant > value
|
||||
template <typename T>
|
||||
friend bool operator>(TVariant lhs, T* rhs) {
|
||||
friend bool operator>(const TVariant& lhs, T* rhs) {
|
||||
return compare(lhs, rhs) == COMPARE_RESULT_GREATER;
|
||||
}
|
||||
template <typename T>
|
||||
friend enable_if_t<!is_base_of<VariantOperatorTag, T>::value, bool> operator>(
|
||||
TVariant lhs, const T& rhs) {
|
||||
template <typename T,
|
||||
enable_if_t<!is_base_of<VariantOperatorTag, T>::value, int> = 0>
|
||||
friend bool operator>(TVariant lhs, const T& rhs) {
|
||||
return compare(lhs, rhs) == COMPARE_RESULT_GREATER;
|
||||
}
|
||||
|
||||
// value >= TVariant
|
||||
template <typename T>
|
||||
friend bool operator>=(T* lhs, TVariant rhs) {
|
||||
friend bool operator>=(T* lhs, const TVariant& rhs) {
|
||||
return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator>=(const T& lhs, TVariant rhs) {
|
||||
friend bool operator>=(const T& lhs, const TVariant& rhs) {
|
||||
return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
|
||||
}
|
||||
|
||||
// TVariant >= value
|
||||
template <typename T>
|
||||
friend bool operator>=(TVariant lhs, T* rhs) {
|
||||
friend bool operator>=(const TVariant& lhs, T* rhs) {
|
||||
return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend enable_if_t<!is_base_of<VariantOperatorTag, T>::value, bool>
|
||||
operator>=(TVariant lhs, const T& rhs) {
|
||||
template <typename T,
|
||||
enable_if_t<!is_base_of<VariantOperatorTag, T>::value, int> = 0>
|
||||
friend bool operator>=(const TVariant& lhs, const T& rhs) {
|
||||
return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
|
||||
}
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user