Skip to content

Commit 0b06807

Browse files
committed
extend JSOn convertion to include vectors
1 parent ac26aea commit 0b06807

File tree

5 files changed

+232
-61
lines changed

5 files changed

+232
-61
lines changed

include/behaviortree_cpp/json_export.h

+52-10
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace BT
1111
{
1212

1313
/**
14-
* To add new type to the JSON library, you should follow these isntructions:
14+
* To add new type to the JSON library, you should follow these instructions:
1515
* https://json.nlohmann.me/features/arbitrary_types/
1616
*
1717
* Considering for instance the type:
@@ -105,6 +105,7 @@ class JsonExporter
105105

106106
std::unordered_map<std::type_index, ToJonConverter> to_json_converters_;
107107
std::unordered_map<std::type_index, FromJonConverter> from_json_converters_;
108+
std::unordered_map<std::type_index, FromJonConverter> from_json_array_converters_;
108109
std::unordered_map<std::string, BT::TypeInfo> type_names_;
109110
};
110111

@@ -129,6 +130,15 @@ inline Expected<T> JsonExporter::fromJson(const nlohmann::json& source) const
129130
template <typename T>
130131
inline void JsonExporter::addConverter()
131132
{
133+
// we need to get the name of the type
134+
nlohmann::json const js = T{};
135+
// we insert both the name obtained from JSON and demangle
136+
if(js.contains("__type"))
137+
{
138+
type_names_.insert({ std::string(js["__type"]), BT::TypeInfo::Create<T>() });
139+
}
140+
type_names_.insert({ BT::demangle(typeid(T)), BT::TypeInfo::Create<T>() });
141+
132142
ToJonConverter to_converter = [](const BT::Any& entry, nlohmann::json& dst) {
133143
dst = *const_cast<BT::Any&>(entry).castPtr<T>();
134144
};
@@ -139,16 +149,23 @@ inline void JsonExporter::addConverter()
139149
return { BT::Any(value), BT::TypeInfo::Create<T>() };
140150
};
141151

142-
// we need to get the name of the type
143-
nlohmann::json const js = T{};
144-
// we insert both the name obtained from JSON and demangle
145-
if(js.contains("__type"))
146-
{
147-
type_names_.insert({ std::string(js["__type"]), BT::TypeInfo::Create<T>() });
148-
}
149-
type_names_.insert({ BT::demangle(typeid(T)), BT::TypeInfo::Create<T>() });
150-
151152
from_json_converters_.insert({ typeid(T), from_converter });
153+
154+
//---- include vectors of T
155+
ToJonConverter to_array_converter = [](const BT::Any& entry, nlohmann::json& dst) {
156+
dst = *const_cast<BT::Any&>(entry).castPtr<std::vector<T>>();
157+
};
158+
to_json_converters_.insert({ typeid(std::vector<T>), to_array_converter });
159+
160+
FromJonConverter from_array_converter = [](const nlohmann::json& src) -> Entry {
161+
std::vector<T> value;
162+
for(const auto& item : src)
163+
{
164+
value.push_back(item.get<T>());
165+
}
166+
return { BT::Any(value), BT::TypeInfo::Create<std::vector<T>>() };
167+
};
168+
from_json_array_converters_.insert({ typeid(T), from_array_converter });
152169
}
153170

154171
template <typename T>
@@ -163,6 +180,18 @@ inline void JsonExporter::addConverter(
163180
}
164181
};
165182
to_json_converters_.insert({ typeid(T), std::move(converter) });
183+
//---------------------------------------------
184+
// add the vector<T> converter
185+
auto vector_converter = [converter](const BT::Any& entry, nlohmann::json& json) {
186+
auto& vec = *const_cast<BT::Any&>(entry).castPtr<std::vector<T>>();
187+
for(const auto& item : vec)
188+
{
189+
nlohmann::json item_json;
190+
converter(BT::Any(item), item_json);
191+
json.push_back(item_json);
192+
}
193+
};
194+
to_json_converters_.insert({ typeid(std::vector<T>), std::move(vector_converter) });
166195
}
167196

168197
template <typename T>
@@ -176,6 +205,19 @@ JsonExporter::addConverter(std::function<void(const nlohmann::json&, T&)> func)
176205
};
177206
type_names_.insert({ BT::demangle(typeid(T)), BT::TypeInfo::Create<T>() });
178207
from_json_converters_.insert({ typeid(T), std::move(converter) });
208+
//---------------------------------------------
209+
// add the vector<T> converter
210+
auto vector_converter = [func](const nlohmann::json& json) -> Entry {
211+
std::vector<T> tmp;
212+
for(const auto& item : json)
213+
{
214+
T item_tmp;
215+
func(item, item_tmp);
216+
tmp.push_back(item_tmp);
217+
}
218+
return { BT::Any(tmp), BT::TypeInfo::Create<std::vector<T>>() };
219+
};
220+
from_json_array_converters_.insert({ typeid(T), std::move(vector_converter) });
179221
}
180222

181223
template <typename T>

include/behaviortree_cpp/utils/safe_any.hpp

+1-26
Original file line numberDiff line numberDiff line change
@@ -162,32 +162,7 @@ class Any
162162
[[nodiscard]] T* castPtr()
163163
{
164164
static_assert(!std::is_same_v<T, float>, "The value has been casted internally to "
165-
"[double]. "
166-
"Use that instead");
167-
static_assert(!SafeAny::details::is_integer<T>() || std::is_same_v<T, uint64_t>, "The"
168-
" va"
169-
"lue"
170-
" ha"
171-
"s "
172-
"bee"
173-
"n "
174-
"cas"
175-
"ted"
176-
" in"
177-
"ter"
178-
"nal"
179-
"ly "
180-
"to "
181-
"[in"
182-
"t64"
183-
"_t]"
184-
". "
185-
"Use"
186-
" th"
187-
"at "
188-
"ins"
189-
"tea"
190-
"d");
165+
"[double]. Use that instead");
191166

192167
return _any.empty() ? nullptr : linb::any_cast<T>(&_any);
193168
}

src/bt_factory.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include <filesystem>
1414
#include "behaviortree_cpp/bt_factory.h"
1515
#include "behaviortree_cpp/utils/shared_library.h"
16-
#include "behaviortree_cpp/contrib/json.hpp"
1716
#include "behaviortree_cpp/xml_parsing.h"
1817
#include "wildcards/wildcards.hpp"
1918

src/json_export.cpp

+54-10
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,22 @@ bool JsonExporter::toJson(const Any& any, nlohmann::json& dst) const
3030
{
3131
dst = any.cast<double>();
3232
}
33+
else if(type == typeid(std::vector<double>))
34+
{
35+
dst = any.cast<std::vector<double>>();
36+
}
37+
else if(type == typeid(std::vector<int>))
38+
{
39+
dst = any.cast<std::vector<int>>();
40+
}
41+
else if(type == typeid(std::vector<std::string>))
42+
{
43+
dst = any.cast<std::vector<std::string>>();
44+
}
45+
else if(type == typeid(std::vector<bool>))
46+
{
47+
dst = any.cast<std::vector<bool>>();
48+
}
3349
else
3450
{
3551
auto it = to_json_converters_.find(type);
@@ -49,20 +65,17 @@ JsonExporter::ExpectedEntry JsonExporter::fromJson(const nlohmann::json& source)
4965
{
5066
if(source.is_null())
5167
{
52-
return nonstd::make_unexpected("json object is null");
68+
return Entry{ BT::Any(), BT::TypeInfo::Create<std::nullptr_t>() };
5369
}
70+
5471
if(source.is_string())
5572
{
5673
return Entry{ BT::Any(source.get<std::string>()),
5774
BT::TypeInfo::Create<std::string>() };
5875
}
59-
if(source.is_number_unsigned())
60-
{
61-
return Entry{ BT::Any(source.get<uint64_t>()), BT::TypeInfo::Create<uint64_t>() };
62-
}
6376
if(source.is_number_integer())
6477
{
65-
return Entry{ BT::Any(source.get<int64_t>()), BT::TypeInfo::Create<int64_t>() };
78+
return Entry{ BT::Any(source.get<int>()), BT::TypeInfo::Create<int>() };
6679
}
6780
if(source.is_number_float())
6881
{
@@ -73,17 +86,48 @@ JsonExporter::ExpectedEntry JsonExporter::fromJson(const nlohmann::json& source)
7386
return Entry{ BT::Any(source.get<bool>()), BT::TypeInfo::Create<bool>() };
7487
}
7588

76-
if(!source.contains("__type"))
89+
// basic vectors
90+
if(source.is_array() && source.size() > 0 && !source.contains("__type"))
91+
{
92+
auto first_element = source[0];
93+
if(first_element.is_string())
94+
{
95+
return Entry{ BT::Any(source.get<std::vector<std::string>>()),
96+
BT::TypeInfo::Create<std::vector<std::string>>() };
97+
}
98+
if(first_element.is_number_integer())
99+
{
100+
return Entry{ BT::Any(source.get<std::vector<int>>()),
101+
BT::TypeInfo::Create<std::vector<int>>() };
102+
}
103+
if(first_element.is_number_float())
104+
{
105+
return Entry{ BT::Any(source.get<std::vector<double>>()),
106+
BT::TypeInfo::Create<std::vector<double>>() };
107+
}
108+
if(first_element.is_boolean())
109+
{
110+
return Entry{ BT::Any(source.get<std::vector<bool>>()),
111+
BT::TypeInfo::Create<std::vector<bool>>() };
112+
}
113+
}
114+
115+
if(!source.contains("__type") && !source.is_array())
77116
{
78117
return nonstd::make_unexpected("Missing field '__type'");
79118
}
80-
auto type_it = type_names_.find(source["__type"]);
119+
120+
auto& from_converters =
121+
source.is_array() ? from_json_array_converters_ : from_json_converters_;
122+
auto type_field = source.is_array() ? source[0]["__type"] : source["__type"];
123+
124+
auto type_it = type_names_.find(type_field);
81125
if(type_it == type_names_.end())
82126
{
83127
return nonstd::make_unexpected("Type not found in registered list");
84128
}
85-
auto func_it = from_json_converters_.find(type_it->second.type());
86-
if(func_it == from_json_converters_.end())
129+
auto func_it = from_converters.find(type_it->second.type());
130+
if(func_it == from_converters.end())
87131
{
88132
return nonstd::make_unexpected("Type not found in registered list");
89133
}

0 commit comments

Comments
 (0)