# Structive Property Core 完整指南 [English](CORE_GUIDE.md) ## 1. Include 与 CMake Target ```cpp #include ``` ```cmake target_link_libraries(my_target PRIVATE structive::property_core) ``` Property Core 使用 C++20。 ## 2. 定义 Managed Object ```cpp using namespace structive; struct Device : Property_Object { double temperature{25.0}; double pressure{101.3}; int serial_number{1001}; }; ``` `Property_Object` 增加 managed operation,字段本身仍是普通成员。 ## 3. 定义 Type Descriptor ```cpp template <> struct structive::Type_Descriptor { static auto get() { return object( synchronization(sync_all_independent), field<&Device::temperature>( key<"temperature">, unit<"C">, min_value<-50.0>, max_value<200.0> ), field<&Device::pressure>( key<"pressure">, unit<"kPa"> ), field<&Device::serial_number>( key<"serial_number">, read_only ) ); } }; ``` Descriptor 就是 `Device` 的结构定义。 ## 4. Schema 静态保证 合法 Schema 保证: - 每个 Property 都有非空 key; - key 唯一; - member selector 属于对应 object type; - 同一 Property 上 single-valued Attribute category 不重复; - capability metadata 不会要求底层 Accessor 不支持的操作; - Constraint 与 Property value type 兼容。 ```cpp static_assert(Property_Described_Object); using Schema = type_descriptor_schema_t; static_assert(Valid_Property_Schema); ``` ## 5. 获取 Schema ```cpp const auto& schema = type_descriptor(); const auto& same_schema = device.schema(); ``` 按 index 或 member pointer 获取 Property: ```cpp const auto& first = schema.property<0>(); const auto& temperature = schema.property<&Device::temperature>(); ``` ## 6. Property Descriptor Descriptor 暴露编译期结构事实: ```cpp using Property = std::remove_cvref_t())>; static_assert(Property::readable); static_assert(Property::writable); using Value = Property::value_type; using Accessor = Property::accessor_type; ``` `read_only` 字段: ```cpp using Serial = std::remove_cvref_t())>; static_assert(Serial::readable); static_assert(!Serial::writable); ``` 运行时可直接取得 key: ```cpp auto key_value = schema.property<&Device::temperature>().key(); ``` ## 7. Intrinsic Capability Core capability: ```cpp Property_Capability::none Property_Capability::read Property_Capability::write Property_Capability::read_write ``` 便捷 Attribute: ```cpp read_only write_only read_write inaccessible ``` Capability 属于 Property 自身,不是 authorization rule。 不声明 capability 时,Structive 根据 Accessor 自动推导。 普通非 const member 默认 read/write;getter-only computed property 默认 read-only。 Capability 可以收窄 Accessor,但不能创造 Accessor 本来不存在的操作。 ## 8. Core 不存在访问控制 API Property Core 不提供 domain access mode,也不区分: ```text internal external persistence ``` Consumer 自己决定 policy。例如 GUI 可以只展示部分 Property,即使这些 Property 在结构上都 readable。 Core 只给出 intrinsic `readable` / `writable`。 ## 9. Core Attribute ### 9.1 Key 每个 Property 必须有 key: ```cpp key<"temperature"> ``` Key 是 runtime lookup 与 adapter 使用的结构协议身份。 ### 9.2 Capability ```cpp read_only write_only read_write inaccessible ``` Capability Attribute 是 single-valued、non-inheritable。 ### 9.3 Unit ```cpp unit<"C"> unit<"kPa"> ``` Core 保存单位信息,但不负责换算。 ### 9.4 Sensitive ```cpp sensitive<> sensitive ``` `sensitive` 是可继承 metadata,不实现访问控制。Consumer 可以把它作为自己 policy 的一个输入。 ## 10. 自定义 Attribute 与 Defaults 任何遵守 Attribute protocol 的类型都可以挂在 Property 上。 ```cpp struct Group_Category {}; template struct Group_Attribute { using attribute_category = Group_Category; static constexpr bool single_valued = true; static constexpr bool inheritable = true; static constexpr auto value = Value; }; ``` Inheritable Attribute 可以放进 `defaults(...)`: ```cpp object( defaults(sensitive<>), field<&Device::temperature>(key<"temperature">) ) ``` Capability 故意不可继承,因为每个 Property 的固有操作集合必须独立成立。 ## 11. Constraint 与 Validation 内置 Constraint: ```cpp min_value<0> max_value<100> finite ``` 自定义 Constraint: ```cpp constraint<"even">([](int value) { return value % 2 == 0; }) ``` 显式验证: ```cpp auto result = validate_property_value<&Device::temperature>(device.schema(), candidate); if (result) { auto key_value = result->property_key; auto code = result->code; } ``` `write()` 不自动调用 Validation。 ## 12. Typed Managed Read/Write C++ 业务代码优先 member pointer: ```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); ``` Typed API 由 intrinsic capability 约束。对 `read_only` 调用 write 时,函数在 overload resolution 阶段就不可用。 ```cpp template concept Can_Write_Serial = requires(Object& object) { object.template write<&Device::serial_number>(1); }; static_assert(!Can_Write_Serial); ``` ## 13. Read-Only Fast Path Stored read-only property 在编译期和同步解析阶段都会被裁掉。 ```cpp field<&Device::serial_number>(key<"serial_number">, read_only) ``` 最终: ```text serial_number -> unsynchronized_slot ``` `read<&Device::serial_number>()` 不查询 lock slot,也不构造 `shared_lock`。 即使默认是 `sync_all_shared` 也一样。 如果一个对象只有 stored read-only property,这些 Property 对 `resolved_synchronization().lock_count` 的贡献为 0。 ## 14. Synchronization Plan ### 14.1 Independent ```cpp synchronization(sync_all_independent) ``` 每个真正需要同步的 Property 各自一个 lock domain。 ### 14.2 Shared ```cpp synchronization(sync_all_shared) ``` 所有真正需要同步的 Property 共用一个 lock domain。 Read-only stored property 在 slot materialization 前就被排除。 ### 14.3 Unsynchronized ```cpp synchronization(sync_all_unsynchronized) ``` 即使 writable property 也不执行真实锁。 ### 14.4 单 Property Override ```cpp synchronization( sync_all_independent, sync_unsynchronized<&Device::temperature>() ) ``` 也支持动态 key 规则。 ### 14.5 Group ```cpp synchronization( sync_all_independent, sync_group<&Device::min_speed, &Device::max_speed>("speed_range") ) ``` 同组、且真正需要同步的 Property 解析到同一个 lock slot。 ## 15. 每实例 Synchronization Override 对象可以显式覆盖类型默认策略: ```cpp Device device{ property_synchronization( synchronization(sync_all_shared) ) }; ``` Typed member rule: ```cpp Device device{ property_synchronization( synchronization( sync_all_independent, sync_group<&Device::temperature, &Device::pressure>("environment") ) ) }; ``` 默认 topology 每类型共享。只有显式 override 的实例才保存紧凑 override layout。 ## 16. 查看 Resolved Synchronization ```cpp auto view = device.resolved_synchronization(); auto count = view.lock_count; ``` 成员 slot: ```cpp auto slot = device.lock_slot<&Device::temperature>(); ``` 无锁 Property 使用: ```cpp Resolved_Synchronization_View::unsynchronized_slot ``` Stored read-only property 自动得到这个值。 ## 17. 静态多属性 Guard Read Guard: ```cpp auto guard = device.lock_shared<&Device::temperature, &Device::pressure>(); auto temperature = guard.get<&Device::temperature>(); ``` Write Guard: ```cpp auto guard = device.lock_unique<&Device::min_speed, &Device::max_speed>(); guard.set<&Device::min_speed>(20); guard.set<&Device::max_speed>(120); ``` Static Guard 会对 slot 去重,并使用稳定 slot 顺序获取锁。 Typed unique guard 要求所有目标 Property intrinsically writable。 ## 18. Dynamic-Key Guard ```cpp auto read_guard = device.lock_shared({"temperature", "pressure"}); auto write_guard = device.lock_unique({"temperature", "pressure"}); ``` 未知 key 抛 `std::invalid_argument`。 Dynamic unique guard 如果遇到 read-only property,也会因为 key 只能运行期确定而运行时拒绝。 ## 19. Traversal 只遍历 Schema: ```cpp schema.for_each_property([&](auto index, const auto& descriptor) { }); ``` 遍历 readable value: ```cpp device.for_each_readable([&](auto index, const auto& descriptor, const auto& value) { }); ``` 一次性锁定后遍历: ```cpp device.for_each_readable_locked([&](auto index, const auto& descriptor, const auto& value) { }); ``` Locked traversal 只获取真实存在的同步 slot,read-only stored property 不会引入锁。 获取全部 writable lock domain: ```cpp device.with_all_writable_locked([&](auto& guard) { }); ``` 它不会自动执行 validation 或 rollback。 ## 20. Computed Property Synchronized 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">) ``` 如果 writable dependency 需要同一快照,应共享 computed synchronization domain: ```cpp synchronization( sync_all_independent, sync_group("speed", "min_speed", "max_speed", "speed_span") ) ``` Read-only stored dependency 可以直接通过 computed view 读取,不需要加入 lock slot,因为它没有 managed writer。 ## 21. Trusted Accessor Property Trusted getter: ```cpp trusted_computed_property<&Device::value>(key<"value">) ``` Trusted getter/setter: ```cpp trusted_accessor_property<&Device::get_value, &Device::set_value>(key<"value">) ``` 这类入口直接访问对象,而不是通过 synchronized dependency view。只有调用方明确掌握成员函数同步语义时才应该使用。 ## 22. Runtime Type-Erased Access 动态 Adapter 使用: ```cpp Property_Object_Base& erased = device; ``` 类型信息: ```cpp erased.runtime_object_type(); erased.runtime_property_count(); ``` 读取: ```cpp auto result = erased.runtime_read("temperature", context, callback); ``` 写入: ```cpp auto result = erased.runtime_write("temperature", typeid(double), &value); ``` 结果: ```text ok unknown_property not_readable not_writable type_mismatch ``` Runtime access 没有 external/persistence mode。Adapter 自己拥有 policy,然后决定是否调用 intrinsic runtime read/write。 Stored read-only property 的 runtime read 同样走 no-lock fast path。 ## 23. Lock Policy 默认: ```cpp Property_Object ``` NoLock: ```cpp Property_Object ``` `No_Lock_Policy` 不保存真实 mutex array,并从 managed hot path 去除真实 lock object。 ## 24. Raw Object Access ```cpp Device& raw = device.unsafe_object(); ``` 或直接 public member: ```cpp device.temperature = 30.0; ``` 都绕过 Structive managed contract。 这是刻意设计。Structive 是协作式结构基础设施,不是强制封装。 ## 25. 推荐规则 1. 存储保持普通 C++ member。 2. 只注册真正属于结构模型的字段。 3. C++ 业务代码优先 member-pointer typed API。 4. 当 managed model 永远不应该写某个存储字段时,用 `read_only`。 5. 利用 stored read-only 的 zero-lock 优化。 6. 并发 managed code 中不要通过 raw path 修改 read-only 字段。 7. 跨字段 mutable consistency 使用 synchronization group。 8. Validation 保持显式。 9. Runtime access 只用于真正动态的 Adapter。 10. GUI/RPC/Persistence/Authorization 自己拥有 exposure 与 access policy。