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 <utility>
38#include <variant>
39
40namespace util::config {
41
49public:
55 constexpr ConfigValue(ConfigType type) : type_(type)
56 {
57 }
58
65 [[nodiscard]] ConfigValue&
66 defaultValue(Value value)
67 {
68 auto const err = checkTypeConsistency(type_, value);
69 ASSERT(!err.has_value(), "{}", err->error);
70 value_ = value;
71 return *this;
72 }
73
81 [[nodiscard]] std::optional<Error>
82 setValue(Value value, std::optional<std::string_view> key = std::nullopt)
83 {
84 if (std::holds_alternative<NullType>(value)) {
85 if (hasValue()) {
86 // Using default value
87 return std::nullopt;
88 }
89 if (not isOptional()) {
90 return Error{
91 key.value_or("Unknown_key"),
92 "Provided value is null but ConfigValue is not optional and doesn't have a default value."
93 };
94 }
95 value_ = std::move(value);
96 return std::nullopt;
97 }
98
99 auto err = checkTypeConsistency(type_, value);
100 if (err.has_value()) {
101 err->error = fmt::format("{} {}", key.value_or("Unknown_key"), err->error);
102 return err;
103 }
104
105 if (cons_.has_value()) {
106 auto constraintCheck = cons_->get().checkConstraint(value);
107 if (constraintCheck.has_value()) {
108 constraintCheck->error = fmt::format("{} {}", key.value_or("Unknown_key"), constraintCheck->error);
109 return constraintCheck;
110 }
111 }
112 value_ = value;
113 return std::nullopt;
114 }
115
127 [[nodiscard]] constexpr ConfigValue&
129 {
130 cons_ = std::reference_wrapper<Constraint const>(cons);
131 ASSERT(cons_.has_value(), "Constraint must be defined");
132
133 if (value_.has_value()) {
134 auto const& temp = cons_.value().get();
135 auto const& result = temp.checkConstraint(value_.value());
136 if (result.has_value()) {
137 // useful for specifying clear Error message
138 std::string type;
139 std::visit(
141 [&type](bool tmp) { type = fmt::format("bool {}", tmp); },
142 [&type](std::string const& tmp) { type = fmt::format("string {}", tmp); },
143 [&type](double tmp) { type = fmt::format("double {}", tmp); },
144 [&type](int64_t tmp) { type = fmt::format("int {}", tmp); },
145 [&type](NullType) { type = "null"; },
146 },
147 value_.value()
148 );
149 ASSERT(false, "Value {} ConfigValue does not satisfy the set Constraint", type);
150 }
151 }
152 return *this;
153 }
154
160 [[nodiscard]] constexpr std::optional<std::reference_wrapper<Constraint const>>
162 {
163 return cons_;
164 }
165
171 [[nodiscard]] constexpr ConfigType
172 type() const
173 {
174 return type_;
175 }
176
182 [[nodiscard]] constexpr ConfigValue&
184 {
185 optional_ = true;
186 return *this;
187 }
188
194 [[nodiscard]] bool constexpr isOptional() const
195 {
196 return optional_;
197 }
198
204 [[nodiscard]] bool constexpr hasValue() const
205 {
206 return value_.has_value();
207 }
208
214 [[nodiscard]] Value const&
215 getValue() const
216 {
217 ASSERT(value_.has_value(), "getValue() is called when there is no value set");
218 return value_.value();
219 }
220
228 friend std::ostream&
229 operator<<(std::ostream& stream, ConfigValue val)
230 {
231 stream << "- **Required**: " << (val.isOptional() ? "False" : "True") << "\n";
232 stream << "- **Type**: " << val.type() << "\n";
233 stream << "- **Default value**: " << (val.hasValue() ? *val.value_ : "None") << "\n";
234 stream << "- **Constraints**: ";
235
236 if (val.getConstraint().has_value()) {
237 stream << val.getConstraint()->get() << "\n";
238 } else {
239 stream << "None" << "\n";
240 }
241 return stream;
242 }
243
244private:
251 static std::optional<Error>
252 checkTypeConsistency(ConfigType type, Value value)
253 {
254 if (type == ConfigType::String && !std::holds_alternative<std::string>(value)) {
255 return Error{"value does not match type string"};
256 }
257 if (type == ConfigType::Boolean && !std::holds_alternative<bool>(value)) {
258 return Error{"value does not match type boolean"};
259 }
260 if (type == ConfigType::Double && (!std::holds_alternative<double>(value))) {
261 if (std::holds_alternative<int64_t>(value))
262 return std::nullopt;
263 return Error{"value does not match type double"};
264 }
265 if (type == ConfigType::Integer && !std::holds_alternative<int64_t>(value)) {
266 return Error{"value does not match type integer"};
267 }
268 return std::nullopt;
269 }
270
271 ConfigType type_{};
272 bool optional_{false};
273 std::optional<Value> value_;
274 std::optional<std::reference_wrapper<Constraint const>> cons_;
275};
276
277} // namespace util::config
Represents the config values for Json/Yaml config.
Definition ConfigValue.hpp:48
friend std::ostream & operator<<(std::ostream &stream, ConfigValue val)
Prints all the info of this config value to the output stream.
Definition ConfigValue.hpp:229
constexpr ConfigType type() const
Gets the config type.
Definition ConfigValue.hpp:172
constexpr std::optional< std::reference_wrapper< Constraint const > > getConstraint() const
Retrieves the constraint associated with this ConfigValue, if any.
Definition ConfigValue.hpp:161
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:183
constexpr ConfigValue(ConfigType type)
Constructor initializing with the config type.
Definition ConfigValue.hpp:55
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:82
bool constexpr isOptional() const
Checks if configValue is optional.
Definition ConfigValue.hpp:194
ConfigValue & defaultValue(Value value)
Sets the default value for the config.
Definition ConfigValue.hpp:66
Value const & getValue() const
Get the value of config.
Definition ConfigValue.hpp:215
bool constexpr hasValue() const
Check if value is optional.
Definition ConfigValue.hpp:204
constexpr ConfigValue & withConstraint(Constraint const &cons)
Assigns a constraint to the ConfigValue.
Definition ConfigValue.hpp:128
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
A type that represents a null value.
Definition Types.hpp:40