#pragma once #include "accessor.hpp" #include "attributes.hpp" #include "meta.hpp" #include #include #include #include #include namespace structive { template consteval bool constraints_compatible() { return (([] { if constexpr (Property_Constraint) { return Property_Constraint_For; } return true; }()) && ...); } template struct Property_Descriptor { using property_descriptor_tag = void; using accessor_type = Accessor; using object_type = typename Accessor::object_type; using value_type = typename Accessor::value_type; using storage_identity = typename Accessor::storage_identity; using dependency_spec = typename Accessor::dependency_spec; using metadata_types = Type_List; using capability_type = find_attribute_in_list_t; static constexpr Property_Capability intrinsic_capability = [] { if constexpr (!std::same_as) { return capability_type::value; } else if constexpr (Accessor::readable && Accessor::writable) { return Property_Capability::read_write; } else if constexpr (Accessor::readable) { return Property_Capability::read; } else if constexpr (Accessor::writable) { return Property_Capability::write; } else { return Property_Capability::none; } }(); static constexpr bool readable = Accessor::readable && (intrinsic_capability == Property_Capability::read || intrinsic_capability == Property_Capability::read_write); static constexpr bool writable = Accessor::writable && (intrinsic_capability == Property_Capability::write || intrinsic_capability == Property_Capability::read_write); static constexpr bool synchronized_view_read = Accessor::synchronized_view_read; static constexpr bool trusted_object_access = Accessor::trusted_object_access; static constexpr std::size_t dependency_count = dependency_spec::count; static constexpr bool runtime_copy_writable = writable && requires(const Accessor& accessor, object_type& object, const value_type& candidate) { accessor.write(object, candidate); }; static_assert((Property_Metadata && ...), "property metadata must be an Attribute or Constraint"); static_assert(unique_single_value_categories()); static_assert(!((intrinsic_capability == Property_Capability::read || intrinsic_capability == Property_Capability::read_write) && !Accessor::readable), "property capability requests read from a non-readable accessor"); static_assert(!((intrinsic_capability == Property_Capability::write || intrinsic_capability == Property_Capability::read_write) && !Accessor::writable), "property capability requests write from a non-writable accessor"); using key_type = find_attribute_in_list_t; static_assert(!std::same_as); static_assert(key_type::value.view().size() > 0); static_assert(constraints_compatible()); [[no_unique_address]] Accessor accessor{}; std::tuple metadata; template using attribute_type = find_attribute_in_list_t; template static constexpr std::size_t attribute_count = count_attribute_category(); template static constexpr bool has_attribute = attribute_count != 0; template constexpr decltype(auto) attribute() const requires (attribute_count == 1) { using target = attribute_type; return std::get(metadata); } constexpr std::string_view key() const noexcept { return key_type::value.view(); } template constexpr void for_each_metadata(Function&& function) const { std::apply([&](const auto&... values) { (function(values), ...); }, metadata); } template constexpr void for_each_attribute(Function&& function) const { std::apply([&](const auto&... values) { ([&] { using type = std::remove_cvref_t; if constexpr (Property_Attribute) { function(values); } }(), ...); }, metadata); } template constexpr void for_each_attribute(Function&& function) const { std::apply([&](const auto&... values) { ([&] { using type = std::remove_cvref_t; if constexpr (Property_Attribute && std::same_as, Category>) { function(values); } }(), ...); }, metadata); } template constexpr void for_each_constraint(Function&& function) const { std::apply([&](const auto&... values) { ([&] { using type = std::remove_cvref_t; if constexpr (Property_Constraint) { function(values); } }(), ...); }, metadata); } }; template concept Property_Descriptor_Type = requires { typename Type::property_descriptor_tag; typename Type::object_type; typename Type::value_type; typename Type::accessor_type; typename Type::storage_identity; }; template constexpr auto property(Metadata&&... metadata) { using accessor = Member_Accessor; return Property_Descriptor...>{{}, {std::forward(metadata)...}}; } template constexpr auto field(Metadata&&... metadata) { return property(std::forward(metadata)...); } template constexpr auto computed_property(Dependencies, Function&& function, Metadata&&... metadata) { using accessor = Synchronized_Computed_Accessor, Dependencies>; return Property_Descriptor...>{accessor{std::forward(function)}, {std::forward(metadata)...}}; } template requires Trusted_Getter_Function constexpr auto trusted_computed_property(Metadata&&... metadata) { using accessor = Trusted_Computed_Accessor; return Property_Descriptor...>{{}, {std::forward(metadata)...}}; } template requires Trusted_Getter_Function && Trusted_Setter_Function_For, trusted_getter_value_t> constexpr auto trusted_accessor_property(Metadata&&... metadata) { using accessor = Trusted_Getter_Setter_Accessor; return Property_Descriptor...>{{}, {std::forward(metadata)...}}; } }