29 #include <type_traits>
39 namespace fable::schema {
54 template <
typename T,
typename CRTP>
58 using MakeFunc = std::function<T(
const Conf& c)>;
64 TypeFactory(
Box s, MakeFunc f) : schema(std::move(s)), func(std::move(f)) {
72 using TransformFunc = std::function<
Box(
Struct&&)>;
73 using FactoryMap = std::map<std::string, TypeFactory>;
74 using FactoryPairList = std::initializer_list<std::pair<std::string, TypeFactory>>;
82 , transform_func_(other.transform_func_)
83 , available_(other.available_)
84 , factory_key_(other.factory_key_)
85 , args_key_(other.args_key_)
86 , args_subset_(other.args_subset_) {
94 Base<CRTP>::operator=(other);
95 transform_func_ = other.transform_func_;
96 available_ = other.available_;
97 factory_key_ = other.factory_key_;
98 args_key_ = other.args_key_;
99 args_subset_ = other.args_subset_;
104 FactoryBase(FactoryBase&&) noexcept = default;
106 FactoryBase& operator=(FactoryBase&&) noexcept = default;
120 :
Base<CRTP>(
JsonType::object, std::move(desc)), available_(std::move(fs)) {
124 FactoryBase(std::string desc, FactoryMap&& fs)
125 : Base<CRTP>(
JsonType::object, std::move(desc)), available_(std::move(fs)) {
136 return std::move(*
dynamic_cast<CRTP*
>(
this));
146 return std::move(*
dynamic_cast<CRTP*
>(
this));
156 return std::move(*
dynamic_cast<CRTP*
>(
this));
166 return std::move(*
dynamic_cast<CRTP*
>(
this));
177 assert(!keyword.empty());
178 factory_key_ = keyword;
222 return available_.at(key);
229 std::vector<std::string> keys;
230 for (
const auto& [key, value] : available_) {
231 keys.emplace_back(key);
239 [[nodiscard]]
bool has_factory(
const std::string& key)
const {
return available_.count(key); }
248 if (!available_.count(key)) {
249 available_.insert(std::make_pair(key,
TypeFactory{std::move(s), std::move(f)}));
260 if (!available_.count(key)) {
261 available_.erase(key);
263 available_.insert(std::make_pair(key,
TypeFactory{std::move(s), std::move(f)}));
280 template <
typename F,
281 std::enable_if_t<(std::is_default_constructible_v<F> &&
282 std::is_convertible_v<std::unique_ptr<F>, T>),
285 add_factory(key, make_prototype<F>().get_confable_schema(), [](
const Conf& c) -> T {
286 auto ptr = std::make_unique<F>();
295 if (available_.empty()) {
297 {
"description",
"no variants available"},
300 j[
"oneOf"] = factory_json_schemas();
302 this->augment_schema(j);
306 bool validate(
const Conf& c, std::optional<SchemaError>& err)
const override {
307 assert(schema_ !=
nullptr);
308 auto factory = c.
get<std::string>(factory_key_);
309 if (!available_.count(factory)) {
310 return this->set_error(err, c,
"unknown factory: {}", factory);
313 return schema_->validate(c, err);
316 [[nodiscard]] Type make(
const Conf& c)
const {
return deserialize(c); }
318 [[nodiscard]] Type deserialize(
const Conf& c)
const {
319 assert(schema_ !=
nullptr);
320 auto factory = c.
get<std::string>(factory_key_);
321 if (!available_.count(factory)) {
322 throw this->error(c,
"unknown factory: {}", factory);
327 if (!args_key_.empty()) {
328 if (c.
has(args_key_)) {
329 args = c.
at(args_key_);
333 args.
erase(factory_key_);
339 return available_.at(factory).func(args);
342 [[nodiscard]]
Json serialize(
const Type& x)
const {
return x; }
344 void serialize_into(Json& j,
const Type& x)
const { j = serialize(x); }
346 void deserialize_into(
const Conf& c, Type& x)
const { x = deserialize(c); }
349 throw std::logic_error(
"FactoryBase::from_conf() should not be used");
354 throw std::logic_error(
"FactoryBase::to_json() should not be used");
362 void reset_schema() {
363 if (available_.size() == 0) {
366 schema_ = std::make_unique<Variant>(factory_schemas());
369 [[nodiscard]] std::vector<Box> factory_schemas()
const {
370 std::vector<Box> out;
371 out.reserve(available_.size());
372 for (
auto& kv : available_) {
374 {factory_key_, make_const_schema(kv.first,
"name of factory").require()},
376 if (args_key_.empty()) {
377 base.set_properties_from(kv.second.schema);
379 base.set_property(args_key_, kv.second.schema.clone());
383 if (transform_func_) {
384 out.emplace_back(transform_func_(std::move(base)));
386 out.emplace_back(std::move(base));
392 [[nodiscard]] std::vector<Json> factory_json_schemas()
const {
393 auto schemas = factory_schemas();
394 std::vector<Json> out;
395 out.reserve(schemas.size());
396 for (
auto& s : schemas) {
397 out.emplace_back(s.json_schema());
403 std::unique_ptr<Variant> schema_;
404 TransformFunc transform_func_;
405 FactoryMap available_;
406 std::string factory_key_{
"factory"};
407 std::string args_key_{
"args"};
408 bool args_subset_{
true};
415 template <
typename T>
434 template <
typename T>
453 Factory(Type* ptr, std::string desc, FactoryMap&& fs)
455 for (
auto&& f : fs) {
456 this->available_.insert(f);
458 this->reset_schema();
461 Factory(Type* ptr, std::string desc, FactoryPairList fs)
463 for (
auto&& f : fs) {
464 this->available_.insert(f);
466 this->reset_schema();
471 assert(ptr_ !=
nullptr);
472 *ptr_ = this->deserialize(c);
476 assert(ptr_ !=
nullptr);
477 j = this->serialize(*ptr_);
bool has(const std::string &key) const
Definition: conf.hpp:165
size_t erase(const std::string &key)
Definition: conf.cpp:74
Conf at(const std::string &key) const
Definition: conf.cpp:58
T get() const
Definition: conf.hpp:297
Definition: interface.hpp:398
Definition: interface.hpp:297
void reset_ptr() override
Definition: interface.hpp:381
Definition: factory.hpp:55
void add_default_factory(const std::string &key)
Definition: factory.hpp:284
void set_transform_schema(TransformFunc f)
Definition: factory.hpp:216
void set_args_subset(bool value)
Definition: factory.hpp:207
Json json_schema() const override
Definition: factory.hpp:293
void from_conf(const Conf &) override
Definition: factory.hpp:348
bool has_factory(const std::string &key) const
Definition: factory.hpp:239
void reset_ptr() override
Definition: factory.hpp:357
const TypeFactory & get_factory(const std::string &key) const
Definition: factory.hpp:221
void set_factory(const std::string &key, Box &&s, MakeFunc f)
Definition: factory.hpp:259
std::vector< std::string > get_factory_keys() const
Definition: factory.hpp:228
CRTP args_key(const std::string &keyword) &&
Definition: factory.hpp:144
void to_json(Json &) const override
Definition: factory.hpp:353
void set_factory_key(const std::string &keyword)
Definition: factory.hpp:176
CRTP factory_key(const std::string &keyword) &&
Definition: factory.hpp:134
CRTP args_subset(bool value) &&
Definition: factory.hpp:154
void set_args_key(const std::string &keyword)
Definition: factory.hpp:191
CRTP transform_schema(TransformFunc f) &&
Definition: factory.hpp:164
bool validate(const Conf &c, std::optional< SchemaError > &err) const override
Definition: factory.hpp:306
bool add_factory(const std::string &key, Box &&s, MakeFunc f)
Definition: factory.hpp:247
Definition: factory.hpp:416
Definition: factory.hpp:435
void from_conf(const Conf &c) override
Definition: factory.hpp:470
void to_json(Json &j) const override
Definition: factory.hpp:475
void reset_ptr() override
Definition: factory.hpp:480
virtual Json to_json() const
Definition: interface.hpp:254
Definition: struct.hpp:70
nlohmann::json Json
Definition: fable_fwd.hpp:35
nlohmann::json::value_t JsonType
Definition: json.hpp:78
Definition: factory.hpp:63