Clio develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
ConfigValue.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2024, the clio developers.
5
6 Permission to use, copy, modify, and distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#pragma once
21
22#include "util/Assert.hpp"
23#include "util/OverloadSet.hpp"
24#include "util/config/ConfigConstraints.hpp"
25#include "util/config/Error.hpp"
26#include "util/config/Types.hpp"
27
28#include <fmt/format.h>
29
30#include <cstddef>
31#include <cstdint>
32#include <functional>
33#include <optional>
34#include <ostream>
35#include <string>
36#include <string_view>
37#include <variant>
38
39namespace util::config {
40
48public:
54 constexpr ConfigValue(ConfigType type) : type_(type)
55 {
56 }
57
65 [[nodiscard]] ConfigValue&
66 defaultValue(Value value, std::optional<std::string_view> description = std::nullopt)
67 {
68 auto const err = checkTypeConsistency(type_, value);
69 if (err.has_value())
70 ASSERT(false, "{}", err->error);
71 description_ = description;
72 value_ = value;
73 return *this;
74 }
75
83 [[nodiscard]] std::optional<Error>
84 setValue(Value value, std::optional<std::string_view> key = std::nullopt)
85 {
86 auto err = checkTypeConsistency(type_, value);
87 if (err.has_value()) {
88 err->error = fmt::format("{} {}", key.value_or("Unknown_key"), err->error);
89 return err;
90 }
91
92 if (cons_.has_value()) {
93 auto constraintCheck = cons_->get().checkConstraint(value);
94 if (constraintCheck.has_value()) {
95 constraintCheck->error = fmt::format("{} {}", key.value_or("Unknown_key"), constraintCheck->error);
96 return constraintCheck;
97 }
98 }
99 value_ = value;
100 return std::nullopt;
101 }
102
114 [[nodiscard]] constexpr ConfigValue&
116 {
117 cons_ = std::reference_wrapper<Constraint const>(cons);
118 ASSERT(cons_.has_value(), "Constraint must be defined");
119
120 if (value_.has_value()) {
121 auto const& temp = cons_.value().get();
122 auto const& result = temp.checkConstraint(value_.value());
123 if (result.has_value()) {
124 // useful for specifying clear Error message
125 std::string type;
126 std::visit(
128 [&type](bool tmp) { type = fmt::format("bool {}", tmp); },
129 [&type](std::string const& tmp) { type = fmt::format("string {}", tmp); },
130 [&type](double tmp) { type = fmt::format("double {}", tmp); },
131 [&type](int64_t tmp) { type = fmt::format("int {}", tmp); },
132 },
133 value_.value()
134 );
135 ASSERT(false, "Value {} ConfigValue does not satisfy the set Constraint", type);
136 }
137 }
138 return *this;
139 }
140
146 [[nodiscard]] constexpr std::optional<std::reference_wrapper<Constraint const>>
148 {
149 return cons_;
150 }
151
157 [[nodiscard]] constexpr ConfigType
158 type() const
159 {
160 return type_;
161 }
162
168 [[nodiscard]] constexpr ConfigValue&
170 {
171 optional_ = true;
172 return *this;
173 }
174
180 [[nodiscard]] bool constexpr isOptional() const
181 {
182 return optional_;
183 }
184
190 [[nodiscard]] bool constexpr hasValue() const
191 {
192 return value_.has_value();
193 }
194
200 [[nodiscard]] Value const&
201 getValue() const
202 {
203 ASSERT(value_.has_value(), "getValue() is called when there is no value set");
204 return value_.value();
205 }
206
214 friend std::ostream&
215 operator<<(std::ostream& stream, ConfigValue val)
216 {
217 stream << "- **Required**: " << (val.isOptional() ? "False" : "True") << "\n";
218 stream << "- **Type**: " << val.type() << "\n";
219 if (val.description_.has_value()) {
220 stream << "- **Default value**: " << *val.description_ << "\n";
221 } else if (val.hasValue()) {
222 stream << "- **Default value**: `" << *val.value_ << "`\n";
223 } else {
224 stream << "- **Default value**: None\n";
225 }
226 stream << "- **Constraints**: ";
227
228 if (val.getConstraint().has_value()) {
229 stream << val.getConstraint()->get() << "\n";
230 } else {
231 stream << "None" << "\n";
232 }
233 return stream;
234 }
235
236private:
243 static std::optional<Error>
244 checkTypeConsistency(ConfigType type, Value value)
245 {
246 if (type == ConfigType::String && !std::holds_alternative<std::string>(value)) {
247 return Error{"value does not match type string"};
248 }
249 if (type == ConfigType::Boolean && !std::holds_alternative<bool>(value)) {
250 return Error{"value does not match type boolean"};
251 }
252 if (type == ConfigType::Double && (!std::holds_alternative<double>(value))) {
253 if (std::holds_alternative<int64_t>(value))
254 return std::nullopt;
255 return Error{"value does not match type double"};
256 }
257 if (type == ConfigType::Integer && !std::holds_alternative<int64_t>(value)) {
258 return Error{"value does not match type integer"};
259 }
260 return std::nullopt;
261 }
262
263 ConfigType type_{};
264 bool optional_{false};
265 std::optional<Value> value_;
266 std::optional<std::reference_wrapper<Constraint const>> cons_;
267 std::optional<std::string_view> description_;
268};
269
270} // namespace util::config
Represents the config values for Json/Yaml config.
Definition ConfigValue.hpp:47
ConfigValue & defaultValue(Value value, std::optional< std::string_view > description=std::nullopt)
Sets the default value for the config.
Definition ConfigValue.hpp:66
friend std::ostream & operator<<(std::ostream &stream, ConfigValue val)
Prints all the info of this config value to the output stream.
Definition ConfigValue.hpp:215
constexpr ConfigType type() const
Gets the config type.
Definition ConfigValue.hpp:158
constexpr std::optional< std::reference_wrapper< Constraint const > > getConstraint() const
Retrieves the constraint associated with this ConfigValue, if any.
Definition ConfigValue.hpp:147
constexpr ConfigValue & optional()
Sets the config value as optional, meaning the user doesn't have to provide the value in their config...
Definition ConfigValue.hpp:169
constexpr ConfigValue(ConfigType type)
Constructor initializing with the config type.
Definition ConfigValue.hpp:54
std::optional< Error > setValue(Value value, std::optional< std::string_view > key=std::nullopt)
Sets the value current ConfigValue given by the User's defined value.
Definition ConfigValue.hpp:84
bool constexpr isOptional() const
Checks if configValue is optional.
Definition ConfigValue.hpp:180
Value const & getValue() const
Get the value of config.
Definition ConfigValue.hpp:201
bool constexpr hasValue() const
Check if value is optional.
Definition ConfigValue.hpp:190
constexpr ConfigValue & withConstraint(Constraint const &cons)
Assigns a constraint to the ConfigValue.
Definition ConfigValue.hpp:115
An interface to enforce constraints on certain values within ClioConfigDefinition.
Definition ConfigConstraints.hpp:90
Overload set for lambdas.
Definition OverloadSet.hpp:30
Displays the different errors when parsing user config.
Definition Error.hpp:31