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_RUNTIME_JSONUTIL_H
17 #define API_RUNTIME_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/quaternion.h>
25 #include <base/math/vector.h>
26 #include <base/util/uid_util.h>
27 #include <core/json/json.h>
28
CORE_BEGIN_NAMESPACE()29 CORE_BEGIN_NAMESPACE()
30
31 inline BASE_NS::string JsonUnescape(BASE_NS::string_view str)
32 {
33 return CORE_NS::json::unescape(str);
34 }
35
36 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)37 inline bool SafeGetJsonValue(
38 const CORE_NS::json::value& jsonData, const BASE_NS::string_view element, BASE_NS::string& error, T& output)
39 {
40 if (auto const pos = jsonData.find(element); pos) {
41 if (pos->is_number()) {
42 output = pos->as_number<T>();
43 return true;
44 } else if (pos->is_boolean()) {
45 output = pos->boolean_;
46 return true;
47 } else {
48 error += element + ": expected number.\n";
49 }
50 }
51 return false;
52 }
53
54 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)55 inline bool SafeGetJsonValue(
56 const CORE_NS::json::value& jsonData, const BASE_NS::string_view element, BASE_NS::string& error, T& output)
57 {
58 if (auto const pos = jsonData.find(element); pos) {
59 if (pos->is_string()) {
60 output = JsonUnescape(T(pos->string_.data(), pos->string_.size()));
61 return true;
62 } else {
63 error += element + ": expected string.\n";
64 }
65 }
66 return false;
67 }
68
69 template<class T, std::enable_if_t<std::is_arithmetic_v<T>, bool> = true>
FromJson(const CORE_NS::json::value & jsonIn,T & output)70 inline bool FromJson(const CORE_NS::json::value& jsonIn, T& output)
71 {
72 if (jsonIn.is_number()) {
73 output = jsonIn.as_number<T>();
74 return true;
75 }
76 return false;
77 }
78
79 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)80 inline bool FromJson(const CORE_NS::json::value& jsonIn, T& output)
81 {
82 if (jsonIn.is_string()) {
83 output = JsonUnescape(static_cast<T>(jsonIn.string_));
84 return true;
85 }
86 return false;
87 }
88
FromJson(const CORE_NS::json::value & jsonIn,bool & output)89 inline bool FromJson(const CORE_NS::json::value& jsonIn, bool& output)
90 {
91 if (jsonIn.is_boolean()) {
92 output = jsonIn.boolean_;
93 return true;
94 }
95 return false;
96 }
97
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Uid & output)98 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Uid& output)
99 {
100 constexpr size_t UID_LENGTH = 36;
101 if (jsonIn.is_string() && jsonIn.string_.size() == UID_LENGTH) {
102 output = StringToUid(JsonUnescape(jsonIn.string_));
103 return true;
104 }
105 return false;
106 }
107
108 template<class T>
FromJsonArray(const CORE_NS::json::value & jsonIn,T * output,size_t size)109 inline bool FromJsonArray(const CORE_NS::json::value& jsonIn, T* output, size_t size)
110 {
111 if (jsonIn.is_array() && jsonIn.array_.size() == size) {
112 for (const auto& element : jsonIn.array_) {
113 if (!FromJson(element, *output)) {
114 return false;
115 }
116 output++;
117 }
118 return true;
119 }
120 return false;
121 }
122
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::Vec2 & output)123 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::Vec2& output)
124 {
125 return FromJsonArray(jsonIn, output.data, 2);
126 }
127
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::Vec3 & output)128 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::Vec3& output)
129 {
130 return FromJsonArray(jsonIn, output.data, 3);
131 }
132
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::Vec4 & output)133 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::Vec4& output)
134 {
135 return FromJsonArray(jsonIn, output.data, 4);
136 }
137
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::UVec2 & output)138 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::UVec2& output)
139 {
140 return FromJsonArray(jsonIn, output.data, 2);
141 }
142
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::UVec3 & output)143 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::UVec3& output)
144 {
145 return FromJsonArray(jsonIn, output.data, 3);
146 }
147
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::UVec4 & output)148 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::UVec4& output)
149 {
150 return FromJsonArray(jsonIn, output.data, 4);
151 }
152
FromJson(const CORE_NS::json::value & jsonIn,BASE_NS::Math::Quat & output)153 inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::Quat& output)
154 {
155 return FromJsonArray(jsonIn, output.data, 4);
156 }
157
158 template<class T>
ToJson(T value)159 inline CORE_NS::json::standalone_value ToJson(T value)
160 {
161 return CORE_NS::json::standalone_value(value);
162 }
163
164 // FIXME: how to make more generic?, Does not understand fixed_string
165 template<>
ToJson(BASE_NS::string_view value)166 inline CORE_NS::json::standalone_value ToJson(BASE_NS::string_view value)
167 {
168 return CORE_NS::json::standalone_value(BASE_NS::string { value });
169 }
170
171 template<>
ToJson(BASE_NS::string value)172 inline CORE_NS::json::standalone_value ToJson(BASE_NS::string value)
173 {
174 return CORE_NS::json::standalone_value(value);
175 }
176
177 template<>
178 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::Vec2>(BASE_NS::Math::Vec2 value)
179 {
180 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
181 json.array_.reserve(2);
182 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
183 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
184 return json;
185 }
186 template<>
187 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::UVec2>(BASE_NS::Math::UVec2 value)
188 {
189 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
190 json.array_.reserve(2);
191 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
192 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
193 return json;
194 }
195
196 template<>
197 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::Vec3>(BASE_NS::Math::Vec3 value)
198 {
199 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
200 json.array_.reserve(3);
201 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
202 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
203 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
204 return json;
205 }
206 template<>
207 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::UVec3>(BASE_NS::Math::UVec3 value)
208 {
209 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
210 json.array_.reserve(3);
211 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
212 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
213 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
214 return json;
215 }
216
217 template<>
218 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::Vec4>(BASE_NS::Math::Vec4 value)
219 {
220 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
221 json.array_.reserve(4);
222 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
223 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
224 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
225 json.array_.emplace_back(CORE_NS::json::standalone_value(value.w));
226 return json;
227 }
228 template<>
229 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::UVec4>(BASE_NS::Math::UVec4 value)
230 {
231 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
232 json.array_.reserve(4);
233 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
234 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
235 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
236 json.array_.emplace_back(CORE_NS::json::standalone_value(value.w));
237 return json;
238 }
239
240 template<>
241 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Math::Quat>(BASE_NS::Math::Quat value)
242 {
243 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
244 json.array_.reserve(4);
245 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
246 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
247 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
248 json.array_.emplace_back(CORE_NS::json::standalone_value(value.w));
249 return json;
250 }
251
252 template<>
253 inline CORE_NS::json::standalone_value ToJson<BASE_NS::Uid>(BASE_NS::Uid value)
254 {
255 return ToJson(BASE_NS::string_view { to_string(value) });
256 }
257
258 CORE_END_NAMESPACE()
259 #endif // SCENE_PLUGIN_JSONUTIL_H
260