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