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
32 UTIL_BEGIN_NAMESPACE()
33
JsonUnescape(::string_view str)34 inline ::string JsonUnescape(::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 ::string_view element, ::string& error, T& output)40 inline bool SafeGetJsonValue(
41 const CORE_NS::json::value& jsonData, const ::string_view element, ::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, ::string_view>, bool> = true>
SafeGetJsonValue( const CORE_NS::json::value& jsonData, const ::string_view element, ::string& error, T& output)58 inline bool SafeGetJsonValue(
59 const CORE_NS::json::value& jsonData, const ::string_view element, ::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, ::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, ::Uid& output)101 inline bool FromJson(const CORE_NS::json::value& jsonIn, ::Uid& output)
102 {
103 constexpr size_t UID_LENGTH = 36;
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, ::Math::Vec2& output)126 inline bool FromJson(const CORE_NS::json::value& jsonIn, ::Math::Vec2& output)
127 {
128 return FromJsonArray(jsonIn, output.data, 2);
129 }
130
FromJson(const CORE_NS::json::value& jsonIn, ::Math::Vec3& output)131 inline bool FromJson(const CORE_NS::json::value& jsonIn, ::Math::Vec3& output)
132 {
133 return FromJsonArray(jsonIn, output.data, 3);
134 }
135
FromJson(const CORE_NS::json::value& jsonIn, ::Math::Vec4& output)136 inline bool FromJson(const CORE_NS::json::value& jsonIn, ::Math::Vec4& output)
137 {
138 return FromJsonArray(jsonIn, output.data, 4);
139 }
140
FromJson(const CORE_NS::json::value& jsonIn, ::Math::UVec2& output)141 inline bool FromJson(const CORE_NS::json::value& jsonIn, ::Math::UVec2& output)
142 {
143 return FromJsonArray(jsonIn, output.data, 2);
144 }
145
FromJson(const CORE_NS::json::value& jsonIn, ::Math::UVec3& output)146 inline bool FromJson(const CORE_NS::json::value& jsonIn, ::Math::UVec3& output)
147 {
148 return FromJsonArray(jsonIn, output.data, 3);
149 }
150
FromJson(const CORE_NS::json::value& jsonIn, ::Math::UVec4& output)151 inline bool FromJson(const CORE_NS::json::value& jsonIn, ::Math::UVec4& output)
152 {
153 return FromJsonArray(jsonIn, output.data, 4);
154 }
155
FromJson(const CORE_NS::json::value& jsonIn, ::Math::Quat& output)156 inline bool FromJson(const CORE_NS::json::value& jsonIn, ::Math::Quat& output)
157 {
158 return FromJsonArray(jsonIn, output.data, 4);
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 // FIXME: how to make more generic?, Does not understand fixed_string
168 template<>
ToJson(::string_view value)169 inline CORE_NS::json::standalone_value ToJson(::string_view value)
170 {
171 return CORE_NS::json::standalone_value(::string{ value });
172 }
173
174 template<>
ToJson(::string value)175 inline CORE_NS::json::standalone_value ToJson(::string value)
176 {
177 return CORE_NS::json::standalone_value(value);
178 }
179
180 template<>
ToJson(::Math::Vec2 value)181 inline CORE_NS::json::standalone_value ToJson<::Math::Vec2>(::Math::Vec2 value)
182 {
183 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
184 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
185 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
186 return json;
187 }
188 template<>
ToJson(::Math::UVec2 value)189 inline CORE_NS::json::standalone_value ToJson<::Math::UVec2>(::Math::UVec2 value)
190 {
191 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
192 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
193 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
194 return json;
195 }
196
197 template<>
ToJson(::Math::Vec3 value)198 inline CORE_NS::json::standalone_value ToJson<::Math::Vec3>(::Math::Vec3 value)
199 {
200 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
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<>
ToJson(::Math::UVec3 value)207 inline CORE_NS::json::standalone_value ToJson<::Math::UVec3>(::Math::UVec3 value)
208 {
209 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
210 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
211 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
212 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
213 return json;
214 }
215
216 template<>
ToJson(::Math::Vec4 value)217 inline CORE_NS::json::standalone_value ToJson<::Math::Vec4>(::Math::Vec4 value)
218 {
219 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
220 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
221 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
222 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
223 json.array_.emplace_back(CORE_NS::json::standalone_value(value.w));
224 return json;
225 }
226 template<>
ToJson(::Math::UVec4 value)227 inline CORE_NS::json::standalone_value ToJson<::Math::UVec4>(::Math::UVec4 value)
228 {
229 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
230 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
231 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
232 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
233 json.array_.emplace_back(CORE_NS::json::standalone_value(value.w));
234 return json;
235 }
236
237 template<>
ToJson(::Math::Quat value)238 inline CORE_NS::json::standalone_value ToJson<::Math::Quat>(::Math::Quat value)
239 {
240 CORE_NS::json::standalone_value json = CORE_NS::json::standalone_value::array();
241 json.array_.emplace_back(CORE_NS::json::standalone_value(value.x));
242 json.array_.emplace_back(CORE_NS::json::standalone_value(value.y));
243 json.array_.emplace_back(CORE_NS::json::standalone_value(value.z));
244 json.array_.emplace_back(CORE_NS::json::standalone_value(value.w));
245 return json;
246 }
247
248 template<>
ToJson(::Uid value)249 inline CORE_NS::json::standalone_value ToJson<::Uid>(::Uid value)
250 {
251 return ToJson(::string_view{ to_string(value) });
252 }
253
254 UTIL_END_NAMESPACE()
255 #endif // API_UTIL_JSONUTIL_H
256