Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
ConfigValue.hpp
1#pragma once
2
3#include "util/Assert.hpp"
4#include "util/OverloadSet.hpp"
5#include "util/config/ConfigConstraints.hpp"
6#include "util/config/Error.hpp"
7#include "util/config/Types.hpp"
8
9#include <fmt/format.h>
10
11#include <cstddef>
12#include <cstdint>
13#include <functional>
14#include <optional>
15#include <ostream>
16#include <string>
17#include <string_view>
18#include <variant>
19
20namespace util::config {
21
29public:
35 constexpr ConfigValue(ConfigType type) : type_(type)
36 {
37 }
38
46 [[nodiscard]] ConfigValue&
47 defaultValue(Value value, std::optional<std::string_view> description = std::nullopt)
48 {
49 auto const err = checkTypeConsistency(type_, value);
50 if (err.has_value())
51 ASSERT(false, "{}", err->error);
52 description_ = description;
53 value_ = value;
54 return *this;
55 }
56
65 [[nodiscard]] std::optional<Error>
66 setValue(Value value, std::optional<std::string_view> key = std::nullopt)
67 {
68 auto err = checkTypeConsistency(type_, value);
69 if (err.has_value()) {
70 err->error = fmt::format("{} {}", key.value_or("Unknown_key"), err->error);
71 return err;
72 }
73
74 if (cons_.has_value()) {
75 auto constraintCheck = cons_->get().checkConstraint(value);
76 if (constraintCheck.has_value()) {
77 constraintCheck->error =
78 fmt::format("{} {}", key.value_or("Unknown_key"), constraintCheck->error);
79 return constraintCheck;
80 }
81 }
82 value_ = value;
83 return std::nullopt;
84 }
85
97 [[nodiscard]] constexpr ConfigValue&
99 {
100 cons_ = std::reference_wrapper<Constraint const>(cons);
101 ASSERT(cons_.has_value(), "Constraint must be defined");
102
103 if (value_.has_value()) {
104 auto const& temp = cons_.value().get();
105 auto const& result = temp.checkConstraint(value_.value());
106 if (result.has_value()) {
107 // useful for specifying clear Error message
108 std::string type;
109 std::visit(
111 [&type](bool tmp) { type = fmt::format("bool {}", tmp); },
112 [&type](std::string const& tmp) { type = fmt::format("string {}", tmp); },
113 [&type](double tmp) { type = fmt::format("double {}", tmp); },
114 [&type](int64_t tmp) { type = fmt::format("int {}", tmp); },
115 },
116 value_.value()
117 );
118 ASSERT(false, "Value {} ConfigValue does not satisfy the set Constraint", type);
119 }
120 }
121 return *this;
122 }
123
129 [[nodiscard]] constexpr std::optional<std::reference_wrapper<Constraint const>>
131 {
132 return cons_;
133 }
134
140 [[nodiscard]] constexpr ConfigType
141 type() const
142 {
143 return type_;
144 }
145
152 [[nodiscard]] constexpr ConfigValue&
154 {
155 optional_ = true;
156 return *this;
157 }
158
164 [[nodiscard]] bool constexpr isOptional() const
165 {
166 return optional_;
167 }
168
174 [[nodiscard]] bool constexpr hasValue() const
175 {
176 return value_.has_value();
177 }
178
184 [[nodiscard]] Value const&
185 getValue() const
186 {
187 ASSERT(value_.has_value(), "getValue() is called when there is no value set");
188 return value_.value();
189 }
190
198 friend std::ostream&
199 operator<<(std::ostream& stream, ConfigValue val)
200 {
201 stream << "- **Required**: " << (val.isOptional() ? "False" : "True") << "\n";
202 stream << "- **Type**: " << val.type() << "\n";
203 if (val.description_.has_value()) {
204 stream << "- **Default value**: " << *val.description_ << "\n";
205 } else if (val.hasValue()) {
206 stream << "- **Default value**: `" << *val.value_ << "`\n";
207 } else {
208 stream << "- **Default value**: None\n";
209 }
210 stream << "- **Constraints**: ";
211
212 if (val.getConstraint().has_value()) {
213 stream << val.getConstraint()->get() << "\n";
214 } else {
215 stream << "None" << "\n";
216 }
217 return stream;
218 }
219
220private:
227 static std::optional<Error>
228 checkTypeConsistency(ConfigType type, Value value)
229 {
230 if (type == ConfigType::String && !std::holds_alternative<std::string>(value)) {
231 return Error{"value does not match type string"};
232 }
233 if (type == ConfigType::Boolean && !std::holds_alternative<bool>(value)) {
234 return Error{"value does not match type boolean"};
235 }
236 if (type == ConfigType::Double && (!std::holds_alternative<double>(value))) {
237 if (std::holds_alternative<int64_t>(value))
238 return std::nullopt;
239 return Error{"value does not match type double"};
240 }
241 if (type == ConfigType::Integer && !std::holds_alternative<int64_t>(value)) {
242 return Error{"value does not match type integer"};
243 }
244 return std::nullopt;
245 }
246
247 ConfigType type_{};
248 bool optional_{false};
249 std::optional<Value> value_;
250 std::optional<std::reference_wrapper<Constraint const>> cons_;
251 std::optional<std::string_view> description_;
252};
253
254} // namespace util::config
Represents the config values for Json/Yaml config.
Definition ConfigValue.hpp:28
ConfigValue & defaultValue(Value value, std::optional< std::string_view > description=std::nullopt)
Sets the default value for the config.
Definition ConfigValue.hpp:47
friend std::ostream & operator<<(std::ostream &stream, ConfigValue val)
Prints all the info of this config value to the output stream.
Definition ConfigValue.hpp:199
constexpr ConfigType type() const
Gets the config type.
Definition ConfigValue.hpp:141
constexpr std::optional< std::reference_wrapper< Constraint const > > getConstraint() const
Retrieves the constraint associated with this ConfigValue, if any.
Definition ConfigValue.hpp:130
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:153
constexpr ConfigValue(ConfigType type)
Constructor initializing with the config type.
Definition ConfigValue.hpp:35
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:66
bool constexpr isOptional() const
Checks if configValue is optional.
Definition ConfigValue.hpp:164
Value const & getValue() const
Get the value of config.
Definition ConfigValue.hpp:185
bool constexpr hasValue() const
Check if value is optional.
Definition ConfigValue.hpp:174
constexpr ConfigValue & withConstraint(Constraint const &cons)
Assigns a constraint to the ConfigValue.
Definition ConfigValue.hpp:98
An interface to enforce constraints on certain values within ClioConfigDefinition.
Definition ConfigConstraints.hpp:76
Overload set for lambdas.
Definition OverloadSet.hpp:11
Displays the different errors when parsing user config.
Definition Error.hpp:12