1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef API_UTIL_JSONUTIL_H
17 #define API_UTIL_JSONUTIL_H
18
19 #include <cstdlib>
20 #include <type_traits>
21
22 #include <base/containers/string.h>
23 #include <base/containers/string_view.h>
24 #include <base/math/vector.h>
25 #include <base/math/quaternion.h>
26 #include <base/util/uid_util.h>
27
28 #include <core/json/json.h>
29
30 #include <util/namespace.h>
31
UTIL_BEGIN_NAMESPACE()32 UTIL_BEGIN_NAMESPACE()
33
34 inline BASE_NS::string JsonUnescape(BASE_NS::string_view str)
35 {
36 return CORE_NS::json::unescape(str);
37 }
38
39 template<class T, std::enable_if_t<std::is_arithmetic_v<T>, bool> = true>
SafeGetJsonValue(const CORE_NS::json::value & jsonData,const BASE_NS::string_view element,BASE_NS::string & error,T & output)40 inline bool SafeGetJsonValue(
41 const CORE_NS::json::value& jsonData, const BASE_NS::string_view element, BASE_NS::string& error, T& output)
42 {
43 if (auto const pos = jsonData.find(element); pos) {
44 if (pos->is_number()) {
45 output = pos->as_number<T>();
46 return true;
47 } else if (pos->is_boolean()) {
48 output = pos->boolean_;
49 return true;
50 } else {
51 error += element + ": expected number.\n";
52 }
53 }
54 return false;
55 }
56
57 template<class T, std::enable_if_t<std::is_convertible_v<T, BASE_NS::string_view>, bool> = true>
SafeGetJsonValue(const CORE_NS::json::value & jsonData,const BASE_NS::string_view element,BASE_NS::string & error,T & output)58 inline bool SafeGetJsonValue(
59 const CORE_NS::json::value& jsonData, const BASE_NS::string_view element, BASE_NS::string& error, T& output)
60 {
61 if (auto const pos = jsonData.find(element); pos) {
62 if (pos->is_string()) {
63 output = JsonUnescape(T(pos->string_.data(), pos->string_.size()));
64 return true;
65 } else {
66 error += element + ": expected string.\n";
67 }
68 }
69 return false;
70 }
71
72 template<class T, std::enable_if_t<std::is_arithmetic_v<T>, bool> = true>
FromJson(const CORE_NS::json::value & jsonIn,T & output)73 inline bool FromJson(const CORE_NS::json::value& jsonIn, T& output)
74 {
75 if (jsonIn.is_number()) {
76 output = jsonIn.as_number<T>();
77 return true;
78 }
79 return false;
80 }
81
82 template<class T, std::enable_if_t<std::is_convertible_v<T, BASE_NS::string_view>, bool> = true>
FromJson(const CORE_NS::json::value & jsonIn,T & output)83 inline bool FromJson(const CORE_NS::json::value& jsonIn, T& output)
84 {
85 if (jsonIn.is_string()) {
86 output = JsonUnescape(static_cast<T>(jsonIn.string_));
87 return true;
88 }
89 return false;
90 }
91
FromJson(const CORE_NS::json::value & jsonIn,bool & output)92 inline bool FromJson(const CORE_NS::json::value& jsonIn, bool& output)
93 {
94 if (jsonIn.is_boolean()) {
95 output = jsonIn.boolean_;
96 return true;
97 }
98 return false;
99 }
100
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Uid & output)101 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Uid& output)
102 {
103 constexpr size_t UID_LENGTH = 36; // 36:uid length
104 if (jsonIn.is_string() && jsonIn.string_.size() == UID_LENGTH) {
105 output = StringToUid(JsonUnescape(jsonIn.string_));
106 return true;
107 }
108 return false;
109 }
110
111 template<class T>
FromJsonArray(const CORE_NS::json::value & jsonIn,T * output,size_t size)112 inline bool FromJsonArray(const CORE_NS::json::value& jsonIn, T* output, size_t size)
113 {
114 if (jsonIn.is_array() && jsonIn.array_.size() == size) {
115 for (const auto& element : jsonIn.array_) {
116 if (!FromJson(element, *output)) {
117 return false;
118 }
119 output++;
120 }
121 return true;
122 }
123 return false;
124 }
125
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::Vec2 & output)126 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::Vec2& output)
127 {
128 return FromJsonArray(jsonIn, output.data, 2); // 2 : param
129 }
130
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::Vec3 & output)131 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::Vec3& output)
132 {
133 return FromJsonArray(jsonIn, output.data, 3); // 3 : param
134 }
135
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::Vec4 & output)136 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::Vec4& output)
137 {
138 return FromJsonArray(jsonIn, output.data, 4); // 4 : size
139 }
140
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::UVec2 & output)141 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::UVec2& output)
142 {
143 return FromJsonArray(jsonIn, output.data, 2); // 2 : size
144 }
145
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::UVec3 & output)146 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::UVec3& output)
147 {
148 return FromJsonArray(jsonIn, output.data, 3); // 3 :size
149 }
150
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::UVec4 & output)151 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::UVec4& output)
152 {
153 return FromJsonArray(jsonIn, output.data, 4); // 4 : size
154 }
155
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::Quat & output)156 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::Quat& output)
157 {
158 return FromJsonArray(jsonIn, output.data, 4); // 4 : size
159 }
160
161 template<class T>
ToJson(T value)162 inline CORE_NS::json::standalone_value ToJson(T value)
163 {
164 return CORE_NS::json::standalone_value(value);
165 }
166
167 // how to make more generic?, Does not understand fixed_string
168 template<>
ToJson(BASE_NS::string_view value)169 inline CORE_NS::json::standalone_value ToJson(BASE_NS::string_view value)
170 {
171 return CORE_NS::json::standalone_value(BASE_NS::string{ value });
172 }
173
174 template<>
ToJson(BASE_NS::string value)175 inline CORE_NS::json::standalone_value ToJson(BASE_NS::string value)
176 {
177 return CORE_NS::json::standalone_value(value);
178 }
179
180 template<>
181 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::Vec2>(BASE_NS::Math::Vec2 value)
182 {
183 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
184 json.array_.reserve(2); // 2 : param
185 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
186 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
187 return json;
188 }
189 template<>
190 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::UVec2>(BASE_NS::Math::UVec2 value)
191 {
192 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
193 json.array_.reserve(2); // 2 : param
194 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
195 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
196 return json;
197 }
198
199 template<>
200 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::Vec3>(BASE_NS::Math::Vec3 value)
201 {
202 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
203 json.array_.reserve(3); // 3 : size
204 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
205 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
206 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
207 return json;
208 }
209 template<>
210 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::UVec3>(BASE_NS::Math::UVec3 value)
211 {
212 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
213 json.array_.reserve(3); // 3 : size
214 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
215 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
216 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
217 return json;
218 }
219
220 template<>
221 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::Vec4>(BASE_NS::Math::Vec4 value)
222 {
223 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
224 json.array_.reserve(4); // 4 :size
225 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
226 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
227 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
228 json.array_.emplace_back(CORE_NS::json::standalone_value(value.w));
229 return json;
230 }
231 template<>
232 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::UVec4>(BASE_NS::Math::UVec4 value)
233 {
234 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
235 json.array_.reserve(4); // 4 : size
236 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
237 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
238 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
239 json.array_.emplace_back(CORE_NS::json::standalone_value(value.w));
240 return json;
241 }
242
243 template<>
244 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::Quat>(BASE_NS::Math::Quat value)
245 {
246 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
247 json.array_.reserve(4); // 4 : size
248 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
249 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
250 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
251 json.array_.emplace_back(CORE_NS::json::standalone_value(value.w));
252 return json;
253 }
254
255 template<>
256 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Uid>(BASE_NS::Uid value)
257 {
258 return ToJson(BASE_NS::string_view{ to_string(value) });
259 }
260
261 UTIL_END_NAMESPACE()
262 #endif // API_UTIL_JSONUTIL_H
263