29 #include <initializer_list>
33 #include <type_traits>
38 #include <fable/utility/templates.hpp>
40 namespace fable::schema {
43 Number<T> Number<T>::minimum(T value) && {
45 return std::move(*
this);
49 void Number<T>::set_minimum(T value) {
51 exclusive_min_ =
false;
55 Number<T> Number<T>::exclusive_minimum(T value) && {
56 set_exclusive_minimum(value);
57 return std::move(*
this);
61 void Number<T>::set_exclusive_minimum(T value) {
63 exclusive_min_ =
true;
67 Number<T> Number<T>::maximum(T value) && {
69 return std::move(*
this);
73 void Number<T>::set_maximum(T value) {
75 exclusive_max_ =
false;
79 Number<T> Number<T>::exclusive_maximum(T value) && {
80 set_exclusive_maximum(value);
81 return std::move(*
this);
85 void Number<T>::set_exclusive_maximum(T value) {
87 exclusive_max_ =
true;
91 std::pair<T, T> Number<T>::bounds()
const {
92 return std::make_pair(value_min_, value_max_);
96 Number<T> Number<T>::bounds(T min, T max) && {
98 return std::move(*
this);
101 template <
typename T>
102 void Number<T>::set_bounds(T min, T max) {
103 exclusive_min_ =
false;
105 exclusive_max_ =
false;
109 template <
typename T>
110 Number<T> Number<T>::bounds_with(T min, T max, std::initializer_list<T> whitelisted) && {
111 exclusive_min_ =
false;
113 exclusive_max_ =
false;
115 for (
auto x : whitelisted) {
118 return std::move(*
this);
121 template <
typename T>
122 Number<T> Number<T>::whitelist(T x) && {
124 return std::move(*
this);
127 template <
typename T>
128 Number<T> Number<T>::whitelist(std::initializer_list<T> xs) && {
129 extend_whitelist(std::move(xs));
130 return std::move(*
this);
133 template <
typename T>
134 void Number<T>::insert_whitelist(T x) {
135 if (std::is_floating_point_v<T>) {
136 throw std::logic_error(
"cannot whitelist floating-point numbers");
138 if (blacklist_.count(x)) {
139 throw std::logic_error(
"cannot add blacklisted value to whitelist: " + std::to_string(x));
141 whitelist_.insert(x);
144 template <
typename T>
145 void Number<T>::extend_whitelist(std::initializer_list<T> xs) {
146 for (
const auto& x : xs) {
151 template <
typename T>
152 void Number<T>::reset_whitelist(std::initializer_list<T> xs) {
154 extend_whitelist(std::move(xs));
157 template <
typename T>
158 Number<T> Number<T>::blacklist(T x) && {
160 return std::move(*
this);
163 template <
typename T>
164 Number<T> Number<T>::blacklist(std::initializer_list<T> xs) && {
165 extend_blacklist(std::move(xs));
166 return std::move(*
this);
169 template <
typename T>
170 void Number<T>::insert_blacklist(T x) {
171 if (std::is_floating_point_v<T>) {
172 throw std::logic_error(
"cannot blacklist floating-point numbers");
174 if (blacklist_.count(x)) {
175 throw std::logic_error(
"cannot add whitelisted value to blacklist: " + std::to_string(x));
177 blacklist_.insert(x);
180 template <
typename T>
181 void Number<T>::extend_blacklist(std::initializer_list<T> xs) {
182 for (
const auto& x : xs) {
187 template <
typename T>
188 void Number<T>::reset_blacklist(std::initializer_list<T> xs) {
190 extend_blacklist(std::move(xs));
193 template <
typename T>
196 {
"type", this->type_string()},
197 {exclusive_min_ ?
"exclusiveMinimum" :
"minimum", value_min_},
198 {exclusive_max_ ?
"exclusiveMaximum" :
"maximum", value_max_},
201 if (!std::is_floating_point_v<T>) {
202 auto write_list = [&j](
auto name,
auto xlist) {
203 if (!xlist.empty()) {
205 for (
auto x : xlist) {
212 write_list(
"whitelist", whitelist_);
213 write_list(
"blacklist", blacklist_);
216 this->augment_schema(j);
220 template <
typename T>
223 case JsonType::number_unsigned:
224 return validate_bounds<uint64_t>(c, err);
225 case JsonType::number_integer:
226 return validate_bounds<int64_t>(c, err);
227 case JsonType::number_float:
228 if (this->type() != JsonType::number_float) {
229 return this->set_wrong_type(err, c);
231 return validate_bounds<double>(c, err);
234 return this->set_wrong_type(err, c);
238 template <
typename T>
240 assert(ptr_ !=
nullptr);
241 j = serialize(*ptr_);
244 template <
typename T>
246 assert(ptr_ !=
nullptr);
247 *ptr_ = deserialize(c);
250 template <
typename T>
255 template <
typename T>
256 T Number<T>::deserialize(
const Conf& c)
const {
260 template <
typename T>
261 void Number<T>::serialize_into(Json& j,
const T& x)
const {
265 template <
typename T>
266 void Number<T>::deserialize_into(
const Conf& c, T& x)
const {
270 template <
typename T>
288 template <
typename T>
289 template <
typename B>
291 auto original = c.
get<B>();
292 auto value =
static_cast<T
>(original);
293 if constexpr (!std::is_floating_point_v<T>) {
294 if (!is_cast_safe<T>(original)) {
295 return this->set_error(err, c,
296 "failed to convert input to destination type {}, got {}( {} ) = {}",
302 if (!std::is_floating_point_v<T>) {
303 if (whitelist_.count(value)) {
306 if (blacklist_.count(value)) {
307 return this->set_error(err, c,
"unexpected blacklisted value {}", value);
312 if (exclusive_min_) {
313 if (value <= value_min_) {
314 return this->set_error(err, c,
"expected exclusive minimum > {}, got {}", value_min_, value);
317 if (value < value_min_) {
318 return this->set_error(err, c,
"expected minimum >= {}, got {}", value_min_, value);
322 if (exclusive_max_) {
323 if (value >= value_max_) {
324 return this->set_error(err, c,
"expected exclusive maximum < {}, got {}", value_max_, value);
327 if (value > value_max_) {
328 return this->set_error(err, c,
"expected maximum <= {}, got {}", value_max_, value);
T get() const
Definition: conf.hpp:298
Definition: number.hpp:36
void from_conf(const Conf &c) override
Definition: number_impl.hpp:245
virtual Json to_json() const
Definition: interface.hpp:254
Json json_schema() const override
Definition: number_impl.hpp:194
void reset_ptr() override
Definition: number_impl.hpp:271
bool validate(const Conf &c, std::optional< SchemaError > &err) const override
Definition: number_impl.hpp:221
nlohmann::json Json
Definition: fable_fwd.hpp:35
Definition: templates.hpp:66