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