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