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/newconfig/ConfigConstraints.hpp"
25#include "util/newconfig/Error.hpp"
26#include "util/newconfig/Types.hpp"
27
28#include <fmt/core.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 ASSERT(!err.has_value(), "{}", err->error);
70 description_ = description;
71 value_ = value;
72 return *this;
73 }
74
82 [[nodiscard]] std::optional<Error>
83 setValue(Value value, std::optional<std::string_view> key = std::nullopt)
84 {
85 auto err = checkTypeConsistency(type_, value);
86 if (err.has_value()) {
87 err->error = fmt::format("{} {}", key.value_or("Unknown_key"), err->error);
88 return err;
89 }
90
91 if (cons_.has_value()) {
92 auto constraintCheck = cons_->get().checkConstraint(value);
93 if (constraintCheck.has_value()) {
94 constraintCheck->error = fmt::format("{} {}", key.value_or("Unknown_key"), constraintCheck->error);
95 return constraintCheck;
96 }
97 }
98 value_ = value;
99 return std::nullopt;
100 }
101
113 [[nodiscard]] constexpr ConfigValue&
115 {
116 cons_ = std::reference_wrapper<Constraint const>(cons);
117 ASSERT(cons_.has_value(), "Constraint must be defined");
118
119 if (value_.has_value()) {
120 auto const& temp = cons_.value().get();
121 auto const& result = temp.checkConstraint(value_.value());
122 if (result.has_value()) {
123 // useful for specifying clear Error message
124 std::string type;
125 std::visit(
127 [&type](bool tmp) { type = fmt::format("bool {}", tmp); },
128 [&type](std::string const& tmp) { type = fmt::format("string {}", tmp); },
129 [&type](double tmp) { type = fmt::format("double {}", tmp); },
130 [&type](int64_t tmp) { type = fmt::format("int {}", tmp); },
131 },
132 value_.value()
133 );
134 ASSERT(false, "Value {} ConfigValue does not satisfy the set Constraint", type);
135 }
136 }
137 return *this;
138 }
139
145 [[nodiscard]] constexpr std::optional<std::reference_wrapper<Constraint const>>
147 {
148 return cons_;
149 }
150
156 [[nodiscard]] constexpr ConfigType
157 type() const
158 {
159 return type_;
160 }
161
167 [[nodiscard]] constexpr ConfigValue&
169 {
170 optional_ = true;
171 return *this;
172 }
173
179 [[nodiscard]] bool constexpr isOptional() const
180 {
181 return optional_;
182 }
183
189 [[nodiscard]] bool constexpr hasValue() const
190 {
191 return value_.has_value();
192 }
193
199 [[nodiscard]] Value const&
200 getValue() const
201 {
202 ASSERT(value_.has_value(), "getValue() is called when there is no value set");
203 return value_.value();
204 }
205
213 friend std::ostream&
214 operator<<(std::ostream& stream, ConfigValue val)
215 {
216 stream << "- **Required**: " << (val.isOptional() ? "False" : "True") << "\n";
217 stream << "- **Type**: " << val.type() << "\n";
218 if (val.description_.has_value()) {
219 stream << "- **Default value**: " << *val.description_ << "\n";
220 } else if (val.hasValue()) {
221 stream << "- **Default value**: `" << *val.value_ << "`\n";
222 } else {
223 stream << "- **Default value**: None\n";
224 }
225 stream << "- **Constraints**: ";
226
227 if (val.getConstraint().has_value()) {
228 stream << val.getConstraint()->get() << "\n";
229 } else {
230 stream << "None" << "\n";
231 }
232 return stream;
233 }
234
235private:
242 static std::optional<Error>
243 checkTypeConsistency(ConfigType type, Value value)
244 {
245 if (type == ConfigType::String && !std::holds_alternative<std::string>(value)) {
246 return Error{"value does not match type string"};
247 }
248 if (type == ConfigType::Boolean && !std::holds_alternative<bool>(value)) {
249 return Error{"value does not match type boolean"};
250 }
251 if (type == ConfigType::Double && (!std::holds_alternative<double>(value))) {
252 if (std::holds_alternative<int64_t>(value))
253 return std::nullopt;
254 return Error{"value does not match type double"};
255 }
256 if (type == ConfigType::Integer && !std::holds_alternative<int64_t>(value)) {
257 return Error{"value does not match type integer"};
258 }
259 return std::nullopt;
260 }
261
262 ConfigType type_{};
263 bool optional_{false};
264 std::optional<Value> value_;
265 std::optional<std::reference_wrapper<Constraint const>> cons_;
266 std::optional<std::string_view> description_;
267};
268
269} // 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:214
constexpr ConfigType type() const
Gets the config type.
Definition ConfigValue.hpp:157
constexpr std::optional< std::reference_wrapper< Constraint const > > getConstraint() const
Retrieves the constraint associated with this ConfigValue, if any.
Definition ConfigValue.hpp:146
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:168
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:83
bool constexpr isOptional() const
Checks if configValue is optional.
Definition ConfigValue.hpp:179
Value const & getValue() const
Get the value of config.
Definition ConfigValue.hpp:200
bool constexpr hasValue() const
Check if value is optional.
Definition ConfigValue.hpp:189
constexpr ConfigValue & withConstraint(Constraint const &cons)
Assigns a constraint to the ConfigValue.
Definition ConfigValue.hpp:114
An interface to enforce constraints on certain values within ClioConfigDefinition.
Definition ConfigConstraints.hpp:91
Overload set for lambdas.
Definition OverloadSet.hpp:30
Displays the different errors when parsing user config.
Definition Error.hpp:31