# Structive Property Core 完整指南 [English](CORE_GUIDE.md) ## 1. Include 与 CMake Target 完整 Core 接口: ```cpp #include ``` CMake: ```cmake target_link_libraries(my_target PRIVATE structive::property_core) ``` Core 是 header-only,要求 C++20。 ## 2. 定义 Managed Object 通常让业务对象继承 `Property_Object`: ```cpp using namespace structive; struct Device : Property_Object { double temperature{25.0}; double pressure{101.3}; double min_speed{10.0}; double max_speed{100.0}; std::string name{"device-1"}; }; ``` 这些成员仍然都是普通 C++ 成员。 ## 3. 定义 Type Descriptor 特化 `Type_Descriptor`,通过 `object(...)` 返回 `Object_Schema`: ```cpp template <> struct structive::Type_Descriptor { static auto get() { return object( defaults( external_access, persistence_access ), synchronization( sync_all_independent, sync_group<&Device::min_speed, &Device::max_speed>("speed_range") ), field<&Device::temperature>( key<"temperature">, unit<"C">, min_value<-50.0>, max_value<200.0> ), field<&Device::pressure>(key<"pressure">, unit<"kPa">), field<&Device::min_speed>(key<"min_speed">), field<&Device::max_speed>(key<"max_speed">), field<&Device::name>(key<"name">) ); } }; ``` `field(...)` 是 `property(...)` 的别名,产生 member-backed `Property_Descriptor`。 ## 4. Schema 提供的静态保证 Schema 会检查: - 每个 property 都必须拥有非空 `key`; - 同一 Schema 内 key 唯一; - 同一个成员存储不能重复注册; - single-valued Attribute category 不能在同一声明中重复; - constraint 必须能作用于 property value type; - `defaults(...)` 只能放 inheritable Attribute; - External/Persistence capability 不能声明 accessor 实际不支持的读写能力。 因此大量结构错误会直接成为编译期错误。 ## 5. 获取 Schema 类型级: ```cpp const auto& schema = type_descriptor(); ``` 实例级: ```cpp Device device; const auto& schema = device.schema(); ``` 可以通过编译期 index 或成员指针定位 property: ```cpp const auto& first = schema.property<0>(); const auto& temperature = schema.property<&Device::temperature>(); ``` 业务 typed code 优先成员指针;index 主要用于泛型遍历。 ## 6. Property Descriptor 获取 key: ```cpp auto key_value = temperature.key(); ``` 静态能力: ```cpp using Property = std::remove_cvref_t; static_assert(Property::readable); static_assert(Property::writable); ``` 按 category 查询 Attribute: ```cpp static_assert(Property::has_attribute); const auto& attribute = temperature.attribute(); ``` 遍历全部声明 Attribute: ```cpp temperature.for_each_attribute([](const auto& attribute) { // 根据 attribute 类型处理 }); ``` 单独遍历 constraint: ```cpp temperature.for_each_constraint([](const auto& constraint_value) { // 检查 constraint }); ``` ## 7. Object Defaults 与 Effective Attribute `defaults(...)` 给 inheritable Attribute 提供对象级默认值: ```cpp defaults( external_access, persistence_access, sensitive ) ``` Property 可以覆盖: ```cpp field<&Device::name>( key<"name">, external_access ) ``` Core 提供 `effective_external_access_v`、`external_readable_v`、`external_writable_v`、`persistence_loadable_v`、`persistence_storable_v`、`effective_sensitive_v` 等有效属性计算入口。 Extension 自己的 inheritable category 可以通过 `declared_effective_attribute(schema)` 读取 property 声明或 object default 中的有效值。 ## 8. Core Attribute ### 8.1 Key ```cpp key<"temperature"> ``` 每个 property 必须存在,不能为空,同一 Schema 内唯一。 ### 8.2 External Access ```cpp external_access external_access external_access external_access ``` 支持在 `defaults(...)` 中继承。 ### 8.3 Persistence Access ```cpp persistence_access persistence_access persistence_access persistence_access ``` 同样支持继承。 ### 8.4 Unit ```cpp unit<"C"> ``` 描述元数据,不支持 object default 继承。 ### 8.5 Sensitive ```cpp sensitive<> sensitive ``` 支持继承。Core 会计算 effective value,但不会自动执行脱敏或隐藏输出。 ## 9. Constraint 与 Validation 内置 constraint: ```cpp min_value<0> max_value<100> finite ``` 自定义 constraint: ```cpp constraint<"even">([](int value) { return value % 2 == 0; }) ``` 按成员指针验证: ```cpp auto error = validate_property_value<&Device::temperature>(device.schema(), candidate); ``` 按编译期 key 验证: ```cpp auto error = validate_property_key_value<"temperature">(device.schema(), candidate); ``` 失败结果: ```cpp struct Validation_Error { std::string_view property_key; std::string_view code; }; ``` Validation 是显式操作,不会在 managed write 中自动执行。 ## 10. Internal Managed Read/Write 成员指针形式: ```cpp auto temperature = device.read<&Device::temperature>(); device.write<&Device::temperature>(30.0); ``` 编译期 key 形式: ```cpp auto temperature = device.read_key<"temperature">(); device.write_key<"temperature">(30.0); ``` 这些操作属于 `Managed_Access_Mode::internal`。 `read()` 返回值对象而不是底层存储引用。启用同步时,读取发生在配置的 shared lock 持有期间。 ## 11. External Capability View 可以通过 object defaults 默认开放 external access: ```cpp defaults(external_access) ``` 使用: ```cpp device.external().write<&Device::temperature>(30.0); auto value = device.external().read<&Device::temperature>(); ``` Const object 返回 const capability view,因此没有 write API。 Typed API 对静态不可访问操作直接在编译期拒绝。 ## 12. Persistence Capability View Persistence 使用 load/store 语义: ```cpp device.persistence().load<&Device::temperature>(30.0); auto value = device.persistence().store<&Device::temperature>(); ``` 编译期 key 版本: ```cpp device.persistence().load_key<"temperature">(30.0); auto value = device.persistence().store_key<"temperature">(); ``` 能力由 `Persistence_Access` 元数据决定。 ## 13. Synchronization Plan ### 13.1 Independent 默认 `Synchronization_Plan` 就是 independent:每个同步 property 拥有独立逻辑锁域。 显式写法: ```cpp synchronization(sync_all_independent) ``` ### 13.2 Shared ```cpp synchronization(sync_all_shared) ``` 除显式 override 外,全部 property 共用一个 lock slot。 ### 13.3 Unsynchronized ```cpp synchronization(sync_all_unsynchronized) ``` property 使用 `unsynchronized_slot`,Structive 不提供真实 mutex 保护。 ### 13.4 单 Property Override 成员指针形式: ```cpp sync_independent<&Device::temperature>() sync_unsynchronized<&Device::immutable_id>() ``` 运行时字符串形式: ```cpp sync_independent("temperature") sync_unsynchronized("immutable_id") ``` 静态已知 property 优先成员指针形式。 ### 13.5 Group 成员指针形式: ```cpp sync_group<&Device::min_speed, &Device::max_speed>("speed_range") ``` 字符串形式: ```cpp sync_group("speed_range", "min_speed", "max_speed") ``` 同一 group 的 property 共用 lock slot。 Resolver 会拒绝未知 key、重复 group name、空 group,以及同一 property 被重复显式配置。 ## 14. 每实例覆盖同步策略 Type Descriptor 提供默认同步计划,但单个实例可以通过 `Property_Synchronization` 覆盖: ```cpp struct Device : Property_Object { Device() = default; explicit Device(Property_Synchronization synchronization) : Property_Object(std::move(synchronization)) {} }; Device shared_device{ property_synchronization(synchronization(sync_all_shared)) }; ``` 如果使用成员指针同步规则,可以显式提供对象类型完成 Schema materialization: ```cpp auto policy = property_synchronization( synchronization( sync_all_independent, sync_group<&Device::temperature, &Device::pressure>("environment") ) ); ``` Schema 本身不变,只改变该实例的 lock topology。 ## 15. 查看解析后的同步拓扑 单字段: ```cpp auto slot = device.lock_slot<&Device::temperature>(); ``` 完整 view: ```cpp auto resolved = device.resolved_synchronization(); auto count = resolved.lock_count; auto slot = resolved.slot(0); auto uses_lock = resolved.uses_lock(0); ``` `Resolved_Synchronization_View::unsynchronized_slot` 表示无同步 property。 ## 16. 静态多属性 Guard Shared guard: ```cpp auto guard = device.lock_shared<&Device::temperature, &Device::pressure>(); auto temperature = guard.get<&Device::temperature>(); auto pressure = guard.get<&Device::pressure>(); ``` Unique guard: ```cpp auto guard = device.lock_unique<&Device::min_speed, &Device::max_speed>(); auto old_min = guard.get<&Device::min_speed>(); guard.set<&Device::min_speed>(20.0); guard.set<&Device::max_speed>(120.0); ``` Guard 只允许访问自己持有同步集合中的 property。 Capability view 也提供受其 access mode 限制的静态 guard: ```cpp auto guard = device.external().lock_shared<&Device::temperature>(); ``` ## 17. 动态 Key Guard 运行时才知道属性集合时: ```cpp std::array keys{"temperature", "pressure"}; auto guard = device.lock_shared(keys); ``` 或者: ```cpp auto guard = device.lock_unique({"min_speed", "max_speed"}); ``` 动态 guard 会在运行时检查 key 和 capability。获取锁前会对 lock slot 排序、去重。 Guard 获取以后仍然可以通过编译期成员或 key 读写,但访问未包含在 held set 中的 property 会抛出 `std::logic_error`。 ## 18. Traversal Schema 遍历: ```cpp schema.for_each_property([](auto index, const auto& property) { // compile-time index + descriptor }); ``` Managed value 遍历: ```cpp device.for_each_readable([](auto index, const auto& descriptor, const auto& value) { // 每个 property 单独 managed read }); ``` Locked traversal 会先获取完整 readable 同步集合: ```cpp device.external().for_each_readable_locked([](auto index, const auto& descriptor, const auto& value) { // 全部选中 property 在 guard 下访问 }); ``` 集中 writable 操作: ```cpp device.with_all_writable_locked([](auto& guard) { // guard.get / guard.set }); ``` Persistence view 对应提供 `with_all_loadable_locked(...)`。 ## 19. Computed Property 同步 computed property 接收 read view: ```cpp computed_property([](const auto& view) { return view.template get<&Device::max_speed>() - view.template get<&Device::min_speed>(); }, key<"speed_span">, external_access) ``` Computed property 自身与通过 view 读取的每个 dependency 必须解析到同一个 lock slot。 例如: ```cpp synchronization( sync_all_independent, sync_group("speed", "min_speed", "max_speed", "speed_span") ) ``` Computed property 是只读属性。 ## 20. Trusted Accessor Property Core 还支持基于成员函数的 trusted access: ```cpp trusted_computed_property<&Device::get_temperature>(key<"temperature">) ``` 以及 getter/setter: ```cpp trusted_accessor_property<&Device::get_temperature, &Device::set_temperature>(key<"temperature">) ``` 它们直接调用对象成员函数,并标记为 trusted object access,不受 synchronized computed view 的 dependency slot 检查。只有当成员函数本身拥有明确同步/一致性契约时才应该使用。 ## 21. Runtime Type-Erased Access 任何 `Property_Object` 同时也是 `Property_Object_Base`: ```cpp Property_Object_Base& erased = device; ``` Runtime introspection: ```cpp erased.runtime_object_type(); erased.runtime_property_count(); ``` Runtime write: ```cpp double value = 35.0; auto result = erased.runtime_write( Managed_Access_Mode::external, "temperature", typeid(double), &value ); ``` Runtime read 通过 callback 返回值: ```cpp static void read_double(void* context, std::size_t, std::string_view, const std::type_info& type, const void* value) { if (type == typeid(double)) { *static_cast(context) = *static_cast(value); } } double output = 0.0; auto result = erased.runtime_read( Managed_Access_Mode::external, "temperature", &output, &read_double ); ``` 结果枚举: ```cpp Runtime_Access_Result::ok Runtime_Access_Result::unknown_property Runtime_Access_Result::not_readable Runtime_Access_Result::not_writable Runtime_Access_Result::type_mismatch ``` Runtime path 与 typed managed access 使用同一套 capability 和 synchronization 规则。 ## 22. Lock Policy 默认: ```cpp struct Device : Property_Object { }; ``` 等价简写: ```cpp struct Device : Property_Object { }; ``` 也提供 no-op lock policy: ```cpp struct Device : Property_Object { }; ``` `No_Lock_Policy` 使用 `Null_Shared_Mutex`,它取消真实互斥;只有外部所有权规则能够保证正确性时才应该使用。 ## 23. Raw Object Access `unsafe_object()` 可以拿到底层 derived object: ```cpp Device& raw = device.unsafe_object(); ``` 普通成员访问当然也仍然存在: ```cpp device.temperature = 40.0; ``` 这些入口故意绕过 Structive managed access。适合调用方已经持有正确同步、或者明确在 Structive 管理契约之外操作的情况。 ## 24. 推荐使用规则 - Typed 业务访问优先 member pointer。 - Runtime integration boundary 使用 string key。 - Key 按协议标识对待。 - 稳定的对象级 capability 放 `defaults(...)`,特殊字段单独 override。 - 需要一致观察的字段放同一个 synchronization group。 - Validation 在业务操作边界显式执行。 - 跨字段 invariant 使用静态 multi-property guard。 - 默认优先 synchronized computed property。 - Runtime access 用于 adapter,不要把普通 typed code 动态化。 - Raw access 只在调用方明确拥有被绕过的管理保证时使用。