• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_NODE_H
17  #define JSON_NODE_H
18  
19  #include <filesystem>
20  #include <list>
21  #include <memory>
22  #include <optional>
23  #include <string>
24  #include <type_traits>
25  #include <unordered_map>
26  #include <variant>
27  #include <vector>
28  
29  #include "cJSON.h"
30  #include "log/log.h"
31  #include "macros.h"
32  #include "traits_util.h"
33  
34  namespace Updater {
35  class JsonNode;
36  
37  enum class NodeType { OBJECT, INT, STRING, ARRAY, BOOL, NUL, UNKNOWN };
38  
39  using NodeMap = std::unordered_map<std::string, std::unique_ptr<JsonNode>>;
40  using NodeVec = std::vector<std::unique_ptr<JsonNode>>;
41  using cJSONPtr = std::unique_ptr<cJSON, decltype(&cJSON_Delete)>;
42  template<typename...T>
43  using optionalVariant = std::variant<std::optional<T> ...>;
44  
45  namespace Fs = std::filesystem;
46  class JsonNode {
47      DISALLOW_COPY_MOVE(JsonNode);
48  public:
49      JsonNode();
50      explicit JsonNode(const Fs::path &path);
51      explicit JsonNode(const std::string &str, bool needDelete = true);
52      explicit JsonNode(const cJSON *root, bool needDelete = true);
53      ~JsonNode();
54  
55      const JsonNode &operator[](int idx) const;
56      const JsonNode &operator[](const std::string &key) const;
57      JsonNode &operator[](int idx);
58      JsonNode &operator[](const std::string &key);
59  
60      template<typename T>
As()61      std::optional<T> As() const
62      {
63          if (auto optPtr = std::get_if<std::optional<Detail::StandardType<T>>>(&innerObj_); optPtr) {
64              return *optPtr;
65          }
66          return std::nullopt;
67      }
68  
69      template<typename T>
70      bool operator==(T rhs) const
71      {
72          if (auto optPtr = std::get_if<std::optional<Detail::StandardType<T>>>(&innerObj_); optPtr) {
73              return *optPtr == rhs;
74          }
75          return false;
76      }
77  
Size()78      int Size() const
79      {
80          return size_;
81      }
Type()82      NodeType Type() const
83      {
84          return type_;
85      }
Key()86      std::optional<std::string> Key() const
87      {
88          return key_;
89      }
90      std::list<std::reference_wrapper<JsonNode>>::const_iterator begin() const;
91      std::list<std::reference_wrapper<JsonNode>>::const_iterator end() const;
92      template<typename T>
93      void operator=(T &&rhs)
94      {
95          static_assert(Detail::G_IS_BASE_TYPE<Detail::RemoveCvRef<T>>, "only allow change int, string, bool value");
96          if (innerObj_.valueless_by_exception()) {
97              innerObj_ = Detail::OptStandardType<T>(rhs);
98          }
99          if (auto optPtr = std::get_if<Detail::OptStandardType<T>>(&innerObj_); optPtr) {
100              *optPtr = Detail::OptStandardType<T>(rhs);
101          } else {
102              LOG(ERROR) << "assign json node failed, key is " << key_.value_or("null") << ", type is "
103                  << static_cast<int>(type_) << ", rhs is " << rhs;
104          }
105      }
106  private:
107      void Parse(const cJSON *root);
108      void Init(const cJSON *root, bool needDelete);
109      int size_ {1};
110      NodeType type_ {NodeType::UNKNOWN};         /* json node type */
111      std::optional<std::string> key_ {std::nullopt}; /* key for object items */
112      optionalVariant<bool, int, std::string, NodeVec, NodeMap> innerObj_ {};
113      std::list<std::reference_wrapper<JsonNode>> innerNodesList_ {};
114  };
115  
GetInvalidNode()116  inline JsonNode &GetInvalidNode()
117  {
118      static JsonNode emptyNode;  // used for invalid json node
119      return emptyNode;
120  }
121  
122  template<typename T>
GetNodeByIdx(T & innerObj,int size,int idx)123  inline JsonNode &GetNodeByIdx(T &innerObj, int size, int idx)
124  {
125      auto optVec = std::get_if<std::optional<NodeVec>>(&innerObj);
126      if (optVec == nullptr || *optVec == std::nullopt) {
127          return GetInvalidNode(); // type not matched
128      }
129      auto &nodeVec = **optVec;
130      if (idx < 0 || idx >= size) {
131          return GetInvalidNode();
132      }
133      return *nodeVec[idx];
134  }
135  
136  template<typename T>
GetNodeByKey(T & innerObj,const std::string & key)137  inline JsonNode &GetNodeByKey(T &innerObj, const std::string &key)
138  {
139      auto optMap = std::get_if<std::optional<NodeMap>>(&innerObj);
140      if (optMap == nullptr || *optMap == std::nullopt) {
141          return GetInvalidNode(); // type not matched
142      }
143      auto &nodeMap = **optMap;
144      if (auto it = nodeMap.find(key); it != nodeMap.end()) {
145          return *(it->second);
146      }
147      return GetInvalidNode();
148  }
149  }
150  #endif // NODE_H
151