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);
230 std::vector<std::string> keys;
231 for (
const auto& [key, value] : available_) {
232 keys.emplace_back(key);
240 [[nodiscard]]
bool has_factory(
const std::string& key)
const {
return available_.count(key); }
249 if (!available_.count(key)) {
250 available_.insert(std::make_pair(key,
TypeFactory{std::move(s), std::move(f)}));
261 if (!available_.count(key)) {
262 available_.erase(key);
264 available_.insert(std::make_pair(key,
TypeFactory{std::move(s), std::move(f)}));
281 template <
typename F,
282 std::enable_if_t<(std::is_default_constructible_v<F> &&
283 std::is_convertible_v<std::unique_ptr<F>, T>),
286 add_factory(key, make_prototype<F>().get_confable_schema(), [](
const Conf& c) -> T {
287 auto ptr = std::make_unique<F>();
296 if (available_.empty()) {
298 {
"description",
"no variants available"},
301 j[
"oneOf"] = factory_json_schemas();
303 this->augment_schema(j);
307 bool validate(
const Conf& c, std::optional<SchemaError>& err)
const override {
308 assert(schema_ !=
nullptr);
309 auto factory = c.
get<std::string>(factory_key_);
310 if (!available_.count(factory)) {
311 return this->set_error(err, c,
"unknown factory: {}", factory);
314 return schema_->validate(c, err);
317 [[nodiscard]] Type make(
const Conf& c)
const {
return deserialize(c); }
319 [[nodiscard]] Type deserialize(
const Conf& c)
const {
320 assert(schema_ !=
nullptr);
321 auto factory = c.
get<std::string>(factory_key_);
322 if (!available_.count(factory)) {
323 throw this->error(c,
"unknown factory: {}", factory);
328 if (!args_key_.empty()) {
329 if (c.
has(args_key_)) {
330 args = c.
at(args_key_);
334 args.
erase(factory_key_);
340 return available_.at(factory).func(args);
343 [[nodiscard]]
Json serialize(
const Type& x)
const {
return x; }
345 void serialize_into(Json& j,
const Type& x)
const { j = serialize(x); }
347 void deserialize_into(
const Conf& c, Type& x)
const { x = deserialize(c); }
350 throw std::logic_error(
"FactoryBase::from_conf() should not be used");
355 throw std::logic_error(
"FactoryBase::to_json() should not be used");
363 void reset_schema() {
364 if (available_.size() == 0) {
367 schema_ = std::make_unique<Variant>(factory_schemas());
370 [[nodiscard]] std::vector<Box> factory_schemas()
const {
371 std::vector<Box> out;
372 out.reserve(available_.size());
373 for (
auto& kv : available_) {
375 {factory_key_, make_const_schema(kv.first,
"name of factory").require()},
377 if (args_key_.empty()) {
378 base.set_properties_from(kv.second.schema);
380 base.set_property(args_key_, kv.second.schema.clone());
384 if (transform_func_) {
385 out.emplace_back(transform_func_(std::move(base)));
387 out.emplace_back(std::move(base));
393 [[nodiscard]] std::vector<Json> factory_json_schemas()
const {
394 auto schemas = factory_schemas();
395 std::vector<Json> out;
396 out.reserve(schemas.size());
397 for (
auto& s : schemas) {
398 out.emplace_back(s.json_schema());
404 std::unique_ptr<Variant> schema_;
405 TransformFunc transform_func_;
406 FactoryMap available_;
407 std::string factory_key_{
"factory"};
408 std::string args_key_{
"args"};
409 bool args_subset_{
true};
416 template <
typename T>
435 template <
typename T>
454 Factory(Type* ptr, std::string desc, FactoryMap&& fs)
456 for (
auto&& f : fs) {
457 this->available_.insert(f);
459 this->reset_schema();
462 Factory(Type* ptr, std::string desc, FactoryPairList fs)
464 for (
auto&& f : fs) {
465 this->available_.insert(f);
467 this->reset_schema();
472 assert(ptr_ !=
nullptr);
473 *ptr_ = this->deserialize(c);
477 assert(ptr_ !=
nullptr);
478 j = this->serialize(*ptr_);
bool has(const std::string &key) const
Definition: conf.hpp:166
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:298
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:285
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:294
void from_conf(const Conf &) override
Definition: factory.hpp:349
bool has_factory(const std::string &key) const
Definition: factory.hpp:240
void reset_ptr() override
Definition: factory.hpp:358
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:260
std::vector< std::string > get_factory_keys() const
Definition: factory.hpp:229
CRTP args_key(const std::string &keyword) &&
Definition: factory.hpp:145
void to_json(Json &) const override
Definition: factory.hpp:354
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:307
bool add_factory(const std::string &key, Box &&s, MakeFunc f)
Definition: factory.hpp:248
Definition: factory.hpp:417
Definition: factory.hpp:436
void from_conf(const Conf &c) override
Definition: factory.hpp:471
void to_json(Json &j) const override
Definition: factory.hpp:476
void reset_ptr() override
Definition: factory.hpp:481
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:64