29 #include <type_traits>
37 namespace fable::schema {
84 [[nodiscard]]
virtual std::unique_ptr<Interface>
clone()
const = 0;
92 [[nodiscard]]
virtual bool is_variant()
const {
return false; }
204 virtual bool validate(
const Conf& c, std::optional<SchemaError>& error)
const = 0;
219 if (
auto err =
fail(c); err) {
220 throw std::move(*err);
237 [[nodiscard]]
virtual std::optional<SchemaError>
fail(
const Conf& c)
const final {
238 std::optional<SchemaError> err;
292 template <
typename S>
293 using enable_if_schema_t = std::enable_if_t<std::is_base_of_v<Interface, S>>;
300 Box(
const Box&) =
default;
301 Box(
Box&&) noexcept =
default;
302 Box& operator=(
const Box&) =
default;
303 Box& operator=(
Box&&) noexcept =
default;
304 ~
Box() noexcept
override =
default;
306 Box(std::unique_ptr<Interface> i) : impl_(std::move(i)) { assert(impl_); }
307 Box(std::shared_ptr<Interface> i) : impl_(std::move(i)) { assert(impl_); }
313 [[nodiscard]] std::shared_ptr<Interface>
get() {
return impl_; }
324 template <
typename T>
325 [[nodiscard]] std::shared_ptr<T>
as()
const {
326 assert(impl_ !=
nullptr);
327 auto downcast_ptr = std::dynamic_pointer_cast<T>(impl_);
328 if (downcast_ptr ==
nullptr) {
345 "cannot dynamic_pointer_cast to type T, got nullptr"};
356 template <
typename T>
358 return std::dynamic_pointer_cast<T>(impl_);
361 [[nodiscard]]
Box reset_pointer() && {
363 return std::move(*
this);
368 [[nodiscard]] std::unique_ptr<Interface>
clone()
const override {
return impl_->clone(); }
370 [[nodiscard]] std::string
type_string()
const override {
return impl_->type_string(); }
371 [[nodiscard]]
bool is_required()
const override {
return impl_->is_required(); }
372 [[nodiscard]]
const std::string&
description()
const override {
return impl_->description(); }
373 void set_description(std::string s)
override {
return impl_->set_description(std::move(s)); }
374 [[nodiscard]]
Json usage()
const override {
return impl_->usage(); }
376 bool validate(
const Conf& c, std::optional<SchemaError>& err)
const override {
377 return impl_->validate(c, err);
383 friend void to_json(
Json& j,
const Box& b) { b.impl_->to_json(j); }
386 std::shared_ptr<Interface> impl_{
nullptr};
397 template <
typename CRTP>
406 Base(
JsonType t, std::string desc) : type_(t), desc_(std::move(desc)) {}
408 explicit Base(std::string desc) : desc_(std::move(desc)) {}
411 ~
Base() noexcept
override =
default;
413 [[nodiscard]] std::unique_ptr<Interface>
clone()
const override {
414 return std::make_unique<CRTP>(
static_cast<CRTP const&
>(*
this));
416 [[nodiscard]]
operator Box()
const {
return Box{this->
clone()}; }
419 [[nodiscard]] std::string
type_string()
const override {
return to_string(type_); }
422 const auto* required = required_ ?
"!" :
"";
426 return fmt::format(
"{}{} :: {}",
type_string(), required, desc_);
429 [[nodiscard]]
bool is_required()
const override {
return required_; }
430 [[nodiscard]] CRTP require() && {
432 return std::move(*
dynamic_cast<CRTP*
>(
this));
434 [[nodiscard]] CRTP required(
bool value) && {
436 return std::move(*
dynamic_cast<CRTP*
>(
this));
439 [[nodiscard]] CRTP reset_pointer() && {
441 return std::move(*
dynamic_cast<CRTP*
>(
this));
444 [[nodiscard]]
bool has_description()
const {
return !desc_.empty(); }
446 [[nodiscard]]
const std::string&
description()
const override {
return desc_; }
447 [[nodiscard]] CRTP
description(std::string desc) && {
448 desc_ = std::move(desc);
449 return std::move(*
dynamic_cast<CRTP*
>(
this));
460 if (c->type() != type_) {
461 if (c->type() == JsonType::number_unsigned && type_ == JsonType::number_integer) {
465 return this->set_error(err, c,
"require type {}, got {}",
type_string(),
466 to_string(c->type()));
471 template <
typename... Args>
472 [[nodiscard]]
SchemaError error(
const Conf& c, std::string_view format, Args&&... args)
const {
476 [[nodiscard]] SchemaError error(
const ConfError& e)
const {
480 [[nodiscard]] SchemaError wrong_type(
const Conf& c)
const {
481 return error(error::WrongType(c, type_));
484 template <
typename... Args>
485 bool set_error(std::optional<SchemaError>& err,
const Conf& c, std::string_view format,
486 Args&&... args)
const {
487 err.emplace(this->error(c, format, std::forward<Args>(args)...));
491 bool set_error(std::optional<SchemaError>& err,
const ConfError& e)
const {
492 err.emplace(this->error(e));
496 bool set_error(std::optional<SchemaError>& err, SchemaError&& e)
const {
497 err.emplace(std::move(e));
501 bool set_wrong_type(std::optional<SchemaError>& err,
const Conf& c)
const {
502 err.emplace(this->wrong_type(c));
506 void augment_schema(Json& j)
const {
507 if (!desc_.empty()) {
508 j[
"description"] = desc_;
514 bool required_{
false};
528 template <
typename T>
529 using enable_if_confable_t = std::enable_if_t<std::is_base_of_v<Confable, T>>;
539 template <
typename T>
540 using enable_if_not_confable_t = std::enable_if_t<!std::is_base_of_v<Confable, T>>;
542 template <
typename T,
typename S = std::
string, std::enable_if_t<std::is_base_of_v<Confable, T>,
int> = 0>
543 auto make_prototype(S&& desc =
"");
545 template <
typename T,
typename S = std::
string, std::enable_if_t<!std::is_base_of_v<Confable, T>,
int> = 0>
546 auto make_prototype(S&& desc =
"");
Definition: error.hpp:149
Definition: interface.hpp:398
bool is_required() const override
Definition: interface.hpp:429
const std::string & description() const override
Definition: interface.hpp:446
Json usage() const override
Definition: interface.hpp:421
JsonType type() const override
Definition: interface.hpp:418
std::unique_ptr< Interface > clone() const override
Definition: interface.hpp:413
bool validate_type(const Conf &c, std::optional< SchemaError > &err) const
Definition: interface.hpp:459
std::string type_string() const override
Definition: interface.hpp:419
void set_description(std::string s) override
Definition: interface.hpp:445
Definition: interface.hpp:297
void from_conf(const Conf &c) override
Definition: interface.hpp:380
Json json_schema() const override
Definition: interface.hpp:375
std::shared_ptr< T > as_unsafe() const
Definition: interface.hpp:357
std::string type_string() const override
Definition: interface.hpp:370
void to_json(Json &j) const override
Definition: interface.hpp:379
void reset_ptr() override
Definition: interface.hpp:381
virtual Json to_json() const
Definition: interface.hpp:254
Json usage() const override
Definition: interface.hpp:374
bool is_required() const override
Definition: interface.hpp:371
std::shared_ptr< T > as() const
Definition: interface.hpp:325
std::unique_ptr< Interface > clone() const override
Definition: interface.hpp:368
std::shared_ptr< Interface > get()
Definition: interface.hpp:313
void set_description(std::string s) override
Definition: interface.hpp:373
JsonType type() const override
Definition: interface.hpp:369
bool validate(const Conf &c, std::optional< SchemaError > &err) const override
Definition: interface.hpp:376
const std::string & description() const override
Definition: interface.hpp:372
Definition: interface.hpp:67
virtual void validate_or_throw(const Conf &c) const final
Definition: interface.hpp:218
virtual Json json_schema() const =0
virtual bool validate(const Conf &c, std::optional< SchemaError > &error) const =0
virtual std::optional< SchemaError > fail(const Conf &c) const final
Definition: interface.hpp:237
virtual Json to_json() const
Definition: interface.hpp:254
virtual void from_conf(const Conf &)=0
virtual const std::string & description() const =0
virtual bool is_variant() const
Definition: interface.hpp:92
virtual bool is_required() const =0
virtual JsonType type() const =0
virtual bool is_valid(const Conf &c) const final
Definition: interface.hpp:246
virtual void reset_ptr()=0
virtual std::string type_string() const =0
virtual void set_description(std::string s)=0
virtual std::unique_ptr< Interface > clone() const =0
virtual void to_json(Json &) const =0
virtual Json usage() const =0
nlohmann::json Json
Definition: fable_fwd.hpp:35
nlohmann::json::value_t JsonType
Definition: json.hpp:78