cppfig 0.1.0
Modern C++20 compile-time type-safe configuration library
Loading...
Searching...
No Matches
validator.h
Go to the documentation of this file.
1#pragma once
2
3#include <concepts>
4#include <cstddef>
5#include <functional>
6#include <string>
7#include <type_traits>
8#include <vector>
9
10namespace cppfig {
11
14 bool is_valid = true;
15 std::string error_message;
16
18 static auto Ok() -> ValidationResult { return { .is_valid = true, .error_message = "" }; }
19
21 static auto Error(std::string message) -> ValidationResult { return { .is_valid = false, .error_message = std::move(message) }; }
22
23 explicit operator bool() const { return is_valid; }
24};
25
27template <typename V, typename T>
28concept ValidatorFor = requires(const V& validator, const T& value) {
29 { validator(value) } -> std::same_as<ValidationResult>;
30};
31
33template <typename T>
34class Validator {
35public:
36 using validator_fn = std::function<ValidationResult(const T&)>;
37
40 : fn_([](const T&) { return ValidationResult::Ok(); })
41 {
42 }
43
46 : fn_(std::move(fn))
47 {
48 }
49
51 auto operator()(const T& value) const -> ValidationResult { return fn_(value); }
52
54 [[nodiscard]] auto And(Validator<T> other) const -> Validator<T>
55 {
56 auto this_fn = fn_;
57 auto other_fn = other.fn_;
58 return Validator<T>([this_fn, other_fn](const T& value) -> ValidationResult {
59 auto result = this_fn(value);
60 if (!result) {
61 return result;
62 }
63 return other_fn(value);
64 });
65 }
66
68 [[nodiscard]] auto Or(Validator<T> other) const -> Validator<T>
69 {
70 auto this_fn = fn_;
71 auto other_fn = other.fn_;
72 return Validator<T>([this_fn, other_fn](const T& value) -> ValidationResult {
73 auto result = this_fn(value);
74 if (result) {
75 return result;
76 }
77 return other_fn(value);
78 });
79 }
80
81private:
82 validator_fn fn_;
83};
84
86template <typename T>
87 requires std::is_arithmetic_v<T>
88auto Min(T min_value) -> Validator<T>
89{
90 return Validator<T>([min_value](const T& value) -> ValidationResult {
91 if (value < min_value) {
92 return ValidationResult::Error("Value " + std::to_string(value) + " is less than minimum " + std::to_string(min_value));
93 }
94 return ValidationResult::Ok();
95 });
96}
97
99template <typename T>
100 requires std::is_arithmetic_v<T>
101auto Max(T max_value) -> Validator<T>
102{
103 return Validator<T>([max_value](const T& value) -> ValidationResult {
104 if (value > max_value) {
105 return ValidationResult::Error("Value " + std::to_string(value) + " exceeds maximum " + std::to_string(max_value));
106 }
107 return ValidationResult::Ok();
108 });
109}
110
112template <typename T>
113 requires std::is_arithmetic_v<T>
114auto Range(T min_value, T max_value) -> Validator<T>
115{
116 return Min(min_value).And(Max(max_value));
117}
118
120template <typename T>
121 requires std::is_arithmetic_v<T>
123{
124 return Validator<T>([](const T& value) -> ValidationResult {
125 if (value <= T { 0 }) {
126 return ValidationResult::Error("Value must be positive");
127 }
128 return ValidationResult::Ok();
129 });
130}
131
133template <typename T>
134 requires std::is_arithmetic_v<T>
136{
137 return Validator<T>([](const T& value) -> ValidationResult {
138 if (value < T { 0 }) {
139 return ValidationResult::Error("Value must be non-negative");
140 }
141 return ValidationResult::Ok();
142 });
143}
144
147{
148 return Validator<std::string>([](const std::string& value) -> ValidationResult {
149 if (value.empty()) {
150 return ValidationResult::Error("Value must not be empty");
151 }
152 return ValidationResult::Ok();
153 });
154}
155
157inline auto MaxLength(std::size_t max_len) -> Validator<std::string>
158{
159 return Validator<std::string>([max_len](const std::string& value) -> ValidationResult {
160 if (value.size() > max_len) {
161 return ValidationResult::Error("String length " + std::to_string(value.size()) + " exceeds maximum " + std::to_string(max_len));
162 }
163 return ValidationResult::Ok();
164 });
165}
166
168inline auto MinLength(std::size_t min_len) -> Validator<std::string>
169{
170 return Validator<std::string>([min_len](const std::string& value) -> ValidationResult {
171 if (value.size() < min_len) {
172 return ValidationResult::Error("String length " + std::to_string(value.size()) + " is less than minimum " + std::to_string(min_len));
173 }
174 return ValidationResult::Ok();
175 });
176}
177
179template <typename T>
180auto OneOf(std::vector<T> allowed_values) -> Validator<T>
181{
182 return Validator<T>([allowed = std::move(allowed_values)](const T& value) -> ValidationResult {
183 for (const auto& allowed_value : allowed) {
184 if (value == allowed_value) {
185 return ValidationResult::Ok();
186 }
187 }
188 return ValidationResult::Error("Value is not in the list of allowed values");
189 });
190}
191
193template <typename T, typename Pred>
194 requires std::predicate<Pred, const T&>
195auto Predicate(Pred pred, std::string error_message) -> Validator<T>
196{
197 return Validator<T>([p = std::move(pred), msg = std::move(error_message)](const T& value) -> ValidationResult {
198 if (!p(value)) {
199 return ValidationResult::Error(msg);
200 }
201 return ValidationResult::Ok();
202 });
203}
204
206template <typename T>
208{
209 return Validator<T>();
210}
211
212} // namespace cppfig
Type-erased validator that can hold any validation function.
Definition validator.h:34
Validator()
Creates an always-valid validator.
Definition validator.h:39
auto And(Validator< T > other) const -> Validator< T >
Combines this validator with another (both must pass).
Definition validator.h:54
auto Or(Validator< T > other) const -> Validator< T >
Combines this validator with another (either must pass).
Definition validator.h:68
auto operator()(const T &value) const -> ValidationResult
Validates a value.
Definition validator.h:51
std::function< ValidationResult(const T &)> validator_fn
Definition validator.h:36
Validator(validator_fn fn)
Creates a validator from a function.
Definition validator.h:45
Concept for validator types.
Definition validator.h:28
C++20 compile-time type-safe configuration library.
Definition conf.h:17
auto Positive() -> Validator< T >
Creates a validator that checks if a numeric value is positive.
Definition validator.h:122
auto Predicate(Pred pred, std::string error_message) -> Validator< T >
Creates a validator from a predicate function.
Definition validator.h:195
auto Max(T max_value) -> Validator< T >
Creates a validator that checks if a numeric value is at most max.
Definition validator.h:101
auto MaxLength(std::size_t max_len) -> Validator< std::string >
Creates a validator that checks if a string length is at most max.
Definition validator.h:157
auto NonNegative() -> Validator< T >
Creates a validator that checks if a numeric value is non-negative.
Definition validator.h:135
auto MinLength(std::size_t min_len) -> Validator< std::string >
Creates a validator that checks if a string length is at least min.
Definition validator.h:168
auto Range(T min_value, T max_value) -> Validator< T >
Creates a validator that checks if a numeric value is within [min, max].
Definition validator.h:114
auto AlwaysValid() -> Validator< T >
Creates an always-valid validator.
Definition validator.h:207
auto Min(T min_value) -> Validator< T >
Creates a validator that checks if a numeric value is at least min.
Definition validator.h:88
auto OneOf(std::vector< T > allowed_values) -> Validator< T >
Creates a validator that checks if a value is one of the allowed values.
Definition validator.h:180
auto NotEmpty() -> Validator< std::string >
Creates a validator that checks if a string is not empty.
Definition validator.h:146
Result of a validation operation.
Definition validator.h:13
static auto Ok() -> ValidationResult
Creates a successful validation result.
Definition validator.h:18
static auto Error(std::string message) -> ValidationResult
Creates a failed validation result with an error message.
Definition validator.h:21
std::string error_message
Definition validator.h:15
bool is_valid
Definition validator.h:14