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
84 [[nodiscard]] std::optional<Error>
85 setValue(Value value, std::optional<std::string_view> key = std::nullopt)
86 {
87 auto err = checkTypeConsistency(type_, value);
88 if (err.has_value()) {
89 err->error = fmt::format("{} {}", key.value_or("Unknown_key"), err->error);
90 return err;
91 }
92
93 if (cons_.has_value()) {
94 auto constraintCheck = cons_->get().checkConstraint(value);
95 if (constraintCheck.has_value()) {
96 constraintCheck->error =
97 fmt::format("{} {}", key.value_or("Unknown_key"), constraintCheck->error);
98 return constraintCheck;
99 }
100 }
101 value_ = value;
102 return std::nullopt;
103 }
104
116 [[nodiscard]] constexpr ConfigValue&
118 {
119 cons_ = std::reference_wrapper<Constraint const>(cons);
120 ASSERT(cons_.has_value(), "Constraint must be defined");
121
122 if (value_.has_value()) {
123 auto const& temp = cons_.value().get();
124 auto const& result = temp.checkConstraint(value_.value());
125 if (result.has_value()) {
126 // useful for specifying clear Error message
127 std::string type;
128 std::visit(
130 [&type](bool tmp) { type = fmt::format("bool {}", tmp); },
131 [&type](std::string const& tmp) { type = fmt::format("string {}", tmp); },
132 [&type](double tmp) { type = fmt::format("double {}", tmp); },
133 [&type](int64_t tmp) { type = fmt::format("int {}", tmp); },
134 },
135 value_.value()
136 );
137 ASSERT(false, "Value {} ConfigValue does not satisfy the set Constraint", type);
138 }
139 }
140 return *this;
141 }
142
148 [[nodiscard]] constexpr std::optional<std::reference_wrapper<Constraint const>>
150 {
151 return cons_;
152 }
153
159 [[nodiscard]] constexpr ConfigType
160 type() const
161 {
162 return type_;
163 }
164
171 [[nodiscard]] constexpr ConfigValue&
173 {
174 optional_ = true;
175 return *this;
176 }
177
183 [[nodiscard]] bool constexpr isOptional() const
184 {
185 return optional_;
186 }
187
193 [[nodiscard]] bool constexpr hasValue() const
194 {
195 return value_.has_value();
196 }
197
203 [[nodiscard]] Value const&
204 getValue() const
205 {
206 ASSERT(value_.has_value(), "getValue() is called when there is no value set");
207 return value_.value();
208 }
209
217 friend std::ostream&
218 operator<<(std::ostream& stream, ConfigValue val)
219 {
220 stream << "- **Required**: " << (val.isOptional() ? "False" : "True") << "\n";
221 stream << "- **Type**: " << val.type() << "\n";
222 if (val.description_.has_value()) {
223 stream << "- **Default value**: " << *val.description_ << "\n";
224 } else if (val.hasValue()) {
225 stream << "- **Default value**: `" << *val.value_ << "`\n";
226 } else {
227 stream << "- **Default value**: None\n";
228 }
229 stream << "- **Constraints**: ";
230
231 if (val.getConstraint().has_value()) {
232 stream << val.getConstraint()->get() << "\n";
233 } else {
234 stream << "None" << "\n";
235 }
236 return stream;
237 }
238
239private:
246 static std::optional<Error>
247 checkTypeConsistency(ConfigType type, Value value)
248 {
249 if (type == ConfigType::String && !std::holds_alternative<std::string>(value)) {
250 return Error{"value does not match type string"};
251 }
252 if (type == ConfigType::Boolean && !std::holds_alternative<bool>(value)) {
253 return Error{"value does not match type boolean"};
254 }
255 if (type == ConfigType::Double && (!std::holds_alternative<double>(value))) {
256 if (std::holds_alternative<int64_t>(value))
257 return std::nullopt;
258 return Error{"value does not match type double"};
259 }
260 if (type == ConfigType::Integer && !std::holds_alternative<int64_t>(value)) {
261 return Error{"value does not match type integer"};
262 }
263 return std::nullopt;
264 }
265
266 ConfigType type_{};
267 bool optional_{false};
268 std::optional<Value> value_;
269 std::optional<std::reference_wrapper<Constraint const>> cons_;
270 std::optional<std::string_view> description_;
271};
272
273} // 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:218
constexpr ConfigType type() const
Gets the config type.
Definition ConfigValue.hpp:160
constexpr std::optional< std::reference_wrapper< Constraint const > > getConstraint() const
Retrieves the constraint associated with this ConfigValue, if any.
Definition ConfigValue.hpp:149
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:172
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:85
bool constexpr isOptional() const
Checks if configValue is optional.
Definition ConfigValue.hpp:183
Value const & getValue() const
Get the value of config.
Definition ConfigValue.hpp:204
bool constexpr hasValue() const
Check if value is optional.
Definition ConfigValue.hpp:193
constexpr ConfigValue & withConstraint(Constraint const &cons)
Assigns a constraint to the ConfigValue.
Definition ConfigValue.hpp:117
An interface to enforce constraints on certain values within ClioConfigDefinition.
Definition ConfigConstraints.hpp:95
Overload set for lambdas.
Definition OverloadSet.hpp:30
Displays the different errors when parsing user config.
Definition Error.hpp:31