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 29CORE_BEGIN_NAMESPACE() 30 31inline BASE_NS::string JsonUnescape(BASE_NS::string_view str) 32{ 33 return CORE_NS::json::unescape(str); 34} 35 36template<class T, std::enable_if_t<std::is_arithmetic_v<T>, bool> = true> 37inline 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 54template<class T, std::enable_if_t<std::is_convertible_v<T, BASE_NS::string_view>, bool> = true> 55inline 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 69template<class T, std::enable_if_t<std::is_arithmetic_v<T>, bool> = true> 70inline 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 79template<class T, std::enable_if_t<std::is_convertible_v<T, BASE_NS::string_view>, bool> = true> 80inline 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 89inline 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 98inline 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 108template<class T> 109inline 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 123inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::Vec2& output) 124{ 125 return FromJsonArray(jsonIn, output.data, 2); 126} 127 128inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::Vec3& output) 129{ 130 return FromJsonArray(jsonIn, output.data, 3); 131} 132 133inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::Vec4& output) 134{ 135 return FromJsonArray(jsonIn, output.data, 4); 136} 137 138inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::UVec2& output) 139{ 140 return FromJsonArray(jsonIn, output.data, 2); 141} 142 143inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::UVec3& output) 144{ 145 return FromJsonArray(jsonIn, output.data, 3); 146} 147 148inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::UVec4& output) 149{ 150 return FromJsonArray(jsonIn, output.data, 4); 151} 152 153inline bool FromJson(const CORE_NS::json::value& jsonIn, BASE_NS::Math::Quat& output) 154{ 155 return FromJsonArray(jsonIn, output.data, 4); 156} 157 158template<class T> 159inline 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 165template<> 166inline 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 171template<> 172inline CORE_NS::json::standalone_value ToJson(BASE_NS::string value) 173{ 174 return CORE_NS::json::standalone_value(value); 175} 176 177template<> 178inline 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} 186template<> 187inline 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 196template<> 197inline 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} 206template<> 207inline 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 217template<> 218inline 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} 228template<> 229inline 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 240template<> 241inline 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 252template<> 253inline 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 258CORE_END_NAMESPACE() 259#endif // SCENE_PLUGIN_JSONUTIL_H 260