How to create converters for STL containers?
Custom converters allow ArduinoJson to support user-defined types. This page shows how we can write converters for STL containers.
I’ll probably include these converters in the library someday.
std::vector
The following class adds support for std::vector<T>
.
Of course, T
itself has to be supported by ArduinoJson, either natively or through a custom converter.
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
struct Converter<std::vector<T> > {
static void toJson(const std::vector<T>& src, JsonVariant dst) {
JsonArray array = dst.to<JsonArray>();
for (T item : src)
array.add(item);
}
static std::vector<T> fromJson(JsonVariantConst src) {
std::vector<T> dst;
for (T item : src.as<JsonArrayConst>())
dst.push_back(item);
return dst;
}
static bool checkJson(JsonVariantConst src) {
JsonArrayConst array = src;
bool result = array;
for (JsonVariantConst item : array)
result &= item.is<T>();
return result;
}
};
} // namespace ARDUINOJSON_NAMESPACE
Thanks to this converter, you can now write thinks like this:
std::vector<int> v1 = {1, 2};
doc["values"] = v1;
if (doc["values"].is<std::vector<int> >()) {
std::vector<int> v2 = doc["values"];
// ...
}
The same technique works with std::list
. If you’re a TMP wizard, you can write a generic implementation by leveraging the Enable
template parameter of Converter
.
std::array
For std::array
, we need a different converter because:
- it doesn’t support the
push_back()
operation - it has a fixed size, so
checkJson()
must check it
Here is a possible implementation:
namespace ARDUINOJSON_NAMESPACE {
template <typename T, size_t N>
struct Converter<std::array<T, N> > {
static void toJson(const std::array<T, N>& src, JsonVariant dst) {
JsonArray array = dst.to<JsonArray>();
for (T item : src)
array.add(item);
}
static std::array<T, N> fromJson(JsonVariantConst src) {
std::array<T, N> dst;
size_t idx = 0;
for (T item : src.as<JsonArrayConst>())
dst[idx++] = item;
return dst;
}
static bool checkJson(JsonVariantConst src) {
JsonArrayConst array = src;
bool result = array;
size_t size = 0;
for (JsonVariantConst item : array) {
result &= item.is<T>();
size++;
}
return result && size == N;
}
};
} // namespace ARDUINOJSON_NAMESPACE
std::map
Here is the implementation for std::map<std::string, T>
, you can use a similar implementation for std::unordered_map
.
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
struct Converter<std::map<std::string, T> > {
static void toJson(const std::map<std::string, T>& src, JsonVariant dst) {
JsonObject obj = dst.to<JsonObject>();
for (const auto& item : src)
obj[item.first] = item.second;
}
static std::map<std::string, T> fromJson(JsonVariantConst src) {
std::map<std::string, T> dst;
for (JsonPairConst item : src.as<JsonObjectConst>())
dst[item.key().c_str()] = item.value().as<T>();
return dst;
}
static bool checkJson(JsonVariantConst src) {
JsonObjectConst obj = src;
bool result = obj;
for (JsonPairConst item : obj)
result &= item.value().is<T>();
return result;
}
};
} // namespace ARDUINOJSON_NAMESPACE