Skip to content

Commit 45e333c

Browse files
committed
fable: Add from_json to adl_serializer<sol::object>
1 parent 5146b3f commit 45e333c

File tree

2 files changed

+190
-0
lines changed

2 files changed

+190
-0
lines changed

fable/include/fable/utility/sol.hpp

+68
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
#include <nlohmann/json.hpp>
3535

36+
#include <sol/state_view.hpp>
3637
#include <sol/object.hpp> // for object
3738
#include <sol/optional.hpp> // for optional
3839
#include <sol/table.hpp> // for table
@@ -58,6 +59,7 @@ namespace nlohmann {
5859
*/
5960
template <>
6061
struct adl_serializer<sol::object> {
62+
// NOLINTNEXTLINE(misc-no-recursion)
6163
static void to_json_array(json& j, const sol::table& tbl) {
6264
if (j.type() != json::value_t::array) {
6365
j = json::array();
@@ -76,6 +78,7 @@ struct adl_serializer<sol::object> {
7678
}
7779
}
7880

81+
// NOLINTNEXTLINE(misc-no-recursion)
7982
static void to_json_object(json& j, const sol::table& tbl) {
8083
if (j.type() != json::value_t::object) {
8184
j = json::object();
@@ -86,6 +89,7 @@ struct adl_serializer<sol::object> {
8689
}
8790
}
8891

92+
// NOLINTNEXTLINE(misc-no-recursion)
8993
static void to_json(json& j, const sol::table& tbl) {
9094
if (tbl.pairs().begin() == tbl.pairs().end()) {
9195
// We don't know whether this is an empty array or an empty object,
@@ -108,6 +112,7 @@ struct adl_serializer<sol::object> {
108112
}
109113
}
110114

115+
// NOLINTNEXTLINE(misc-no-recursion)
111116
static void to_json(json& j, const sol::object& obj) {
112117
switch (obj.get_type()) {
113118
case sol::type::table: {
@@ -155,6 +160,69 @@ struct adl_serializer<sol::object> {
155160
break;
156161
}
157162
}
163+
164+
// NOLINTNEXTLINE(misc-no-recursion)
165+
static void from_json(const json& j, sol::object& obj) {
166+
auto* L = obj.lua_state();
167+
if (L == nullptr) {
168+
throw std::logic_error("can only deserialize to existing sol::object");
169+
}
170+
auto lua = sol::state_view(L);
171+
switch (j.type()) {
172+
case json::value_t::object: {
173+
auto tbl = lua.create_table();
174+
for (const auto& it : j.items()) {
175+
auto tmp = sol::object(L, sol::in_place, nullptr);
176+
from_json(it.value(), tmp);
177+
tbl[it.key()] = tmp;
178+
}
179+
obj = tbl;
180+
break;
181+
}
182+
case json::value_t::null: {
183+
obj = sol::object(L, sol::in_place, nullptr);
184+
break;
185+
}
186+
case json::value_t::array: {
187+
auto tbl = lua.create_table();
188+
for (const auto& el : j) {
189+
auto tmp = sol::object(L, sol::in_place, nullptr);
190+
from_json(el, tmp);
191+
tbl.add(tmp);
192+
}
193+
obj = tbl;
194+
break;
195+
}
196+
case json::value_t::binary: {
197+
obj = sol::object(L, sol::in_place, nullptr);
198+
break;
199+
}
200+
case json::value_t::string: {
201+
obj = sol::object(L, sol::in_place, j.get<std::string>());
202+
break;
203+
}
204+
case json::value_t::boolean: {
205+
obj = sol::object(L, sol::in_place, j.get<bool>());
206+
break;
207+
}
208+
case json::value_t::number_float: {
209+
obj = sol::object(L, sol::in_place, j.get<double>());
210+
break;
211+
}
212+
case json::value_t::number_unsigned: {
213+
obj = sol::object(L, sol::in_place, j.get<unsigned long>());
214+
break;
215+
}
216+
case json::value_t::number_integer: {
217+
obj = sol::object(L, sol::in_place, j.get<signed long>());
218+
break;
219+
}
220+
case json::value_t::discarded: {
221+
obj = sol::object(L, sol::in_place, nullptr);
222+
break;
223+
}
224+
}
225+
}
158226
};
159227

160228
} // namespace nlohmann

fable/src/fable/utility/sol_test.cpp

+122
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,125 @@ TEST(fable_utility_sol, to_json) {
4646
assert_xeq("x = { extra = true, 1, 2, 3 }", R"([ 1, 2, 3, { "extra": true } ])");
4747
assert_xeq("x = {}", "[]");
4848
}
49+
50+
void json_to_lua(sol::state_view& lua, std::string_view field, const fable::Json& json) {
51+
auto tmp = sol::object(lua, sol::in_place, nullptr);
52+
nlohmann::adl_serializer<sol::object>::from_json(json, tmp);
53+
lua[field] = tmp;
54+
}
55+
56+
TEST(fable_utility_sol, from_json_bool) {
57+
auto lua = sol::state();
58+
lua.open_libraries(sol::lib::base);
59+
60+
json_to_lua(lua, "json", Json(true));
61+
lua.script(
62+
R"(
63+
assert(type(json) == "boolean")
64+
assert(json == true)
65+
)");
66+
}
67+
68+
TEST(fable_utility_sol, from_json_int) {
69+
auto lua = sol::state();
70+
lua.open_libraries(sol::lib::base);
71+
72+
json_to_lua(lua, "json", Json(42));
73+
lua.script(
74+
R"(
75+
assert(type(json) == "number")
76+
assert(json == 42)
77+
)");
78+
}
79+
80+
TEST(fable_utility_sol, from_json_float) {
81+
auto lua = sol::state();
82+
lua.open_libraries(sol::lib::base);
83+
84+
json_to_lua(lua, "json", Json(3.14159));
85+
lua.script(
86+
R"(
87+
assert(type(json) == "number")
88+
assert(json == 3.14159)
89+
)");
90+
}
91+
92+
TEST(fable_utility_sol, from_json_string) {
93+
auto lua = sol::state();
94+
lua.open_libraries(sol::lib::base);
95+
96+
json_to_lua(lua, "json", Json("hello world!"));
97+
lua.script(
98+
R"(
99+
assert(type(json) == "string")
100+
assert(json == "hello world!")
101+
)");
102+
}
103+
104+
TEST(fable_utility_sol, from_json_array) {
105+
auto lua = sol::state();
106+
lua.open_libraries(sol::lib::base);
107+
108+
json_to_lua(lua, "json", Json({1, 2, 3}));
109+
lua.script(
110+
R"(
111+
assert(type(json) == "table")
112+
assert(#json == 3)
113+
assert(json[1] == 1)
114+
assert(json[2] == 2)
115+
assert(json[3] == 3)
116+
)");
117+
}
118+
119+
TEST(fable_utility_sol, from_json_object) {
120+
auto lua = sol::state();
121+
lua.open_libraries(sol::lib::base);
122+
123+
auto json = Json{
124+
{"xbool", true},
125+
{"xstring", "hello world!"},
126+
{"xint", -42}, // NOLINT
127+
{"xunsigned", 42u}, // NOLINT
128+
{"xdouble", 42.0}, // NOLINT
129+
{"xarray", {1, 2, 3}},
130+
{"xobject", {
131+
{"foo", "bar"},
132+
}},
133+
{"xnull", nullptr},
134+
};
135+
136+
auto tmp = sol::object(lua["json"]);
137+
nlohmann::adl_serializer<sol::object>::from_json(json, tmp);
138+
lua["json"] = tmp;
139+
lua.script(
140+
R"(
141+
print(json)
142+
assert(json)
143+
144+
print(json.xbool)
145+
assert(json.xbool == true)
146+
147+
print(json.xstring)
148+
assert(json.xstring == "hello world!")
149+
150+
print(json.xint)
151+
assert(json.xint == -42)
152+
153+
print(json.xunsigned)
154+
assert(json.xunsigned == 42)
155+
156+
print(json.xdouble)
157+
assert(json.xdouble == 42.0)
158+
159+
assert(type(json.xarray) == "table")
160+
assert(json.xarray[1] == 1)
161+
assert(json.xarray[3] == 3)
162+
assert(json.xarray[4] == nil)
163+
164+
print(json.xobject)
165+
assert(json.xobject)
166+
assert(json.xobject.foo == "bar")
167+
168+
assert(not json.xnull)
169+
)");
170+
}

0 commit comments

Comments
 (0)