Files
Structive/docs/EXTENSIONS.md
T
2026-08-07 17:50:04 +08:00

273 lines
6.6 KiB
Markdown

# Structive Extension Architecture
[中文](EXTENSIONS.zh-CN.md)
## 1. Extension role
Extensions add domain metadata and domain interpretation without making Property Core depend on that domain.
The dependency direction is:
```text
Extension → Property Core
Property Core -X→ Extension
```
Core supplies:
- schema and property descriptors;
- intrinsic readable/writable capability;
- the Attribute protocol;
- constraints;
- synchronization metadata and managed access;
- runtime structural access.
Extensions add their own categories and interpretation.
## 2. Extension principle
An extension should own only its domain semantics.
For example, Presentation owns:
```text
label
description
group
order
```
It does not need Property Core to understand presentation.
Likewise, a future persistence extension may own persistence-specific metadata, and an RPC extension may own protocol metadata.
## 3. External policy stays external
Property Core has no built-in access-control mode.
An extension or application layer is responsible for its own policy:
```text
Should this property be visible?
Should this endpoint permit a write?
Should this property be persisted?
Does the current user have permission?
```
An extension may inspect structural facts such as:
```text
Property::readable
Property::writable
sensitive metadata
extension-owned metadata
```
but the final policy belongs to the consumer.
A `read_only` property means the Structive managed object itself has no write operation for that property. It does not mean every external system must expose it.
## 4. Current presentation extension
Include:
```cpp
#include <structive/property/extensions/presentation.hpp>
```
Link:
```cmake
target_link_libraries(my_target PRIVATE structive::property_extensions)
```
Available Attributes:
```cpp
presentation::label<"Temperature">
presentation::description<"Current device temperature">
presentation::group<"Environment">
presentation::order<2>
```
Example:
```cpp
field<&Device::temperature>(
key<"temperature">,
unit<"C">,
presentation::label<"Temperature">,
presentation::description<"Current device temperature">,
presentation::group<"Environment">,
presentation::order<2>
)
```
## 5. Presentation interpretation
```cpp
auto info = presentation::describe<&Device::temperature>(device.schema());
```
`Presentation_Info` contains:
```text
key
label
description
group
order
has_order
```
If no label is supplied, the presentation extension falls back to the property key. That fallback is presentation behavior, not Core behavior.
## 6. Inheritable extension Attributes
An extension category may choose to be inheritable.
```cpp
defaults(
presentation::group<"Environment">
)
```
Property-level metadata overrides an inheritable single-valued default from the same category.
Use inheritance only for metadata whose semantics genuinely support inheritance.
## 7. Designing a new extension Attribute
A simple extension Attribute can be defined as:
```cpp
namespace my_extension {
struct Format_Category {};
template <Fixed_String Value>
struct Format_Attribute {
using attribute_category = Format_Category;
static constexpr bool single_valued = true;
static constexpr bool inheritable = false;
static constexpr auto value = Value;
};
template <Fixed_String Value>
inline constexpr Format_Attribute<Value> format{};
}
```
Then attach it normally:
```cpp
field<&Device::temperature>(
key<"temperature">,
my_extension::format<"0.0 C">
)
```
Core does not require modification.
## 8. Reading extension Attributes
Descriptor-local metadata:
```cpp
using Property = std::remove_cvref_t<decltype(schema.property<&Device::temperature>())>;
static_assert(Property::template has_attribute<my_extension::Format_Category>);
```
Effective inheritable metadata can use Core's generic effective-Attribute utilities.
The extension owns fallback and interpretation rules.
## 9. Multi-valued metadata
If a category is not single-valued, an extension may allow multiple Attributes from that category.
Do not mark a category `single_valued` unless duplicate declarations are structurally invalid.
## 10. Recommended extension boundaries
Good extension domains include:
- presentation and editor hints;
- serialization naming and format hints;
- persistence mapping metadata;
- RPC/protocol naming metadata;
- diagnostics and telemetry metadata;
- documentation metadata.
The domain implementation should remain outside Property Core.
## 11. Using intrinsic capability
A consumer may use intrinsic capability as a structural fact.
For example, an editor can decide that a property is only eligible for an editable widget when:
```cpp
Property::writable
```
That is only eligibility. The editor may still apply additional application policy.
A persistence adapter may choose not to store a property even when `Property::readable` is true.
An RPC endpoint may choose not to expose a writable property at all.
This separation is intentional.
## 12. Read-only optimization is a Core fact
Extensions do not need to implement special locking for `read_only` stored properties.
Core guarantees that such properties do not contribute lock slots or mutexes to the managed object and managed reads use the no-lock path.
An extension that deliberately performs raw C++ writes bypasses that guarantee and owns synchronization itself.
## 13. Fallback behavior belongs to the consumer
Core should not decide domain fallbacks such as:
```text
missing label -> key
missing database column -> key
missing RPC name -> key
```
Those rules belong to the corresponding extension or adapter.
## 14. Avoid semantic leakage into Core
Do not add a Core enum or special branch only because one extension needs it.
Prefer:
```text
extension-owned Attribute category
+ extension-owned interpretation
```
over:
```text
Core learns the extension domain
```
## 15. Linked code versus header-only metadata
Metadata types can usually remain header-only. Linked extension code is appropriate when a domain needs non-template runtime behavior.
The current presentation extension keeps metadata in headers and provides `make_presentation_info` in the linked target.
## 16. Extension review checklist
Before adding an extension feature, ask:
1. Does Core already provide the required generic structural mechanism?
2. Can the feature be expressed as an extension-owned Attribute?
3. Is its fallback rule owned by the extension?
4. Is access/exposure policy being kept outside Core?
5. Is intrinsic `readable/writable` being treated as structure rather than authorization?
6. Does the extension avoid raw writes that would bypass managed synchronization unless intentional?
7. Does Core remain independent of the extension?