30 #include <type_traits>
40 namespace fable::schema {
55 template <
typename T,
typename CRTP>
59 using MakeFunc = std::function<T(
const Conf& c)>;
65 TypeFactory(
Box s, MakeFunc f) : schema(std::move(s)), func(std::move(f)) {
73 using TransformFunc = std::function<
Box(
Struct&&)>;
74 using FactoryMap = std::map<std::string, TypeFactory>;
75 using FactoryPairList = std::initializer_list<std::pair<std::string, TypeFactory>>;
83 , transform_func_(other.transform_func_)
84 , available_(other.available_)
85 , factory_key_(other.factory_key_)
86 , args_key_(other.args_key_)
87 , args_subset_(other.args_subset_) {
95 Base<CRTP>::operator=(other);
96 transform_func_ = other.transform_func_;
97 available_ = other.available_;
98 factory_key_ = other.factory_key_;
99 args_key_ = other.args_key_;
100 args_subset_ = other.args_subset_;
105 FactoryBase(FactoryBase&&) noexcept = default;
107 FactoryBase& operator=(FactoryBase&&) noexcept = default;
121 :
Base<CRTP>(
JsonType::object, std::move(desc)), available_(std::move(fs)) {
125 FactoryBase(std::string desc, FactoryMap&& fs)
126 : Base<CRTP>(
JsonType::object, std::move(desc)), available_(std::move(fs)) {
137 return std::move(*
dynamic_cast<CRTP*
>(
this));
147 return std::move(*
dynamic_cast<CRTP*
>(
this));
157 return std::move(*
dynamic_cast<CRTP*
>(
this));
167 return std::move(*
dynamic_cast<CRTP*
>(
this));
178 assert(!keyword.empty());
179 factory_key_ = keyword;
223 return available_.at(key);
229 [[nodiscard]]
bool has_factory(
const std::string& key)
const {
return available_.count(key); }
238 if (!available_.count(key)) {
239 available_.insert(std::make_pair(key,
TypeFactory{std::move(s), std::move(f)}));
250 if (!available_.count(key)) {
251 available_.erase(key);
253 available_.insert(std::make_pair(key,
TypeFactory{std::move(s), std::move(f)}));
270 template <
typename F,
271 std::enable_if_t<(std::is_default_constructible_v<F> &&
272 std::is_convertible_v<std::unique_ptr<F>, T>),
275 add_factory(key, make_prototype<F>().get_confable_schema(), [](
const Conf& c) -> T {
276 auto ptr = std::make_unique<F>();
285 if (available_.empty()) {
287 {
"description",
"no variants available"},
290 j[
"oneOf"] = factory_json_schemas();
292 this->augment_schema(j);
296 bool validate(
const Conf& c, std::optional<SchemaError>& err)
const override {
297 assert(schema_ !=
nullptr);
298 auto factory = c.
get<std::string>(factory_key_);
299 if (!available_.count(factory)) {
300 return this->set_error(err, c,
"unknown factory: {}", factory);
303 return schema_->validate(c, err);
306 [[nodiscard]] Type make(
const Conf& c)
const {
return deserialize(c); }
308 [[nodiscard]] Type deserialize(
const Conf& c)
const {
309 assert(schema_ !=
nullptr);
310 auto factory = c.
get<std::string>(factory_key_);
311 if (!available_.count(factory)) {
312 throw this->error(c,
"unknown factory: {}", factory);
317 if (!args_key_.empty()) {
318 if (c.
has(args_key_)) {
319 args = c.
at(args_key_);
323 args.
erase(factory_key_);
329 return available_.at(factory).func(args);
332 [[nodiscard]]
Json serialize(
const Type& x)
const {
return x; }
334 void serialize_into(Json& j,
const Type& x)
const { j = serialize(x); }
336 void deserialize_into(
const Conf& c, Type& x)
const { x = deserialize(c); }
339 throw std::logic_error(
"FactoryBase::from_conf() should not be used");
344 throw std::logic_error(
"FactoryBase::to_json() should not be used");
352 void reset_schema() {
353 if (available_.size() == 0) {
356 schema_ = std::make_unique<Variant>(factory_schemas());
359 [[nodiscard]] std::vector<Box> factory_schemas()
const {
360 std::vector<Box> out;
361 out.reserve(available_.size());
362 for (
auto& kv : available_) {
364 {factory_key_, make_const_schema(kv.first,
"name of factory").require()},
366 if (args_key_.empty()) {
367 base.set_properties_from(kv.second.schema);
369 base.set_property(args_key_, kv.second.schema.clone());
373 if (transform_func_) {
374 out.emplace_back(transform_func_(std::move(base)));
376 out.emplace_back(std::move(base));
382 [[nodiscard]] std::vector<Json> factory_json_schemas()
const {
383 auto schemas = factory_schemas();
384 std::vector<Json> out;
385 out.reserve(schemas.size());
386 for (
auto& s : schemas) {
387 out.emplace_back(s.json_schema());
393 std::unique_ptr<Variant> schema_;
394 TransformFunc transform_func_;
395 FactoryMap available_;
396 std::string factory_key_{
"factory"};
397 std::string args_key_{
"args"};
398 bool args_subset_{
true};
405 template <
typename T>
424 template <
typename T>
443 Factory(Type* ptr, std::string desc, FactoryMap&& fs)
445 for (
auto&& f : fs) {
446 this->available_.insert(f);
448 this->reset_schema();
451 Factory(Type* ptr, std::string desc, FactoryPairList fs)
453 for (
auto&& f : fs) {
454 this->available_.insert(f);
456 this->reset_schema();
461 assert(ptr_ !=
nullptr);
462 *ptr_ = this->deserialize(c);
466 assert(ptr_ !=
nullptr);
467 j = this->serialize(*ptr_);
bool has(const std::string &key) const
Definition: conf.hpp:132
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:166
Definition: interface.hpp:398
Definition: interface.hpp:297
void reset_ptr() override
Definition: interface.hpp:381
Definition: factory.hpp:56
void add_default_factory(const std::string &key)
Definition: factory.hpp:274
void set_transform_schema(TransformFunc f)
Definition: factory.hpp:217
void set_args_subset(bool value)
Definition: factory.hpp:208
Json json_schema() const override
Definition: factory.hpp:283
void from_conf(const Conf &) override
Definition: factory.hpp:338
bool has_factory(const std::string &key) const
Definition: factory.hpp:229
void reset_ptr() override
Definition: factory.hpp:347
const TypeFactory & get_factory(const std::string &key) const
Definition: factory.hpp:222
void set_factory(const std::string &key, Box &&s, MakeFunc f)
Definition: factory.hpp:249
CRTP args_key(const std::string &keyword) &&
Definition: factory.hpp:145
void to_json(Json &) const override
Definition: factory.hpp:343
void set_factory_key(const std::string &keyword)
Definition: factory.hpp:177
CRTP factory_key(const std::string &keyword) &&
Definition: factory.hpp:135
CRTP args_subset(bool value) &&
Definition: factory.hpp:155
void set_args_key(const std::string &keyword)
Definition: factory.hpp:192
CRTP transform_schema(TransformFunc f) &&
Definition: factory.hpp:165
bool validate(const Conf &c, std::optional< SchemaError > &err) const override
Definition: factory.hpp:296
bool add_factory(const std::string &key, Box &&s, MakeFunc f)
Definition: factory.hpp:237
Definition: factory.hpp:406
Definition: factory.hpp:425
void from_conf(const Conf &c) override
Definition: factory.hpp:460
void to_json(Json &j) const override
Definition: factory.hpp:465
void reset_ptr() override
Definition: factory.hpp:470
virtual Json to_json() const
Definition: interface.hpp:254
Definition: struct.hpp:70
nlohmann::json Json
Definition: fable_fwd.hpp:35
nlohmann::detail::value_t JsonType
Definition: fable_fwd.hpp:37
Definition: factory.hpp:64