#pragma once #include "util.hpp" #include #include namespace floormat::entities { enum class field_status : unsigned char { enabled, hidden, readonly, }; struct erased_accessor final { using erased_reader_t = void; using erased_writer_t = void; using erased_predicate_t = void; using Object = void; using Value = void; const erased_reader_t* reader; const erased_writer_t* writer; const erased_predicate_t* predicate; StringView field_name, object_type, field_type; void(*read_fun)(const Object*, const erased_reader_t*, Value*); void(*write_fun)(Object*, const erased_writer_t*, Value*); field_status(*predicate_fun)(const Object*, const erased_predicate_t*); constexpr erased_accessor(const erased_accessor&) = default; constexpr erased_accessor(const erased_reader_t* reader, const erased_writer_t* writer, const erased_predicate_t* predicate, StringView field_name, StringView object_name, StringView field_type_name, void(*read_fun)(const Object*, const erased_reader_t*, Value*), void(*write_fun)(Object*, const erased_writer_t*, Value*), field_status(*predicate_fun)(const Object*, const erased_predicate_t*)) : reader{reader}, writer{writer}, predicate{predicate}, field_name{field_name}, object_type{object_name}, field_type{field_type_name}, read_fun{read_fun}, write_fun{write_fun}, predicate_fun{predicate_fun} {} template static constexpr bool check_name_static(); template constexpr bool check_name() const noexcept; template constexpr void assert_name() const noexcept; template void read_unchecked(const Obj& x, FieldType& value) const noexcept; template requires std::is_default_constructible_v FieldType read_unchecked(const Obj& x) const noexcept; template void write_unchecked(Obj& x, move_qualified value) const noexcept; template requires std::is_default_constructible_v FieldType read(const Obj& x) const noexcept; template void read(const Obj& x, FieldType& value) const noexcept; template void write(Obj& x, move_qualified value) const noexcept; template field_status is_enabled(const Obj& x) const noexcept; constexpr bool can_write() const noexcept { return writer != nullptr; } }; template constexpr bool erased_accessor::check_name_static() { return !std::is_pointer_v && !std::is_reference_v && !std::is_pointer_v && !std::is_reference_v; } template constexpr bool erased_accessor::check_name() const noexcept { static_assert(check_name_static()); constexpr auto obj = name_of, field = name_of; return (obj.data() == object_type.data() && field.data() == field_type.data()) || obj == object_type && field == field_type; } template constexpr void erased_accessor::assert_name() const noexcept { fm_assert(check_name()); } template void erased_accessor::read_unchecked(const Obj& x, FieldType& value) const noexcept { static_assert(check_name_static()); read_fun(&x, reader, &value); } template requires std::is_default_constructible_v FieldType erased_accessor::read_unchecked(const Obj& x) const noexcept { static_assert(check_name_static()); FieldType value; read_unchecked(x, value); return value; } template void erased_accessor::write_unchecked(Obj& x, move_qualified value) const noexcept { static_assert(check_name_static()); write_fun(&x, writer, &value); } template requires std::is_default_constructible_v FieldType erased_accessor::read(const Obj& x) const noexcept { assert_name(); return read_unchecked(x); } template void erased_accessor::read(const Obj& x, FieldType& value) const noexcept { assert_name(); read_unchecked(x, value); } template void erased_accessor::write(Obj& x, move_qualified value) const noexcept { assert_name(); write_unchecked(x, value); } template field_status erased_accessor::is_enabled(const Obj& x) const noexcept { static_assert(!std::is_pointer_v && !std::is_reference_v); constexpr auto obj = name_of; fm_assert(obj.data() == object_type.data() || obj == object_type); return predicate_fun(&x, predicate); } } // namespace floormat::entities