LeviLamina
Loading...
Searching...
No Matches
Deserialization.h
1#pragma once
2
3#include "ll/api/reflection/Reflection.h"
4#include "ll/api/reflection/SerializationError.h"
5
6// Priority:
7// 5. IsVectorBase IsDispatcher IsOptional
8// 4. string
9// 3. TupleLike
10// 2. ArrayLike Associative
11// 1. Reflectable enum
12// 0. convertible
13
14namespace ll::reflection {
15template <concepts::IsVectorBase T, class J>
16inline Expected<> deserialize_impl(T& vec, J&& j, meta::PriorityTag<5>);
17template <concepts::IsDispatcher T, class J>
18inline Expected<> deserialize_impl(T& d, J&& j, meta::PriorityTag<5>);
19template <concepts::IsOptional T, class J>
20inline Expected<> deserialize_impl(T& opt, J&& j, meta::PriorityTag<5>);
21template <concepts::IsString T, class J>
22inline Expected<> deserialize_impl(T& str, J&& j, meta::PriorityTag<4>);
23template <concepts::TupleLike T, class J>
24inline Expected<> deserialize_impl(T& tuple, J&& j, meta::PriorityTag<3>);
25template <concepts::ArrayLike T, class J>
26inline Expected<> deserialize_impl(T& arr, J&& j, meta::PriorityTag<2>);
27template <concepts::Associative T, class J>
28inline Expected<> deserialize_impl(T& map, J const& j, meta::PriorityTag<2>);
29template <Reflectable T, class J>
30inline Expected<> deserialize_impl(T& obj, J const& j, meta::PriorityTag<1>);
31template <concepts::Require<std::is_enum> T, class J>
32inline Expected<> deserialize_impl(T& e, J const& j, meta::PriorityTag<1>);
33template <class T, class J>
34inline Expected<> deserialize_impl(T& obj, J const& j, meta::PriorityTag<0>)
35 requires(std::convertible_to<J, T>);
36
37template <class T, class J>
38[[nodiscard]] inline Expected<> deserialize(T& t, J&& j) noexcept
39#if !defined(__INTELLISENSE__)
40 requires(requires(T& t, J&& j) { deserialize_impl<T>(t, std::forward<J>(j), meta::PriorityTag<5>{}); })
41#endif
42try {
43 return deserialize_impl<T>(t, std::forward<J>(j), meta::PriorityTag<5>{});
44} catch (...) {
45 return makeExceptionError();
46}
47
48template <class T, class J>
49[[nodiscard]] inline Expected<T> deserialize_to(J&& j) noexcept {
50 Expected<T> res{};
51 if (auto d = deserialize<T>(*res, std::forward<J>(j)); !d) {
52 res = forwardError(d.error());
53 }
54 return res;
55}
56
57template <concepts::IsVectorBase T, class J>
58inline Expected<> deserialize_impl(T& vec, J&& j, meta::PriorityTag<5>) {
59 Expected<> res{};
60 T::forEachComponent([&]<typename axis_type, size_t iter> {
61 if (res) {
62 res = deserialize<axis_type>(vec.template get<axis_type, iter>(), static_cast<J&&>(j[iter]));
63 if (!res) res = makeSerIndexError(iter, res.error());
64 }
65 });
66 return res;
67}
68template <concepts::IsDispatcher T, class J>
69inline Expected<> deserialize_impl(T& d, J&& j, meta::PriorityTag<5>) {
70 auto res{deserialize<typename T::storage_type>(d.storage, std::forward<J>(j))};
71 if (res) d.call();
72 return res;
73}
74template <concepts::IsOptional T, class J>
75inline Expected<> deserialize_impl(T& opt, J&& j, meta::PriorityTag<5>) {
76 Expected<> res;
77 if (j.is_null()) {
78 opt = std::nullopt;
79 } else {
80 if (!opt) opt.emplace();
81 res = deserialize<typename T::value_type>(*opt, std::forward<J>(j));
82 }
83 return res;
84}
85template <concepts::IsString T, class J>
86inline Expected<> deserialize_impl(T& str, J&& j, meta::PriorityTag<4>) {
87 if (!j.is_string()) return makeStringError("field must be a string");
88 str = std::string{std::forward<J>(j)};
89 return {};
90}
91template <concepts::TupleLike T, class J>
92inline Expected<> deserialize_impl(T& tuple, J&& j, meta::PriorityTag<3>) {
93 if (!j.is_array()) return makeStringError("field must be an array");
94 if (j.size() != std::tuple_size_v<T>)
95 return makeStringError(fmt::format("array size must be {}", std::tuple_size_v<T>));
96 Expected<> res{};
97 std::apply(
98 [&](auto&... args) {
99 size_t iter{0};
100 (([&](auto& arg) {
101 if (res) {
102 res = deserialize<std::remove_cvref_t<decltype(arg)>>(arg, static_cast<J&&>(j[iter]));
103 if (!res) res = makeSerIndexError(iter, res.error());
104 iter++;
105 }
106 }(args)),
107 ...);
108 },
109 tuple
110 );
111 return res;
112}
113template <concepts::ArrayLike T, class J>
114inline Expected<> deserialize_impl(T& arr, J&& j, meta::PriorityTag<2>) {
115 if (!j.is_array()) return makeStringError("field must be an array");
116 using value_type = typename T::value_type;
117 if constexpr (requires(T a) { a.clear(); }) {
118 arr.clear();
119 }
120 if constexpr (requires(T a, value_type v) { a.push_back(v); }) {
121 for (size_t i = 0; i < j.size(); i++) {
122 if (auto res = deserialize<value_type>(arr.emplace_back(), static_cast<J&&>(j[i])); !res) {
123 res = makeSerIndexError(i, res.error());
124 return res;
125 }
126 }
127 } else if constexpr (requires(T a, value_type v) { a.insert(v); }) {
128 for (size_t i = 0; i < j.size(); i++) {
129 value_type tmp{};
130 if (auto res = deserialize<value_type>(tmp, static_cast<J&&>(j[i])); !res) {
131 res = makeSerIndexError(i, res.error());
132 return res;
133 }
134 arr.insert(std::move(tmp));
135 }
136 }
137 return {};
138}
139template <concepts::Associative T, class J>
140inline Expected<> deserialize_impl(T& map, J const& j, meta::PriorityTag<2>) {
141 static_assert(
142 (concepts::IsString<typename T::key_type> || std::is_enum_v<typename T::key_type>),
143 "the key type of the associative container must be convertible to a string"
144 );
145 if (!j.is_object()) return makeStringError("field must be an object");
146 map.clear();
147 for (auto&& [k, v] : j.items()) {
148 if constexpr (std::is_enum_v<typename T::key_type>) {
149 if (auto res = deserialize<typename T::mapped_type>(
150 map[magic_enum::enum_cast<typename T::key_type>(k).value()],
151 std::forward<decltype((v))>(v)
152 );
153 !res) {
154 res = makeSerKeyError(magic_enum::enum_cast<typename T::key_type>(k).value(), res.error());
155 return res;
156 }
157 } else {
158 if (auto res = deserialize<typename T::mapped_type>(map[k], std::forward<decltype((v))>(v)); !res) {
159 res = makeSerKeyError(k, res.error());
160 return res;
161 }
162 }
163 }
164 return {};
165}
166template <Reflectable T, class J>
167inline Expected<> deserialize_impl(T& obj, J const& j, meta::PriorityTag<1>) {
168 Expected<> res;
169 if (!j.is_object()) {
170 res = makeStringError("field must be an object");
171 return res;
172 }
173 forEachMember(obj, [&](std::string_view name, auto& member) {
174 if (name.starts_with('$') || !res) {
175 return;
176 }
177 using member_type = std::remove_cvref_t<decltype((member))>;
178 auto sname = std::string{name};
179 if (j.contains(sname)) {
180 if constexpr (requires(member_type& o, J const& s) { deserialize<member_type>(o, s); }) {
181 res = deserialize<member_type>(member, j[sname]);
182 if (!res) res = makeSerMemberError(sname, res.error());
183 } else {
184 static_assert(traits::always_false<member_type>, "this type can't deserialize");
185 }
186 } else {
187 if constexpr (!concepts::IsOptional<member_type>) {
188 res = makeStringError(fmt::format("missing required field \"{}\" when deserializing", sname));
189 } else {
190 member = std::nullopt;
191 }
192 }
193 });
194 return res;
195}
196template <concepts::Require<std::is_enum> T, class J>
197inline Expected<> deserialize_impl(T& e, J const& j, meta::PriorityTag<1>) {
198 using enum_type = std::remove_cvref_t<T>;
199 if (j.is_string()) {
200 e = magic_enum::enum_cast<enum_type>(std::string{j}).value();
201 } else {
202 e = magic_enum::enum_cast<enum_type>(std::underlying_type_t<enum_type>{j}).value();
203 }
204 return {};
205}
206template <class T, class J>
207inline Expected<> deserialize_impl(T& obj, J const& j, meta::PriorityTag<0>)
208 requires(std::convertible_to<J, T>)
209{
210 obj = j;
211 return {};
212}
213} // namespace ll::reflection