$darkmode
conf.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Robert Bosch GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * SPDX-License-Identifier: Apache-2.0
17  */
51 #pragma once
52 #ifndef FABLE_CONF_HPP_
53 #define FABLE_CONF_HPP_
54 
55 #include <functional> // for function<>
56 #include <string> // for string
57 #include <vector> // for vector<>
58 
59 #include <fmt/format.h> // for fmt::format
60 
61 #include <fable/json.hpp> // for Json
62 
63 // Forward declaration:
64 namespace boost {
65 namespace filesystem {
66 class path;
67 } // namespace filesystem
68 } // namespace boost
69 
70 namespace fable {
71 
72 class ConfError;
73 
74 class Conf {
75  public:
76  Conf() = default;
77  explicit Conf(const Json& data) : data_(data) {}
78  explicit Conf(const std::string& file);
79  Conf(const Json& data, const std::string& file) : file_(file), data_(data) {}
80  Conf(const Json& data, const std::string& file, const std::string& root)
81  : file_(file), root_(root), data_(data) {}
82 
92  bool is_from_file() const { return !file_.empty(); }
93 
97  const std::string& file() const { return file_; }
98 
102  bool is_empty() const { return data_.is_null(); }
103 
109  const Json& operator*() const { return data_; }
110  Json& operator*() { return data_; }
111 
117  const Json* operator->() const { return &data_; }
118  Json* operator->() { return &data_; }
119 
123  std::string root() const { return (root_.empty() ? "/" : root_); }
124 
130  bool has(const std::string& key) const { return data_.count(key) != 0; }
131  bool has(const JsonPointer& key) const;
132  bool has_pointer(const std::string& key) const { return has(JsonPointer(key)); }
133 
139  Conf at(const std::string& key) const;
140  Conf at(const JsonPointer& key) const;
141  Conf at_pointer(const std::string& key) const { return at(JsonPointer(key)); }
142 
147  size_t erase(const std::string& key);
148  size_t erase(const JsonPointer& key);
149  size_t erase_pointer(const std::string& key) { return erase(JsonPointer(key)); }
150 
156  std::vector<Conf> to_array() const;
157 
163  template <typename T>
164  T get() const {
165  try {
166  return data_.get<T>();
167  } catch (nlohmann::detail::type_error&) {
168  throw_wrong_type();
169  }
170  }
171 
177  template <typename T>
178  T get(const std::string& key) const {
179  try {
180  return data_.at(key).get<T>();
181  } catch (nlohmann::detail::out_of_range&) {
182  throw_missing(key);
183  } catch (nlohmann::detail::type_error&) {
184  throw_wrong_type(key);
185  }
186  }
187 
188  template <typename T>
189  T get(const JsonPointer& key) const {
190  try {
191  return data_.at(key).get<T>();
192  } catch (nlohmann::detail::out_of_range&) {
193  throw_missing(key);
194  } catch (nlohmann::detail::type_error&) {
195  throw_wrong_type(key);
196  }
197  }
198 
199  template <typename T>
200  T get_pointer(const std::string& key) const {
201  return get<T>(JsonPointer(key));
202  }
203 
208  template <typename T>
209  T get_or(const std::string& key, T def) const {
210  if (!data_.count(key)) {
211  return def;
212  }
213  try {
214  return data_.at(key).get<T>();
215  } catch (nlohmann::detail::type_error&) {
216  throw_wrong_type(key);
217  }
218  }
219 
220  template <typename T>
221  T get_or(const JsonPointer& key, T def) const {
222  try {
223  return data_.at(key).get<T>();
224  } catch (nlohmann::detail::out_of_range&) {
225  return def;
226  } catch (nlohmann::detail::type_error&) {
227  throw_wrong_type(key);
228  }
229  }
230 
231  template <typename T>
232  T get_pointer_or(const std::string& key, T def) const {
233  return get_or(key, def);
234  }
235 
242  template <typename T>
243  void with(const std::string& key, std::function<void(const T&)> fn) const {
244  if (data_.count(key)) {
245  fn(get<T>(key));
246  }
247  }
248 
249  template <typename T>
250  void with(const JsonPointer& key, std::function<void(const T&)> fn) const {
251  try {
252  fn(get<T>(key));
253  } catch (nlohmann::detail::out_of_range&) {
254  return;
255  }
256  }
257 
258  template <typename T>
259  void with_pointer(const std::string& key, std::function<void(const T&)> fn) const {
260  with(JsonPointer(key), fn);
261  }
262 
268  template <typename T>
269  void try_from(const std::string& key, T* val) const {
270  if (data_.count(key)) {
271  *val = get<T>(key);
272  }
273  }
274 
275  template <typename T>
276  void try_from(const JsonPointer& key, T* val) const {
277  try {
278  *val = data_.at(key).get<T>();
279  } catch (nlohmann::detail::out_of_range& e) {
280  return;
281  } catch (nlohmann::detail::type_error& e) {
282  throw_wrong_type(key);
283  }
284  }
285 
286  template <typename T>
287  void try_from_pointer(const std::string& key, T* val) const {
288  try_from(JsonPointer(key), val);
289  }
290 
294  void assert_has(const std::string& key) const;
295  void assert_has(const JsonPointer& key) const;
296  void assert_has_pointer(const std::string& key) const { assert_has(JsonPointer(key)); }
297 
302  void assert_has_type(const std::string& key, JsonType t) const;
303  void assert_has_type(const JsonPointer& key, JsonType t) const;
304  void assert_has_pointer_type(const std::string& key, JsonType t) const {
305  assert_has_type(JsonPointer(key), t);
306  }
307 
312  void assert_has_not(const std::string& key, const std::string& msg = "") const;
313  void assert_has_not(const JsonPointer& key, const std::string& msg = "") const;
314  void assert_has_pointer_not(const std::string& key, const std::string& msg = "") const {
315  assert_has_not(JsonPointer(key), msg);
316  }
317 
328  boost::filesystem::path resolve_file(const boost::filesystem::path& filename) const;
329  std::string resolve_file(const std::string& filename) const;
330 
331  template <typename... Args>
332  [[noreturn]] void throw_error(const char* msg, const Args&... args) const {
333  throw_error(fmt::format(msg, args...));
334  }
335  [[noreturn]] void throw_error(const std::string& msg) const;
336  [[noreturn]] void throw_unexpected(const std::string& key, const std::string& msg = "") const;
337  [[noreturn]] void throw_missing(const std::string& key) const;
338  [[noreturn]] void throw_wrong_type(const std::string& key = "") const;
339  [[noreturn]] void throw_wrong_type(const std::string& key, JsonType type) const;
340 
341  friend void to_json(Json& j, const Conf& c) { j = *c; }
342  friend void from_json(const Json& j, Conf& c) { *c = j; }
343 
344  private:
345  std::string file_;
346  std::string root_;
347  Json data_;
348 };
349 
350 } // namespace fable
351 
352 #endif // FABLE_CONF_HPP_
Definition: conf.hpp:74
std::string root() const
Definition: conf.hpp:123
Definition: conf.hpp:64
const Json * operator->() const
Definition: conf.hpp:117
bool is_empty() const
Definition: conf.hpp:102
nlohmann::json Json
Definition: json.hpp:62
bool has(const std::string &key) const
Definition: conf.hpp:130
Json::value_t JsonType
Definition: json.hpp:78
Definition: conf.hpp:70
const std::string & file() const
Definition: conf.hpp:97
void try_from(const std::string &key, T *val) const
Definition: conf.hpp:269
Json::json_pointer JsonPointer
Definition: json.hpp:70
const Json & operator*() const
Definition: conf.hpp:109
T get_or(const std::string &key, T def) const
Definition: conf.hpp:209
void with(const std::string &key, std::function< void(const T &)> fn) const
Definition: conf.hpp:243
bool is_from_file() const
Definition: conf.hpp:92