Files
Structive/core/include/structive/property/descriptor.hpp
T
2026-08-07 17:50:04 +08:00

118 lines
5.8 KiB
C++

#pragma once
#include "accessor.hpp"
#include "attributes.hpp"
#include "meta.hpp"
#include <cstddef>
#include <tuple>
#include <string_view>
#include <type_traits>
#include <utility>
namespace structive {
template <class Value, class... Attributes>
consteval bool constraints_compatible() {
return (([] {
if constexpr (Property_Constraint<Attributes>) {
return Property_Constraint_For<Attributes, Value>;
}
return true;
}()) && ...);
}
template <Property_Accessor Accessor, class... Attributes>
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 attribute_types = Type_List<Attributes...>;
using capability_type = find_attribute_in_list_t<Capability_Category, attribute_types>;
static constexpr Property_Capability intrinsic_capability = [] {
if constexpr (!std::same_as<capability_type, void>) {
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_assert(unique_single_value_categories<Attributes...>());
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<Key_Category, attribute_types>;
static_assert(!std::same_as<key_type, void>);
static_assert(key_type::value.view().size() > 0);
static_assert(constraints_compatible<value_type, Attributes...>());
[[no_unique_address]] Accessor accessor{};
std::tuple<Attributes...> attributes;
template <class Category>
using attribute_type = find_attribute_in_list_t<Category, attribute_types>;
template <class Category>
static constexpr bool has_attribute = !std::same_as<attribute_type<Category>, void>;
template <class Category>
constexpr decltype(auto) attribute() const requires has_attribute<Category> {
using target = attribute_type<Category>;
return std::get<target>(attributes);
}
constexpr std::string_view key() const noexcept {
return key_type::value.view();
}
template <class Function>
constexpr void for_each_attribute(Function&& function) const {
std::apply([&](const auto&... values) {
(function(values), ...);
}, attributes);
}
template <class Function>
constexpr void for_each_constraint(Function&& function) const {
std::apply([&](const auto&... values) {
([&] {
using type = std::remove_cvref_t<decltype(values)>;
if constexpr (Property_Constraint<type>) {
function(values);
}
}(), ...);
}, attributes);
}
};
template <class Type>
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 <auto Member, class... Attributes>
constexpr auto property(Attributes&&... attributes) {
using accessor = Member_Accessor<Member>;
return Property_Descriptor<accessor, std::decay_t<Attributes>...>{{}, {std::forward<Attributes>(attributes)...}};
}
template <auto Member, class... Attributes>
constexpr auto field(Attributes&&... attributes) {
return property<Member>(std::forward<Attributes>(attributes)...);
}
template <class Object, class Value, class Function, class... Attributes>
constexpr auto computed_property(Function&& function, Attributes&&... attributes) {
using accessor = Synchronized_Computed_Accessor<Object, Value, std::decay_t<Function>>;
return Property_Descriptor<accessor, std::decay_t<Attributes>...>{accessor{std::forward<Function>(function)}, {std::forward<Attributes>(attributes)...}};
}
template <auto Getter, class... Attributes> requires Trusted_Getter_Function<Getter>
constexpr auto trusted_computed_property(Attributes&&... attributes) {
using accessor = Trusted_Computed_Accessor<Getter>;
return Property_Descriptor<accessor, std::decay_t<Attributes>...>{{}, {std::forward<Attributes>(attributes)...}};
}
template <auto Getter, auto Setter, class... Attributes> requires Trusted_Getter_Function<Getter> && Trusted_Setter_Function_For<Setter, trusted_getter_object_t<Getter>, trusted_getter_value_t<Getter>>
constexpr auto trusted_accessor_property(Attributes&&... attributes) {
using accessor = Trusted_Getter_Setter_Accessor<Getter, Setter>;
return Property_Descriptor<accessor, std::decay_t<Attributes>...>{{}, {std::forward<Attributes>(attributes)...}};
}
}