/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef JSON_VISITOR_H #define JSON_VISITOR_H #include #include "json_node.h" #include "log/log.h" namespace Updater { template struct Traits; enum Action { SETVAL, PRINTVAL }; namespace Detail { template constexpr bool CheckTrait() { bool res = true; for (int i = 0; i < Traits::COUNT; ++i) { res = res && Traits::MEMBER_KEY[i] != nullptr && std::string_view("") != Traits::MEMBER_KEY[i]; } return res; }; template struct MemberVisitor; template using memberType = std::remove_reference_t::template Get(std::declval()))>; template struct StructVisitor { template static bool VisitStruct(const JsonNode &node, const JsonNode &defaultNode, T &t, std::index_sequence) { static_assert(CheckTrait>(), "Trait member key invalid, please check"); constexpr auto key = Traits::MEMBER_KEY[F]; auto &FthMember = Traits::template Get(t); if (!MemberVisitor::template VisitMember>( node[key], defaultNode[key], FthMember, key)) { return false; } if constexpr (sizeof...(R) == 0) { return true; } else { // don't remove else, otherwise can't compile return VisitStruct(node, defaultNode, t, std::index_sequence {}); } } }; template<> struct MemberVisitor { // visit string, int, bool template, bool> = true> static bool VisitMember(const JsonNode &node, const JsonNode &defaultNode, T &obj, const char *key) { auto r = node.As(); auto defaultR = defaultNode.As(); if (!r.has_value() && !defaultR.has_value()) { LOG(ERROR) << key << " has not both default and non-default value!!!"; return false; } if (r) { obj = *r; return true; } if (defaultR) { obj = *defaultR; return true; } return false; } // visit vector, T is std::vector template, bool> = true> static auto VisitMember(const JsonNode &node, const JsonNode &defaultNode, T &obj, const char *key) { if ((node.Type() != NodeType::UNKNOWN && node.Type() != NodeType::NUL && node.Type() != NodeType::ARRAY) || (defaultNode.Type() != NodeType::UNKNOWN && defaultNode.Type() != NodeType::NUL && defaultNode.Type() != NodeType::ARRAY)) { LOG(ERROR) << "Node type not matched with " << key; return false; } typename T::value_type ele {}; for (auto &subNode : node) { ele = {}; if (!VisitMember(subNode, {}, ele, "")) { return false; } obj.push_back(std::move(ele)); } for (auto &subNode : defaultNode) { ele = {}; // using subNode to contruct an element of i-th type of T if (!VisitMember(subNode, {}, ele, "")) { return false; } obj.push_back(std::move(ele)); } return true; } // visit struct template::COUNT)>, bool> = true> static bool VisitMember(const JsonNode &node, const JsonNode &defaultNode, T &obj, const char *key) { return StructVisitor::VisitStruct(node, defaultNode, obj, std::make_index_sequence::COUNT> {}); } }; } // namespace Detail template, bool> = true> bool Visit(const JsonNode &node, T &obj) { static_assert(act == SETVAL, "only for setting stl vector without default node"); return Detail::MemberVisitor::VisitMember(node, {}, obj, ""); } template::COUNT)>, bool> = true> bool Visit(const JsonNode &node, const JsonNode &defaultNode, T &obj) { static_assert(act == SETVAL, "Only for setting member of struct with default node!"); return Detail::StructVisitor::VisitStruct(node, defaultNode, obj, std::make_index_sequence::COUNT> {}); } template::COUNT)>, bool> = true> bool Visit(const JsonNode &node, T &obj) { static_assert(act == SETVAL, "Only for setting member of struct without default node!"); return Detail::StructVisitor::VisitStruct(node, {}, obj, std::make_index_sequence::COUNT> {}); } } // namespace Updater #endif