1/* 2 * Copyright (c) 2022 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 JSON_VISITOR_H 17#define JSON_VISITOR_H 18 19#include <type_traits> 20 21#include "json_node.h" 22#include "log/log.h" 23 24namespace Updater { 25template<typename T> struct Traits; 26enum Action { SETVAL, PRINTVAL }; 27namespace Detail { 28template<typename Traits> 29constexpr bool CheckTrait() 30{ 31 bool res = true; 32 for (int i = 0; i < Traits::COUNT; ++i) { 33 res = res && Traits::MEMBER_KEY[i] != nullptr && std::string_view("") != Traits::MEMBER_KEY[i]; 34 } 35 return res; 36}; 37 38template<Action action> 39struct MemberVisitor; 40 41template<typename T, std::size_t idx> 42using memberType = std::remove_reference_t<decltype(Traits<T>::template Get<idx>(std::declval<T&>()))>; 43 44template<Action action> 45struct StructVisitor { 46 template<typename T, std::size_t F, std::size_t... R> 47 static bool VisitStruct(const JsonNode &node, const JsonNode &defaultNode, T &t, std::index_sequence<F, R...>) 48 { 49 static_assert(CheckTrait<Traits<T>>(), "Trait member key invalid, please check"); 50 constexpr auto key = Traits<T>::MEMBER_KEY[F]; 51 auto &FthMember = Traits<T>::template Get<F>(t); 52 if (!MemberVisitor<action>::template VisitMember<memberType<T, F>>( 53 node[key], defaultNode[key], FthMember, key)) { 54 return false; 55 } 56 57 if constexpr (sizeof...(R) == 0) { 58 return true; 59 } else { // don't remove else, otherwise can't compile 60 return VisitStruct(node, defaultNode, t, std::index_sequence<R...> {}); 61 } 62 } 63}; 64 65template<> 66struct MemberVisitor<SETVAL> { 67 // visit string, int, bool 68 template<typename T, std::enable_if_t<Detail::G_IS_BASE_TYPE<T>, bool> = true> 69 static bool VisitMember(const JsonNode &node, const JsonNode &defaultNode, T &obj, const char *key) 70 { 71 auto r = node.As<T>(); 72 auto defaultR = defaultNode.As<T>(); 73 if (!r.has_value() && !defaultR.has_value()) { 74 LOG(ERROR) << key << " has not both default and non-default value!!!"; 75 return false; 76 } 77 if (r) { 78 obj = *r; 79 return true; 80 } 81 if (defaultR) { 82 obj = *defaultR; 83 return true; 84 } 85 return false; 86 } 87 // visit vector, T is std::vector<T::value_type> 88 template<typename T, std::enable_if_t<Detail::G_IS_VECTOR<T>, bool> = true> 89 static auto VisitMember(const JsonNode &node, const JsonNode &defaultNode, T &obj, const char *key) 90 { 91 if ((node.Type() != NodeType::UNKNOWN && node.Type() != NodeType::NUL && node.Type() != NodeType::ARRAY) || 92 (defaultNode.Type() != NodeType::UNKNOWN && defaultNode.Type() != NodeType::NUL && 93 defaultNode.Type() != NodeType::ARRAY)) { 94 LOG(ERROR) << "Node type not matched with " << key; 95 return false; 96 } 97 typename T::value_type ele {}; 98 for (auto &subNode : node) { 99 ele = {}; 100 if (!VisitMember(subNode, {}, ele, "")) { 101 return false; 102 } 103 obj.push_back(std::move(ele)); 104 } 105 for (auto &subNode : defaultNode) { 106 ele = {}; 107 // using subNode to contruct an element of i-th type of T 108 if (!VisitMember(subNode, {}, ele, "")) { 109 return false; 110 } 111 obj.push_back(std::move(ele)); 112 } 113 return true; 114 } 115 // visit struct 116 template<typename T, std::enable_if_t<std::is_integral_v<decltype(Traits<T>::COUNT)>, bool> = true> 117 static bool VisitMember(const JsonNode &node, const JsonNode &defaultNode, T &obj, const char *key) 118 { 119 return StructVisitor<SETVAL>::VisitStruct(node, defaultNode, obj, 120 std::make_index_sequence<Traits<T>::COUNT> {}); 121 } 122}; 123} // namespace Detail 124 125template<Action act, typename T, std::enable_if_t<Detail::G_IS_VECTOR<T>, bool> = true> 126bool Visit(const JsonNode &node, T &obj) 127{ 128 static_assert(act == SETVAL, "only for setting stl vector without default node"); 129 return Detail::MemberVisitor<act>::VisitMember(node, {}, obj, ""); 130} 131 132template<Action act, typename T, std::enable_if_t<Detail::G_IS_NUM<decltype(Traits<T>::COUNT)>, bool> = true> 133bool Visit(const JsonNode &node, const JsonNode &defaultNode, T &obj) 134{ 135 static_assert(act == SETVAL, 136 "Only for setting member of struct with default node!"); 137 return Detail::StructVisitor<act>::VisitStruct(node, defaultNode, obj, 138 std::make_index_sequence<Traits<T>::COUNT> {}); 139} 140 141template<Action act, typename T, std::enable_if_t<Detail::G_IS_NUM<decltype(Traits<T>::COUNT)>, bool> = true> 142bool Visit(const JsonNode &node, T &obj) 143{ 144 static_assert(act == SETVAL, 145 "Only for setting member of struct without default node!"); 146 return Detail::StructVisitor<act>::VisitStruct(node, {}, obj, 147 std::make_index_sequence<Traits<T>::COUNT> {}); 148} 149} // namespace Updater 150 151#endif 152