mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-08-17 17:31:44 +08:00
Sync copilot instructions and knowledge base
This commit is contained in:
@@ -457,6 +457,7 @@ Registration patterns for structure types with field access capabilities.
|
||||
|
||||
- Use `BEGIN_STRUCT_MEMBER` and `END_STRUCT_MEMBER` for struct registration
|
||||
- Use `STRUCT_MEMBER` to register each accessible field
|
||||
- Use `ATTRIBUTE_TYPE`, `ATTRIBUTE_MEMBER` to attach attributes to the struct or its fields
|
||||
|
||||
[API Explanation](./KB_VlppReflection_StructRegistration.md)
|
||||
|
||||
@@ -481,6 +482,7 @@ Comprehensive registration system for classes and interfaces with methods, prope
|
||||
- Use `CLASS_MEMBER_PROPERTY_EVENT_READONLY_FAST`, `CLASS_MEMBER_PROPERTY_EVENT_FAST` for properties with change events
|
||||
- Use `NO_PARAMETER` for parameterless functions
|
||||
- Use `{ L"arg1" _ L"arg2" ... }` for parameter name lists
|
||||
- Use `ATTRIBUTE_TYPE`, `ATTRIBUTE_MEMBER`, `ATTRIBUTE_PARAMETER` to attach attributes to types, members, and parameters
|
||||
|
||||
[API Explanation](./KB_VlppReflection_ClassInterfaceRegistration.md)
|
||||
|
||||
@@ -500,6 +502,22 @@ Proxy generation for interfaces to enable inheritance in Workflow scripts.
|
||||
|
||||
[API Explanation](./KB_VlppReflection_InterfaceProxy.md)
|
||||
|
||||
#### Attribute Registration
|
||||
|
||||
Attach metadata attributes to types, members, and method parameters during reflection registration.
|
||||
|
||||
Attributes are instances of reflectable structs whose constructor arguments are serializable primitive values.
|
||||
They are stored centrally in the owning type descriptor and can be queried at runtime via the `IAttributeBag` / `IAttributeInfo` interfaces.
|
||||
Attributes survive metaonly metadata serialization and deserialization, and appear in the logged text output.
|
||||
|
||||
- Use `ATTRIBUTE_TYPE(TYPE, ...)` to attach an attribute to the enclosing type descriptor
|
||||
- Use `ATTRIBUTE_MEMBER(TYPE, ...)` to attach an attribute to the most recently registered member (field, property, event, method, or constructor)
|
||||
- Use `ATTRIBUTE_PARAMETER(PARAMETER_NAME, TYPE, ...)` to attach an attribute to a named parameter of the most recently registered method or constructor
|
||||
- Use `IAttributeBag::GetAttributeCount` and `IAttributeBag::GetAttribute` to query attributes at runtime
|
||||
- Use `IAttributeInfo::GetAttributeType`, `IAttributeInfo::GetAttributeValueCount`, `IAttributeInfo::GetAttributeValue` to inspect attribute content
|
||||
|
||||
[API Explanation](./KB_VlppReflection_AttributeRegistration.md)
|
||||
|
||||
### Design Explanation
|
||||
|
||||
## VlppParser2
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
# Attribute Registration
|
||||
|
||||
## Attach metadata attributes to types, members, and method parameters during reflection registration.
|
||||
|
||||
VlppReflection provides three macros for attaching attribute metadata to reflected types and their members.
|
||||
An attribute is an instance of a reflectable struct whose constructor arguments are serializable primitive values (e.g., `WString`, `vint`, `bool`, `float`, `double`).
|
||||
Attributes are stored centrally in the owning type descriptor and can be queried at runtime or through metaonly metadata.
|
||||
|
||||
## Attribute Macros
|
||||
|
||||
### ATTRIBUTE_TYPE(TYPE, ...)
|
||||
|
||||
Attaches an attribute to the enclosing type descriptor.
|
||||
Can appear anywhere inside a `BEGIN_*_MEMBER` / `END_*_MEMBER` block.
|
||||
Zero or more arguments are allowed; `ATTRIBUTE_TYPE(MyAttr)` is equivalent to `MyAttr{}`.
|
||||
|
||||
### ATTRIBUTE_MEMBER(TYPE, ...)
|
||||
|
||||
Attaches an attribute to the most recently registered member (field, property, event, method, or constructor).
|
||||
Must appear after at least one member registration macro (e.g., `CLASS_MEMBER_FIELD`, `CLASS_MEMBER_METHOD`, `CLASS_MEMBER_CONSTRUCTOR`, `CLASS_MEMBER_EVENT`, `CLASS_MEMBER_PROPERTY_*`, `STRUCT_MEMBER`).
|
||||
Multiple `ATTRIBUTE_MEMBER` calls can follow the same member to attach multiple attributes.
|
||||
|
||||
### ATTRIBUTE_PARAMETER(PARAMETER_NAME, TYPE, ...)
|
||||
|
||||
Attaches an attribute to a named parameter of the most recently registered method or constructor.
|
||||
`PARAMETER_NAME` is a wide string literal (e.g., `L"x"`) that must match exactly one parameter name.
|
||||
Must appear after a method or constructor registration macro.
|
||||
|
||||
## Attribute Type Requirements
|
||||
|
||||
- The attribute type must be a reflected struct (`TypeDescriptorFlags::Struct`).
|
||||
- It must be registered via `BEGIN_STRUCT_MEMBER` / `END_STRUCT_MEMBER` before use.
|
||||
- `TYPE{ ARG1, ARG2, ... }` must be a valid C++ aggregate initialization expression.
|
||||
- Each argument is boxed as a `Value` and its type descriptor must have a non-null `GetSerializableType()`.
|
||||
|
||||
## Argument Type Inference
|
||||
|
||||
The attribute macros use a C++20 `BoxingProxy` technique to infer each argument's type from the struct's field type rather than from the C++ deduced literal type.
|
||||
During aggregate initialization of the attribute struct, each argument is wrapped in a `BoxingProxy` whose `operator FieldType()` is called by the compiler with `FieldType` deduced from the corresponding struct field.
|
||||
This means:
|
||||
- An integer literal like `1` written for a `vint` field is boxed as `vint` (= `vint64_t` on x64, `vint32_t` on Win32), not as `int`.
|
||||
- A wide string literal like `L"name"` written for a `WString` field is boxed as `WString`, not as `const wchar_t*`.
|
||||
|
||||
There is no need to explicitly cast arguments to the field type.
|
||||
|
||||
## Storage Architecture
|
||||
|
||||
All attributes are stored centrally in the owning `ITypeDescriptor`'s `AttributeBagSource` base class.
|
||||
- `AttributeBagSource` uses `collections::Group<IMemberInfo*, Ptr<IAttributeInfo>>` where a `nullptr` key represents type-level attributes and non-null keys represent member/parameter-level attributes.
|
||||
- `MemberInfoBase` (the base for all member info implementations) delegates `GetAttributeCount` / `GetAttribute` back to the owner type descriptor's `AttributeBagSource`.
|
||||
- Attributes are returned in registration order.
|
||||
|
||||
## Runtime Query
|
||||
|
||||
Use the `IAttributeBag` interface (inherited by `ITypeDescriptor`, `IMemberInfo`, and `IParameterInfo`) to query attributes:
|
||||
- `GetAttributeCount()` — returns the number of attributes on this target.
|
||||
- `GetAttribute(index)` — returns the `IAttributeInfo` at the given index.
|
||||
|
||||
Use `IAttributeInfo` to inspect an attribute:
|
||||
- `GetAttributeType()` — returns the `ITypeDescriptor` of the attribute struct.
|
||||
- `GetAttributeValueCount()` — returns the number of constructor argument values.
|
||||
- `GetAttributeValue(index)` — returns the boxed `Value` of the argument at the given index.
|
||||
|
||||
## Metaonly Metadata
|
||||
|
||||
Attributes are serialized into metaonly binary metadata by `GenerateMetaonlyTypes` and deserialized by `LoadMetaonlyTypes`.
|
||||
Each attribute value is serialized through `ISerializableType::Serialize` and deserialized through `ISerializableType::Deserialize`.
|
||||
Attributes appear in the logged text output (`.txt` baseline files) in the format:
|
||||
```
|
||||
@Attribute:<AttributeTypeName>(<ArgTypeName>:<SerializedData>, ...)
|
||||
@ParamAttribute:<ParameterName>:<AttributeTypeName>(<ArgTypeName>:<SerializedData>, ...)
|
||||
```
|
||||
|
||||
## Usage Example
|
||||
|
||||
### Define attribute structs
|
||||
```cpp
|
||||
struct MyAttribute
|
||||
{
|
||||
WString name;
|
||||
vint number;
|
||||
auto operator<=>(const MyAttribute&) const = default;
|
||||
};
|
||||
|
||||
struct EmptyAttribute
|
||||
{
|
||||
auto operator<=>(const EmptyAttribute&) const = default;
|
||||
};
|
||||
```
|
||||
|
||||
### Register attribute structs
|
||||
```cpp
|
||||
BEGIN_STRUCT_MEMBER(MyAttribute)
|
||||
STRUCT_MEMBER(name)
|
||||
STRUCT_MEMBER(number)
|
||||
END_STRUCT_MEMBER(MyAttribute)
|
||||
|
||||
BEGIN_STRUCT_MEMBER(EmptyAttribute)
|
||||
END_STRUCT_MEMBER(EmptyAttribute)
|
||||
```
|
||||
|
||||
### Use attribute macros in struct registration
|
||||
```cpp
|
||||
BEGIN_STRUCT_MEMBER(MyStruct)
|
||||
STRUCT_MEMBER(x)
|
||||
ATTRIBUTE_MEMBER(MyAttribute, L"field-x", 42)
|
||||
STRUCT_MEMBER(y)
|
||||
ATTRIBUTE_MEMBER(EmptyAttribute)
|
||||
END_STRUCT_MEMBER(MyStruct)
|
||||
```
|
||||
|
||||
### Use attribute macros in class registration
|
||||
```cpp
|
||||
#define _ ,
|
||||
|
||||
BEGIN_CLASS_MEMBER(MyClass)
|
||||
ATTRIBUTE_TYPE(MyAttribute, L"type", 1)
|
||||
ATTRIBUTE_TYPE(EmptyAttribute)
|
||||
|
||||
CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(vint), {L"seed"})
|
||||
ATTRIBUTE_MEMBER(MyAttribute, L"ctor", 2)
|
||||
ATTRIBUTE_PARAMETER(L"seed", MyAttribute, L"param", 3)
|
||||
|
||||
CLASS_MEMBER_EVENT(Changed)
|
||||
ATTRIBUTE_MEMBER(MyAttribute, L"event", 4)
|
||||
|
||||
CLASS_MEMBER_FIELD(fieldValue)
|
||||
ATTRIBUTE_MEMBER(MyAttribute, L"field", 5)
|
||||
|
||||
CLASS_MEMBER_PROPERTY_FAST(Value)
|
||||
ATTRIBUTE_MEMBER(MyAttribute, L"property", 6)
|
||||
|
||||
CLASS_MEMBER_METHOD(DoWork, {L"x" _ L"y"})
|
||||
ATTRIBUTE_MEMBER(MyAttribute, L"method", 7)
|
||||
ATTRIBUTE_PARAMETER(L"x", MyAttribute, L"param-x", 8)
|
||||
ATTRIBUTE_PARAMETER(L"y", EmptyAttribute)
|
||||
END_CLASS_MEMBER(MyClass)
|
||||
|
||||
#undef _
|
||||
```
|
||||
|
||||
## Compilation Level Support
|
||||
|
||||
- Attribute macros are available when `VCZH_DEBUG_NO_REFLECTION` is **not** defined.
|
||||
- They are excluded when `VCZH_DEBUG_NO_REFLECTION` is defined (no reflection mode).
|
||||
- They work in both full reflection and metaonly reflection (`VCZH_DEBUG_METAONLY_REFLECTION`) builds.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- `ATTRIBUTE_MEMBER` raises `CHECK_ERROR` if no member has been registered yet.
|
||||
- `ATTRIBUTE_PARAMETER` raises `CHECK_ERROR` if the last registered member is not a method or constructor.
|
||||
- `ATTRIBUTE_PARAMETER` raises `CHECK_ERROR` if the named parameter does not exist or is ambiguous.
|
||||
- A `static_assert` fires at compile time if `TYPE{ ARG1, ... }` is not a valid expression.
|
||||
- `CHECK_ERROR` is raised if the attribute type is not a reflected struct or if an argument is not serializable.
|
||||
@@ -92,6 +92,36 @@ END_CLASS_MEMBER(MyClass)
|
||||
#undef _
|
||||
```
|
||||
|
||||
## Attribute Registration
|
||||
|
||||
### Attaching Attributes to Types, Members, and Parameters
|
||||
- Use `ATTRIBUTE_TYPE(TYPE, ...)` to attach an attribute to the type descriptor itself
|
||||
- Use `ATTRIBUTE_MEMBER(TYPE, ...)` after any member registration to attach an attribute to that member
|
||||
- Use `ATTRIBUTE_PARAMETER(PARAMETER_NAME, TYPE, ...)` after a method or constructor registration to attach an attribute to a named parameter
|
||||
- The attribute type must be a reflected struct
|
||||
- Each argument must be a serializable primitive value
|
||||
- Multiple attributes can be attached to the same target
|
||||
- See [Attribute Registration](./KB_VlppReflection_AttributeRegistration.md) for full details
|
||||
|
||||
### Class with Attributes Example
|
||||
```cpp
|
||||
#define _ ,
|
||||
|
||||
BEGIN_CLASS_MEMBER(MyClass)
|
||||
ATTRIBUTE_TYPE(MyAttribute, L"type", 1)
|
||||
|
||||
CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(vint), {L"seed"})
|
||||
ATTRIBUTE_MEMBER(MyAttribute, L"ctor", 2)
|
||||
ATTRIBUTE_PARAMETER(L"seed", MyAttribute, L"param", 3)
|
||||
|
||||
CLASS_MEMBER_METHOD(DoWork, {L"x" _ L"y"})
|
||||
ATTRIBUTE_MEMBER(MyAttribute, L"method", 4)
|
||||
ATTRIBUTE_PARAMETER(L"x", MyAttribute, L"param-x", 5)
|
||||
END_CLASS_MEMBER(MyClass)
|
||||
|
||||
#undef _
|
||||
```
|
||||
|
||||
## Interface Requirements
|
||||
|
||||
### Proxy Requirements
|
||||
|
||||
@@ -23,6 +23,21 @@ END_STRUCT_MEMBER(MyStruct)
|
||||
- Each field registered becomes accessible through the reflection system
|
||||
- Supports both reading and writing field values dynamically
|
||||
|
||||
### Attribute Registration on Structs
|
||||
- Use `ATTRIBUTE_TYPE(TYPE, ...)` to attach an attribute to the struct type itself
|
||||
- Use `ATTRIBUTE_MEMBER(TYPE, ...)` after a `STRUCT_MEMBER` to attach an attribute to that field
|
||||
- Multiple attributes can be attached to the same field
|
||||
- See [Attribute Registration](./KB_VlppReflection_AttributeRegistration.md) for full details
|
||||
|
||||
```cpp
|
||||
BEGIN_STRUCT_MEMBER(MyStruct)
|
||||
STRUCT_MEMBER(FirstField)
|
||||
ATTRIBUTE_MEMBER(MyAttribute, L"first", 1)
|
||||
STRUCT_MEMBER(SecondField)
|
||||
ATTRIBUTE_MEMBER(EmptyAttribute)
|
||||
END_STRUCT_MEMBER(MyStruct)
|
||||
```
|
||||
|
||||
## Registration Requirements
|
||||
|
||||
### Struct Definition
|
||||
|
||||
Reference in New Issue
Block a user