diff --git a/.gitignore b/.gitignore index cc8d7833..4b3e9a5a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ TODO.md .ag_template/ build/ .ag_repo/ -.og_repo/ \ No newline at end of file +.oag_repo/ +.claude diff --git a/.spi.yml b/.spi.yml index 5793db38..11024e65 100644 --- a/.spi.yml +++ b/.spi.yml @@ -1,5 +1,4 @@ version: 1 builder: configs: - - swift_version: 6.0 - documentation_targets: [OpenAttributeGraph] + - documentation_targets: [OpenAttributeGraph] diff --git a/README.md b/README.md index a49e0184..e1abf2b9 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,9 @@ [![codecov](https://codecov.io/gh/OpenSwiftUIProject/OpenAttributeGraph/graph/badge.svg?token=W1KDSUMWJW)](https://codecov.io/gh/OpenSwiftUIProject/OpenAttributeGraph) -OpenAttributeGraph is an open source implementation of Apple's Private framework - AttributeGraph +OpenAttributeGraph is an open source implementation of Apple's Private framework - AttributeGraph which is a high performance computing engine written in C++ and Swift. -AttributeGraph is a high performance computing engine written in C++ and Swift. - -And it powers the underlying computing and diffing of SwiftUI. +And it powers the underlying computing and diffing of [OpenSwiftUI](https://github.com/OpenSwiftUIProject/OpenSwiftUI). | **CI Status** | |---| @@ -25,6 +23,8 @@ The project is for the following purposes: Currently, this project is in early development. +Please refer to the [documentation](https://swiftpackageindex.com/OpenSwiftUIProject/OpenAttributeGraph/main/documentation/openattributegraph) for more information on it. + ## Usage ### Via Swift Package Manager diff --git a/Sources/OpenAttributeGraph/Attribute/Attribute/Attribute.swift b/Sources/OpenAttributeGraph/Attribute/Attribute/Attribute.swift index b097ffc3..716eb10b 100644 --- a/Sources/OpenAttributeGraph/Attribute/Attribute/Attribute.swift +++ b/Sources/OpenAttributeGraph/Attribute/Attribute/Attribute.swift @@ -1,5 +1,60 @@ public import OpenAttributeGraphCxx +/// A reactive property wrapper that automatically tracks dependencies and manages value updates. +/// +/// `Attribute` is the core building block of the OpenAttributeGraph reactive system. When you wrap a +/// property with `@Attribute`, it becomes reactive and can automatically track dependencies and +/// propagate changes. +/// +/// @Attribute var count: Int = 0 +/// @Attribute var doubledCount: Int = count * 2 +/// +/// count = 5 // doubledCount automatically becomes 10 +/// +/// ## Key Features +/// +/// - Automatic dependency tracking: Attributes automatically discover their dependencies +/// - Efficient updates: Only affected attributes are recomputed when changes occur +/// - Type safety: Full Swift type safety with compile-time checking +/// - Dynamic member lookup: Access nested properties as reactive attributes +/// - Property wrapper syntax: Clean, declarative syntax using `@Attribute` +/// +/// ## Property Wrapper Usage +/// +/// Use `@Attribute` to make any Swift value reactive: +/// +/// struct CounterView { +/// @Attribute var count: Int = 0 +/// +/// var body: some View { +/// Button("Count: \(count)") { +/// count += 1 +/// } +/// } +/// } +/// +/// ## Dynamic Member Lookup +/// +/// Access nested properties as separate attributes: +/// +/// @Attribute var person: Person = Person(name: "Alice", age: 30) +/// let nameAttribute: Attribute = person.name +/// let ageAttribute: Attribute = person.age +/// +/// ## Integration with Rules +/// +/// Create computed attributes using ``Rule`` or ``StatefulRule``: +/// +/// struct DoubledRule: Rule { +/// typealias Value = Int +/// let source: Attribute +/// +/// func value() -> Int { +/// source.wrappedValue * 2 +/// } +/// } +/// +/// let doubled = Attribute(DoubledRule(source: count)) @frozen @propertyWrapper @dynamicMemberLookup @@ -8,14 +63,23 @@ public struct Attribute { // MARK: - Initializer + /// Creates an attribute from a type-erased identifier. + /// + /// - Parameter identifier: The type-erased attribute identifier public init(identifier: AnyAttribute) { self.identifier = identifier } + /// Creates an attribute by copying another attribute. + /// + /// - Parameter attribute: The attribute to copy public init(_ attribute: Attribute) { self = attribute } + /// Creates an attribute with an initial value. + /// + /// - Parameter value: The initial value for the attribute public init(value: Value) { self = withUnsafePointer(to: value) { valuePointer in withUnsafePointer(to: External()) { bodyPointer in @@ -61,6 +125,7 @@ public struct Attribute { // MARK: - propertyWrapper + /// The current value of the attribute. public var wrappedValue: Value { unsafeAddress { OAGGraphGetValue(identifier, type: Value.self) @@ -70,6 +135,7 @@ public struct Attribute { nonmutating set { _ = setValue(newValue) } } + /// The attribute itself when accessed with the `$` prefix. public var projectedValue: Attribute { get { self } set { self = newValue } diff --git a/Sources/OpenAttributeGraph/Attribute/Optional/OptionalAttribute.swift b/Sources/OpenAttributeGraph/Attribute/Optional/OptionalAttribute.swift index 9722b8ca..104bc653 100644 --- a/Sources/OpenAttributeGraph/Attribute/Optional/OptionalAttribute.swift +++ b/Sources/OpenAttributeGraph/Attribute/Optional/OptionalAttribute.swift @@ -5,6 +5,7 @@ // Audited for RELEASE_2021 // Status: Complete +/// An optional attribute wrapper that may or may not contain a value. @frozen @propertyWrapper @dynamicMemberLookup diff --git a/Sources/OpenAttributeGraph/Attribute/Rule/Focus.swift b/Sources/OpenAttributeGraph/Attribute/Rule/Focus.swift index dd23ab5a..47a7c69a 100644 --- a/Sources/OpenAttributeGraph/Attribute/Rule/Focus.swift +++ b/Sources/OpenAttributeGraph/Attribute/Rule/Focus.swift @@ -5,6 +5,35 @@ // Audited for RELEASE_2021 // Status: Complete +/// A rule that focuses on a specific property of another attribute using KeyPath. +/// +/// `Focus` provides a way to create attributes that automatically track a specific property of another attribute. It uses Swift's KeyPath system to create a focused view of part of a larger data structure. +/// +/// struct Person { +/// let name: String +/// let age: Int +/// } +/// +/// @Attribute var person = Person(name: "Alice", age: 30) +/// let nameAttribute = Attribute(Focus(root: $person, keyPath: \.name)) +/// // nameAttribute automatically updates when person.name changes +/// +/// Focus is commonly used internally by OpenAttributeGraph's dynamic member lookup system to create property-specific attributes. +/// +/// ## Key Features +/// +/// - KeyPath-based focusing: Use any Swift KeyPath to focus on specific properties +/// - Automatic updates: Changes to the focused property automatically propagate +/// - Type safety: Full compile-time type checking for focused properties +/// - Efficient tracking: Only tracks changes to the specific focused property +/// +/// ## Usage Pattern +/// +/// Focus is ideal for: +/// - Creating focused views of complex data structures +/// - Implementing dynamic member lookup for attributes +/// - Breaking down large objects into smaller, more manageable attribute pieces +/// - Selective observation of specific properties @frozen public struct Focus: Rule, CustomStringConvertible { public var root: Attribute diff --git a/Sources/OpenAttributeGraph/Attribute/Rule/Rule.swift b/Sources/OpenAttributeGraph/Attribute/Rule/Rule.swift index 4e661ee1..4cdfa84d 100644 --- a/Sources/OpenAttributeGraph/Attribute/Rule/Rule.swift +++ b/Sources/OpenAttributeGraph/Attribute/Rule/Rule.swift @@ -7,9 +7,53 @@ public import OpenAttributeGraphCxx +/// A protocol for defining computed attributes that automatically update when dependencies change. +/// +/// Rules provide a way to create derived attributes that compute their values based on other attributes. +/// When any dependency changes, the rule will automatically recompute its value. +/// +/// struct DoubledRule: Rule { +/// typealias Value = Int +/// let source: Attribute +/// +/// var value: Int { +/// source.wrappedValue * 2 +/// } +/// } +/// +/// @Attribute var count: Int = 5 +/// let doubled = Attribute(DoubledRule(source: $count)) +/// // doubled.wrappedValue == 10 +/// +/// count = 10 +/// // doubled.wrappedValue automatically becomes 20 +/// +/// ## Key Features +/// +/// - Automatic dependency tracking: Dependencies are discovered automatically when accessed +/// - Lazy evaluation: Values are only computed when needed +/// - Caching: Results are cached until dependencies change +/// - Efficient updates: Only recomputes when dependencies actually change +/// +/// ## Implementation Requirements +/// +/// Types conforming to `Rule` must provide: +/// - `Value`: The type of value produced by the rule +/// - `value`: A computed property that returns the current value +/// - `initialValue`: An optional initial value (defaults to `nil`) +/// +/// ## Advanced Usage +/// +/// For rules that need to maintain state between evaluations, see ``StatefulRule``. +/// For rules that can be cached based on their content, make your rule type conform to `Hashable`. public protocol Rule: _AttributeBody { + /// The type of value produced by this rule. associatedtype Value + + /// An optional initial value to use before the rule is first evaluated. static var initialValue: Value? { get } + + /// Computes and returns the current value of the rule. var value: Value { get } } diff --git a/Sources/OpenAttributeGraph/Attribute/Rule/StatefulRule.swift b/Sources/OpenAttributeGraph/Attribute/Rule/StatefulRule.swift index be1894d4..8ca72d46 100644 --- a/Sources/OpenAttributeGraph/Attribute/Rule/StatefulRule.swift +++ b/Sources/OpenAttributeGraph/Attribute/Rule/StatefulRule.swift @@ -7,6 +7,36 @@ public import OpenAttributeGraphCxx +/// A protocol for defining computed attributes that maintain state between evaluations. +/// +/// `StatefulRule` extends the basic `Rule` concept by allowing rules to maintain mutable state between updates. This is useful for rules that need to track changes over time or maintain internal state. +/// +/// struct CounterRule: StatefulRule { +/// typealias Value = Int +/// private var counter = 0 +/// +/// mutating func updateValue() { +/// counter += 1 +/// value = counter +/// } +/// } +/// +/// Unlike ``Rule``, `StatefulRule` allows mutation through the `updateValue()` method and provides direct access to the current value through the `value` property. +/// +/// ## Key Features +/// +/// - Mutable state: Rules can maintain and modify internal state +/// - Direct value access: Read and write the current value directly +/// - Context access: Access to rule evaluation context and attribute +/// - Lifecycle control: Manual control over when and how values update +/// +/// ## Usage Pattern +/// +/// StatefulRule is ideal for scenarios where you need to: +/// - Accumulate values over time +/// - Maintain counters or timers +/// - Implement complex state machines +/// - Cache expensive computations with custom invalidation public protocol StatefulRule: _AttributeBody { associatedtype Value static var initialValue: Value? { get } diff --git a/Sources/OpenAttributeGraph/Attribute/RuleContext/RuleContext.swift b/Sources/OpenAttributeGraph/Attribute/RuleContext/RuleContext.swift index 126b494c..2343107a 100644 --- a/Sources/OpenAttributeGraph/Attribute/RuleContext/RuleContext.swift +++ b/Sources/OpenAttributeGraph/Attribute/RuleContext/RuleContext.swift @@ -7,6 +7,7 @@ public import OpenAttributeGraphCxx +/// Context object providing access to rule evaluation state and input values. @frozen public struct RuleContext: Equatable { public var attribute: Attribute diff --git a/Sources/OpenAttributeGraph/Attribute/Weak/WeakAttribute.swift b/Sources/OpenAttributeGraph/Attribute/Weak/WeakAttribute.swift index 31341d90..2fa4f975 100644 --- a/Sources/OpenAttributeGraph/Attribute/Weak/WeakAttribute.swift +++ b/Sources/OpenAttributeGraph/Attribute/Weak/WeakAttribute.swift @@ -7,6 +7,33 @@ public import OpenAttributeGraphCxx +/// A weak reference property wrapper for attributes that prevents retain cycles. +/// +/// `WeakAttribute` provides a way to hold weak references to attributes, preventing strong reference cycles in the attribute graph while still allowing access to reactive values. +/// +/// @WeakAttribute var parentAttribute: SomeType? +/// +/// // Safe access to potentially deallocated attribute +/// if let value = parentAttribute { +/// print("Parent value: \(value)") +/// } +/// +/// The weak attribute automatically becomes `nil` when the referenced attribute is deallocated, providing memory-safe access to optional attribute references. +/// +/// ## Key Features +/// +/// - Weak references: Prevents retain cycles in attribute relationships +/// - Automatic nil assignment: Referenced attributes become nil when deallocated +/// - Dynamic member lookup: Access nested properties through weak references +/// - Optional semantics: All values are optional since references may be deallocated +/// +/// ## Usage Pattern +/// +/// WeakAttribute is essential for: +/// - Parent-child attribute relationships +/// - Observer patterns that don't own the observed attribute +/// - Breaking potential retain cycles in complex attribute graphs +/// - Optional attribute references in data structures @frozen @propertyWrapper @dynamicMemberLookup diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Architecture.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Architecture.md new file mode 100644 index 00000000..2cc7d1de --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Architecture.md @@ -0,0 +1,156 @@ +# Architecture + +Understanding OpenAttributeGraph's architecture: Attributes, Graph, and Runtime. + +## Overview + +OpenAttributeGraph is built around an architecture that provides a complete reactive programming system. Each layer serves a specific purpose in the overall framework, working together to deliver high-performance reactive updates. + +## Core Architecture + +### Attribute Layer + +The Attribute layer forms the foundation of the reactive system, providing the building blocks for trackable, reactive values. + +#### Core Concepts + +Property Wrapper Design: At its heart, ``Attribute`` is a property wrapper that makes any Swift value reactive. When you wrap a value with `@Attribute`, it automatically gains dependency tracking capabilities: + + @Attribute var count: Int = 0 + +Type Erasure: ``AnyAttribute`` provides type-erased access to attributes, enabling runtime flexibility while maintaining type safety where possible. + +Rule-Based Transformations: The ``Rule`` and ``StatefulRule`` protocols allow you to create computed attributes that automatically update when their dependencies change: + + struct DoubledRule: Rule { + typealias Value = Int + let source: Attribute + + func value() -> Int { + source.wrappedValue * 2 + } + } + +Reference Semantics: ``WeakAttribute`` and ``OptionalAttribute`` provide safe ways to handle optional and weak references within the attribute system. + +#### Body System + +The attribute body system optimizes performance through: +- Lazy evaluation: Values are only computed when needed +- Caching: Results are cached until dependencies change +- Efficient invalidation: Only affected attributes are marked for recomputation + +### Graph Layer + +The Graph layer manages the dependency network between attributes and orchestrates efficient updates. + +#### Dependency Management + +The ``Graph`` maintains a directed acyclic graph (DAG) of attribute dependencies: + +- Automatic tracking: Dependencies are discovered automatically when attributes are accessed during rule evaluation +- Cycle detection: The system prevents and detects circular dependencies +- Batch updates: Multiple changes are batched together for optimal performance + +#### Update Propagation + +When an attribute changes, the graph efficiently propagates updates: + +1. Mark phase: Changed attributes are marked as invalid +2. Sweep phase: Dependent attributes are transitively marked +3. Update phase: Values are recomputed in dependency order + +#### Subgraphs + +``Subgraph`` provides scoped computation contexts that allow: +- Isolation: Separate update domains for different parts of your application +- Performance: Smaller update scopes reduce computational overhead +- Testing: Isolated environments for unit testing + +### Runtime Layer + +The Runtime layer provides the low-level type introspection and memory management that makes the higher layers possible. + +#### Type Introspection + +``Metadata`` provides Swift runtime type information: +- Field enumeration: Discover the fields of any Swift type at runtime +- Layout information: Access memory layout and alignment details +- Type comparison: Efficiently compare types and values + +This runtime introspection enables features like automatic KeyPath-based attribute access: + + @Attribute var person: Person = Person(name: "Alice", age: 30) + let nameAttribute = person.name // Automatic attribute creation via KeyPath + +#### Memory Management + +The runtime layer handles: +- Pointer arithmetic: Safe offset calculations for nested attribute access +- Type-safe casting: Runtime type validation and casting +- Value comparison: Efficient equality checking across different types + +#### Integration with Swift Runtime + +> Note: The Runtime layer leverages techniques similar to those found in [wickwirew/Runtime](https://github.com/wickwirew/Runtime) for Swift runtime introspection and type manipulation. + +The system integrates deeply with Swift's runtime to: +- Access private metadata structures safely +- Perform efficient type conversions +- Handle dynamic member lookup for attributes + +## How the Layers Work Together + +### Creating an Attribute + +When you create an attribute, all three layers collaborate: + +1. Runtime layer: Introspects the value type and creates metadata +2. Graph layer: Allocates space in the dependency graph +3. Attribute layer: Wraps the value in a reactive property wrapper + +### Dependency Tracking + +During rule evaluation: + +1. Attribute layer: Rules access their dependency attributes +2. Graph layer: Records these accesses as dependencies +3. Runtime layer: Handles type-safe value extraction and conversion + +### Update Propagation + +When a change occurs: + +1. Attribute layer: Detects the value change +2. Graph layer: Propagates invalidation through dependencies +3. Runtime layer: Provides efficient value comparison to minimize updates + +## Performance Characteristics + +The three-layer architecture enables several performance optimizations: + +- Minimal allocations: Attributes reuse storage and minimize memory churn +- Lazy evaluation: Computations are deferred until values are actually needed +- Batch processing: Multiple updates are processed together +- Cache efficiency: Hot paths through the dependency graph are optimized + +## Design Patterns + +The architecture encourages several beneficial patterns: + +### Composition over Inheritance +Attributes compose naturally through rules and transformations rather than class hierarchies. + +### Functional Reactive Programming +The rule system encourages pure, functional transformations of data. + +### Declarative Updates +Changes propagate automatically without explicit update calls. + +## Debugging and Introspection + +Each layer provides debugging capabilities: + +- Attribute layer: Inspect individual attribute values and states +- Graph layer: Visualize dependency relationships and update cycles +- Runtime layer: Examine type metadata and memory layout \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Attribute-References.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Attribute-References.md new file mode 100644 index 00000000..4e974bd4 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Attribute-References.md @@ -0,0 +1,45 @@ +# Attribute References + +Type-erased and reference management for attributes. + +## Overview + +Attribute references provide type-erased access to attributes and specialized reference management for memory-sensitive scenarios. The AnyAttribute type allows working with attributes without knowing their specific value types, while reference-based attributes provide different memory management strategies. + +These reference types are essential for building flexible reactive systems where attribute types may not be known at compile time, or where careful memory management is required to avoid retain cycles. + +## Topics + +### Type-Erased References + +- ``AnyAttribute`` + +### Reference Creation + +- ``AnyAttribute/init(_:)`` +- ``Attribute/init(identifier:)`` + +### Reference Operations + +- ``AnyAttribute/unsafeCast(to:)`` +- ``Attribute/unsafeCast(to:)`` +- ``AnyAttribute/create(offset:size:)`` + +### Reference Properties + +- ``AnyAttribute/identifier`` +- ``Attribute/identifier`` + +### Memory Management + +- ``AnyAttribute/graph`` +- ``AnyAttribute/subgraph`` +- ``Attribute/graph`` +- ``Attribute/subgraph`` + +### Value State + +- ``AnyAttribute/valueState`` +- ``Attribute/valueState`` +- ``AnyAttribute/hasValue`` +- ``Attribute/hasValue`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Attribute/Attribute.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Attribute/Attribute.md new file mode 100644 index 00000000..a255efa8 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Attribute/Attribute.md @@ -0,0 +1,62 @@ +# ``Attribute`` + +## Topics + +### Creating Attributes + +- ``init(identifier:)`` +- ``init(_:)`` +- ``init(value:)`` +- ``init(type:)`` + +### Property Wrapper + +- ``wrappedValue`` +- ``projectedValue`` + +### Dynamic Member Access + +- ``subscript(dynamicMember:)`` +- ``subscript(keyPath:)`` +- ``subscript(offset:)`` + +### Type Transformations + +- ``unsafeCast(to:)`` +- ``unsafeOffset(at:as:)`` +- ``applying(offset:)`` + +### Graph Integration + +- ``graph`` +- ``subgraph`` + +### Value Management + +- ``value`` +- ``valueState`` +- ``valueAndFlags(options:)`` +- ``changedValue(options:)`` +- ``setValue(_:)`` +- ``hasValue`` +- ``updateValue()`` +- ``prefetchValue()`` +- ``invalidateValue()`` +- ``validate()`` + +### Input Management + +- ``addInput(_:options:token:)-9c3h6`` +- ``addInput(_:options:token:)-7u9k3`` + +### Flags and State + +- ``Flags`` +- ``flags`` +- ``setFlags(_:mask:)`` + +### Advanced Operations + +- ``visitBody(_:)`` +- ``mutateBody(as:invalidating:_:)`` +- ``breadthFirstSearch(options:_:)`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Computed-Attributes.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Computed-Attributes.md new file mode 100644 index 00000000..53b4dea0 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Computed-Attributes.md @@ -0,0 +1,43 @@ +# Computed Attributes + +Rule-based attributes that compute their values from other attributes. + +## Overview + +Computed attributes provide a declarative way to create attributes whose values are derived from other attributes. They use rule-based computation to automatically recalculate their values when dependencies change, forming the backbone of OpenAttributeGraph's reactive computation system. + +Rules can be stateless for simple computations or stateful when they need to maintain internal state across updates. The Focus rule provides a specialized way to create attributes that track specific properties of other attributes using Swift's KeyPath system. + +## Topics + +### Rule Protocols + +- ``Rule`` +- ``StatefulRule`` +- ``_AttributeBody`` + +### Specialized Rules + +- ``Focus`` +- ``External`` + +### Rule Creation + +- ``Attribute/init(_:)-4tj1v`` +- ``Attribute/init(_:)-8hz0z`` +- ``Focus/init(root:keyPath:)`` + +### Rule Properties + +- ``Rule/value`` +- ``Rule/flags`` +- ``StatefulRule/value`` +- ``StatefulRule/flags`` +- ``Focus/root`` +- ``Focus/keyPath`` +- ``Focus/value`` + +### Update Mechanisms + +- ``Rule/_update`` +- ``StatefulRule/_update`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Optional/OptionalAttribute.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Optional/OptionalAttribute.md new file mode 100644 index 00000000..103efe57 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Optional/OptionalAttribute.md @@ -0,0 +1,59 @@ +# ``OptionalAttribute`` + +An optional attribute wrapper that may or may not contain a value. + +## Overview + +`OptionalAttribute` provides a way to work with attributes that may be nil, offering optional semantics for attribute references. This is useful when working with attributes that may be conditionally created or destroyed. + + @OptionalAttribute var maybeAttribute: Int? + + if let value = maybeAttribute { + print("Attribute value: \(value)") + } + +The optional attribute wrapper automatically handles the optional nature of attribute references while maintaining the reactive capabilities of the attribute system. + +## Key Features + +- Optional semantics: Natural handling of attributes that may not exist +- Conditional access: Safe access to potentially nil attributes +- Reactive updates: Changes propagate when the attribute becomes available +- Integration with weak attributes: Works seamlessly with ``WeakAttribute`` + +## Usage Pattern + +OptionalAttribute is commonly used for: +- Conditionally created UI elements +- Optional data model properties +- Weak attribute references that may become nil +- Lazy initialization scenarios + +## Topics + +### Creating Optional Attributes + +- ``init()`` +- ``init(base:)`` +- ``init(_:)-47ane`` +- ``init(_:)-9eqjv`` +- ``init(_:)-2u3gq`` + +### Property Wrapper + +- ``wrappedValue`` +- ``projectedValue`` + +### Value Access + +- ``attribute`` +- ``value`` +- ``changedValue(options:)`` + +### Transformations + +- ``map(_:)`` + +### Base Access + +- ``base`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Reactive-Attributes.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Reactive-Attributes.md new file mode 100644 index 00000000..d1372e09 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Reactive-Attributes.md @@ -0,0 +1,36 @@ +# Reactive Attributes + +Reactive properties that automatically track dependencies and manage value updates. + +## Overview + +Reactive attributes form the foundation of OpenAttributeGraph's reactive programming model. These attributes automatically track their dependencies and efficiently propagate changes through the dependency graph when their values change. + +The primary reactive attribute types provide different levels of memory management and reference semantics to handle various use cases in reactive applications. + +## Topics + +### Core Reactive Types + +- ``Attribute`` +- ``WeakAttribute`` +- ``OptionalAttribute`` + +### Property Wrapper Support + +- ``Attribute/wrappedValue`` +- ``Attribute/projectedValue`` +- ``WeakAttribute/wrappedValue`` +- ``WeakAttribute/projectedValue`` + +### Dynamic Member Access + +- ``Attribute/subscript(dynamicMember:)`` +- ``WeakAttribute/subscript(dynamicMember:)`` + +### Value Management + +- ``Attribute/value`` +- ``Attribute/setValue(_:)`` +- ``WeakAttribute/value`` +- ``WeakAttribute/changedValue(options:)`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Rule/Focus.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Rule/Focus.md new file mode 100644 index 00000000..54a8c9c2 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Rule/Focus.md @@ -0,0 +1,17 @@ +# ``Focus`` + +## Topics + +### Creating Focus Rules + +- ``init(root:keyPath:)`` + +### Properties + +- ``root`` +- ``keyPath`` +- ``value`` + +### Configuration + +- ``flags`` diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Rule/Rule.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Rule/Rule.md new file mode 100644 index 00000000..faea4b64 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Rule/Rule.md @@ -0,0 +1,19 @@ +# ``Rule`` + +## Topics + +### Protocol Requirements + +- ``Value`` +- ``initialValue`` +- ``value`` + +### Context Access + +- ``attribute`` +- ``context`` + +### Cached Evaluation + +- ``cachedValue(options:owner:)`` +- ``cachedValueIfExists(options:owner:)`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Rule/StatefulRule.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Rule/StatefulRule.md new file mode 100644 index 00000000..bea5345f --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Rule/StatefulRule.md @@ -0,0 +1,19 @@ +# ``StatefulRule`` + +## Topics + +### Protocol Requirements + +- ``Value`` +- ``initialValue`` +- ``updateValue()`` + +### Value Management + +- ``value`` +- ``hasValue`` + +### Context Access + +- ``attribute`` +- ``context`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/RuleContext/RuleContext.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/RuleContext/RuleContext.md new file mode 100644 index 00000000..ab6a106a --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/RuleContext/RuleContext.md @@ -0,0 +1,55 @@ +# ``RuleContext`` + +Context object providing access to rule evaluation state and input values. + +## Overview + +`RuleContext` provides a structured way to access input values and manage state during rule evaluation. It offers type-safe access to dependent attributes and their values within the context of a specific rule execution. + +The context ensures that dependency tracking is properly maintained while providing convenient access to input attributes. + +## Key Features + +- Type-safe input access: Access dependent attribute values with full type safety +- Dependency tracking: Automatically tracks accessed attributes as dependencies +- Value management: Direct access to current and changed values +- Context isolation: Maintains evaluation context for proper dependency resolution + +## Usage in Rules + +RuleContext is typically used within ``StatefulRule`` implementations to access dependencies and manage the rule's output value: + + struct MyRule: StatefulRule { + let inputAttribute: Attribute + + mutating func updateValue() { + let inputValue = context[inputAttribute] + value = inputValue * 2 + } + } + +## Topics + +### Creating Context + +- ``init(attribute:)`` + +### Input Access + +- ``subscript(_:)-1g3wa`` +- ``subscript(_:)-6y4wa`` +- ``subscript(_:)-2h8nh`` + +### Value Management + +- ``value`` +- ``hasValue`` + +### Change Tracking + +- ``changedValueFlagged(options:)`` +- ``wasModified(options:)`` + +### Associated Attribute + +- ``attribute`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Weak/WeakAttribute.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Weak/WeakAttribute.md new file mode 100644 index 00000000..521c8209 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Attribute/Weak/WeakAttribute.md @@ -0,0 +1,25 @@ +# ``WeakAttribute`` + +## Topics + +### Creating Weak Attributes + +- ``init()`` +- ``init(base:)`` +- ``init(_:)-4u8wa`` +- ``init(_:)-571kb`` + +### Property Wrapper + +- ``wrappedValue`` +- ``projectedValue`` + +### Dynamic Member Access + +- ``subscript(dynamicMember:)`` + +### Value Access + +- ``attribute`` +- ``value`` +- ``changedValue(options:)`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Graph/Dependency-Graphs.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Graph/Dependency-Graphs.md new file mode 100644 index 00000000..3a2316be --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Graph/Dependency-Graphs.md @@ -0,0 +1,50 @@ +# Dependency Graphs + +Graph structures that manage attribute dependencies and updates. + +## Overview + +Dependency graphs form the backbone of OpenAttributeGraph's reactive system, managing relationships between attributes and coordinating updates when values change. The graph system uses a two-level hierarchy with global graphs containing multiple subgraphs for efficient organization and update propagation. + +Graphs automatically track dependencies as attributes access other attributes during computation, building an efficient dependency network that minimizes unnecessary recalculations when changes occur. + +## Topics + +### Graph Types + +- ``Graph`` +- ``Subgraph`` + +### Graph Creation + +- ``Graph/init()`` +- ``Subgraph/init()`` + +### Graph Management + +- ``Graph/typeIndex(ctx:body:valueType:flags:update:)`` +- ``Subgraph/currentGraphContext`` + +### Update Coordination + +- ``Graph/willInvalidate(attribute:)`` +- ``Graph/updateValue()`` +- ``Subgraph/update()`` + +### Graph Traversal + +- ``Attribute/breadthFirstSearch(options:_:)`` +- ``AnyAttribute/breadthFirstSearch(options:_:)`` + +### Input Management + +- ``Attribute/addInput(_:options:token:)`` +- ``Attribute/addInput(_:options:token:)-6p8bn`` +- ``AnyAttribute/addInput(_:options:token:)`` + +### Graph Properties + +- ``Attribute/graph`` +- ``Attribute/subgraph`` +- ``AnyAttribute/graph`` +- ``AnyAttribute/subgraph`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Graph/Graph.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Graph/Graph.md new file mode 100644 index 00000000..15a7421f --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Graph/Graph.md @@ -0,0 +1,60 @@ +# ``Graph`` + +The central coordinator for attribute relationships and update cycles. + +## Overview + +`Graph` manages the dependency network between attributes and orchestrates efficient updates across the entire reactive system. It maintains a directed acyclic graph (DAG) of attribute dependencies and handles the propagation of changes. + +The graph automatically tracks dependencies when attributes are accessed during rule evaluation, detects cycles, and batches updates for optimal performance. + +## Key Features + +- Dependency tracking: Automatically discovers and maintains attribute relationships +- Cycle detection: Prevents and detects circular dependencies +- Batch updates: Groups multiple changes for efficient processing +- Update scheduling: Coordinates when and how attributes are recomputed +- Performance monitoring: Profiling and debugging capabilities + +## Update Propagation + +When an attribute changes, the graph efficiently propagates updates through three phases: +1. Mark phase: Changed attributes are marked as invalid +2. Sweep phase: Dependent attributes are transitively marked +3. Update phase: Values are recomputed in dependency order + +## Topics + +### Update Control + +- ``withoutUpdate(_:)`` +- ``withoutSubgraphInvalidation(_:)`` +- ``withDeadline(_:_:)`` + +### Callbacks + +- ``onInvalidation(_:)`` +- ``onUpdate(_:)`` + +### Performance Monitoring + +- ``startProfiling()`` +- ``stopProfiling()`` +- ``resetProfile()`` + +### Statistics + +- ``mainUpdates`` + +### Global Operations + +- ``anyInputsChanged(excluding:)`` + +### Output Management + +- ``outputValue()`` +- ``setOutputValue(_:)`` + +### Archive and Debug + +- ``archiveJSON(name:)`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Graph/Subgraph.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Graph/Subgraph.md new file mode 100644 index 00000000..a371e3e4 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Graph/Subgraph.md @@ -0,0 +1,48 @@ +# ``Subgraph`` + +Scoped computation contexts for isolated attribute groups. + +## Overview + +`Subgraph` provides scoped computation contexts that allow for isolated attribute groups with separate update domains. This enables better performance by reducing the scope of updates and provides isolated environments for testing. + +Subgraphs are essential for organizing complex attribute hierarchies and controlling the scope of reactive updates. + +## Key Features + +- Isolation: Separate update domains for different parts of your application +- Performance: Smaller update scopes reduce computational overhead +- Testing: Isolated environments for unit testing +- Observer pattern: Add observers for subgraph changes + +## Usage Pattern + +Subgraphs are commonly used to: +- Isolate different UI components or modules +- Create test environments with controlled attribute scopes +- Optimize performance by limiting update propagation +- Implement hierarchical reactive systems + +## Topics + +### Type Aliases + +- ``Flags`` +- ``ChildFlags`` + +### Observers + +- ``addObserver(_:)`` + +### Scoped Execution + +- ``apply(_:)`` + +### Attribute Iteration + +- ``forEach(_:_:)`` + +### Global Access + +- ``current`` +- ``currentGraphContext`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Info.plist b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Info.plist new file mode 100644 index 00000000..95dc4559 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Info.plist @@ -0,0 +1,12 @@ + + + + + CFBundleName + OpenAttributeGraph + CFBundleDisplayName + OpenAttributeGraph + CDDefaultCodeListingLanguage + swift + + diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/OpenAttributeGraph.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/OpenAttributeGraph.md new file mode 100644 index 00000000..f8f0595e --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/OpenAttributeGraph.md @@ -0,0 +1,29 @@ +# ``OpenAttributeGraph`` + +A high-performance reactive programming framework that powers OpebSwiftUI's underlying dependency tracking and update system. + +## Overview + +It provides a reactive programming model built around attributes that automatically track dependencies and efficiently propagate changes through a dependency graph. + +The framework is designed for high performance and powers the reactive updates that make SwiftUI interfaces responsive and efficient. + +## Topics + +### Essentials + +- + +### Attributes + +- +- +- + +### Graph Management + +- + +### Runtime Support + +- diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/Metadata.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/Metadata.md new file mode 100644 index 00000000..ea3f4d43 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/Metadata.md @@ -0,0 +1,43 @@ +# ``Metadata`` + +Swift runtime type information and reflection capabilities for OpenAttributeGraph. + +## Overview + +`Metadata` provides access to Swift's runtime type system, enabling type introspection and dynamic operations that power OpenAttributeGraph's reactive system. + + let intMetadata = Metadata(Int.self) + let stringMetadata = Metadata(String.self) + + let metadata = Metadata(String.self) + let type = metadata.type // Returns String.Type + +## Key Features + +- Runtime type introspection: Access Swift type metadata at runtime +- Field enumeration: Discover the fields of any Swift type +- Type comparison: Efficient equality checking across different types +- Memory layout: Access memory layout and alignment details + +## Usage with Attributes + +Metadata enables OpenAttributeGraph to perform type-safe operations on attributes with different value types, supporting features like automatic KeyPath-based attribute access and efficient value comparison. + +## Topics + +### Creating Metadata + +- ``init(_:)`` + +### Type Information + +- ``type`` +- ``description`` + +### Field Introspection + +- ``forEachField(options:do:)`` + +### Global Functions + +- ``forEachField(of:do:)`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/TupleType.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/TupleType.md new file mode 100644 index 00000000..4f87c363 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/TupleType.md @@ -0,0 +1,68 @@ +# ``TupleType`` + +Runtime support for Swift tuple types with dynamic element access and memory management. + +## Overview + +`TupleType` provides runtime introspection and manipulation capabilities for Swift tuple types. It enables dynamic access to tuple elements, memory layout information, and safe element copying operations without requiring compile-time knowledge of the tuple's structure. + + let tupleType = TupleType([Int.self, String.self, Bool.self]) + let tuple = (42, "Hello", true) + + // Access elements dynamically + let intValue: Int = tuple[0] + let stringValue: String = tuple[1] + let boolValue: Bool = tuple[2] + +TupleType is essential for OpenAttributeGraph's ability to work with heterogeneous data structures while maintaining type safety and efficient memory operations. + +## Key Features + +- Dynamic tuple creation: Create tuple types from arrays of Swift types +- Element access: Safely access tuple elements by index with type checking +- Memory management: Initialize, copy, and destroy tuple elements safely +- Layout introspection: Query element offsets, sizes, and memory layout +- Buffer operations: Work with raw memory buffers containing tuple data + +## Usage with Attributes + +TupleType enables OpenAttributeGraph to create attributes that contain heterogeneous data structures, supporting complex reactive computations over tuple-based data. + +## Topics + +### Creating Tuple Types + +- ``init(_:)`` +- ``init(_:)-9jmk1`` +- ``init(count:elements:)`` + +### Type Properties + +- ``type`` +- ``count`` +- ``size`` +- ``isEmpty`` +- ``indices`` + +### Element Access + +- ``type(at:)`` +- ``elementType(at:)`` +- ``elementSize(at:)`` +- ``elementOffset(at:type:)`` +- ``offset(at:as:)`` + +### Element Operations + +- ``setElement(in:at:from:options:)`` +- ``getElement(in:at:to:options:)`` +- ``destroy(_:)`` +- ``destroy(_:at:)`` + +### Copy Options + +- ``CopyOptions`` + +### Buffer Functions + +- ``withUnsafeTuple(of:count:_:)`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/Type-Introspection.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/Type-Introspection.md new file mode 100644 index 00000000..78f4885a --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/Type-Introspection.md @@ -0,0 +1,54 @@ +# Type Introspection + +Runtime type information and introspection utilities. + +## Overview + +Type introspection provides runtime access to Swift type metadata, enabling OpenAttributeGraph to work with types dynamically. The Metadata system allows the framework to handle type information at runtime, supporting features like type-erased attributes and dynamic type checking. + +TupleType provides specialized support for working with tuple types at runtime, enabling dynamic element access and memory management for heterogeneous data structures. + +## Topics + +### Type Metadata + +- ``Metadata`` +- ``TupleType`` + +### Metadata Creation + +- ``Metadata/init(_:)`` +- ``TupleType/init(_:)`` +- ``TupleType/init(_:)-9jmk1`` +- ``TupleType/init(count:elements:)`` + +### Type Properties + +- ``Metadata/description`` +- ``TupleType/type`` +- ``TupleType/count`` +- ``TupleType/size`` + +### Tuple Operations + +- ``UnsafeTuple`` +- ``UnsafeMutableTuple`` +- ``withUnsafeTuple(of:count:_:)`` + +### Runtime Utilities + +- ``MemoryLayout/offset(of:)`` +- ``PointerOffset`` + +### Memory Layout + +- ``PointerOffset/offset(_:)`` +- ``PointerOffset/byteOffset`` +- ``Attribute/unsafeOffset(at:as:)`` +- ``Attribute/applying(offset:)`` +- ``TupleType/elementOffset(at:type:)`` + +### Type Validation + +- ``Attribute/validate()`` +- ``AnyAttribute/verify(type:)`` diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/UnsafeMutableTuple.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/UnsafeMutableTuple.md new file mode 100644 index 00000000..54de5069 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/UnsafeMutableTuple.md @@ -0,0 +1,60 @@ +# ``UnsafeMutableTuple`` + +Mutable tuple buffer for dynamic tuple creation, modification, and memory management. + +## Overview + +`UnsafeMutableTuple` extends `UnsafeTuple` with mutation capabilities, allowing creation, modification, and destruction of tuple data. It provides complete lifecycle management for dynamically created tuples with proper memory allocation and cleanup. + + let mutableTuple = UnsafeMutableTuple(with: tupleType) + + // Initialize elements + mutableTuple.initialize(at: 0, to: 42) + mutableTuple.initialize(at: 1, to: "Hello") + + // Access and modify + mutableTuple[0] = 100 + let value: String = mutableTuple[1] + + // Clean up + mutableTuple.deallocate(initialized: true) + +## Key Features + +- Dynamic allocation: Create tuple buffers with proper memory alignment +- Element initialization: Initialize tuple elements in-place with type safety +- Mutation operations: Modify tuple elements after creation +- Memory management: Proper cleanup with element-wise deinitialization +- Lifecycle control: Manual control over initialization and deallocation phases + +## Topics + +### Creating Mutable Tuples + +- ``init(with:)`` + +### Element Initialization + +- ``initialize(at:to:)`` + +### Memory Management + +- ``deinitialize()`` +- ``deinitialize(at:)`` +- ``deallocate(initialized:)`` + +### Tuple Properties + +- ``count`` +- ``isEmpty`` +- ``indices`` + +### Element Access + +- ``subscript()`` +- ``subscript(_:)`` + +### Address Operations + +- ``address(as:)`` +- ``address(of:as:)`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/UnsafeTuple.md b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/UnsafeTuple.md new file mode 100644 index 00000000..f25c6649 --- /dev/null +++ b/Sources/OpenAttributeGraph/OpenAttributeGraph.docc/Runtime/UnsafeTuple.md @@ -0,0 +1,38 @@ +# ``UnsafeTuple`` + +Immutable tuple buffer for safe element access and type-checked operations. + +## Overview + +`UnsafeTuple` provides safe, type-checked access to elements within a tuple stored in a raw memory buffer. It combines tuple type metadata with a pointer to tuple data, enabling runtime inspection and element retrieval while maintaining memory safety. + + withUnsafeTuple(of: tupleType, count: 1) { unsafeTuple in + let firstElement: Int = unsafeTuple[0] + let secondElement: String = unsafeTuple[1] + // Access elements safely with compile-time type checking + } + +## Key Features + +- Type-safe element access: Access tuple elements with automatic type verification +- Index-based operations: Use integer indices to access elements by position +- Memory safety: Bounds checking and type validation prevent unsafe memory access +- Address computation: Get typed pointers to specific tuple elements + +## Topics + +### Tuple Properties + +- ``count`` +- ``isEmpty`` +- ``indices`` + +### Element Access + +- ``subscript()`` +- ``subscript(_:)`` + +### Address Operations + +- ``address(as:)`` +- ``address(of:as:)`` \ No newline at end of file diff --git a/Sources/OpenAttributeGraph/Runtime/CompareValues.swift b/Sources/OpenAttributeGraph/Runtime/CompareValues.swift index 7f9677af..9284ed77 100644 --- a/Sources/OpenAttributeGraph/Runtime/CompareValues.swift +++ b/Sources/OpenAttributeGraph/Runtime/CompareValues.swift @@ -15,10 +15,12 @@ private func OAGCompareValues( options: ComparisonOptions ) -> Bool +/// Compares two values using the specified comparison mode. public func compareValues(_ lhs: Value, _ rhs: Value, mode: ComparisonMode = .equatableAlways) -> Bool { compareValues(lhs, rhs, options: [.init(mode: mode), .copyOnWrite]) } +/// Compares two values using the specified comparison options. public func compareValues(_ lhs: Value, _ rhs: Value, options: ComparisonOptions) -> Bool { withUnsafePointer(to: lhs) { p1 in withUnsafePointer(to: rhs) { p2 in diff --git a/Sources/OpenAttributeGraph/Runtime/Metadata.swift b/Sources/OpenAttributeGraph/Runtime/Metadata.swift index 0a3ee53a..020d8238 100644 --- a/Sources/OpenAttributeGraph/Runtime/Metadata.swift +++ b/Sources/OpenAttributeGraph/Runtime/Metadata.swift @@ -31,10 +31,14 @@ public func forEachField( } extension Metadata: Swift.Hashable, Swift.CustomStringConvertible { + /// Creates metadata from a Swift type. + /// + /// - Parameter type: The Swift type to create metadata for public init(_ type: any Any.Type) { self.init(rawValue: unsafeBitCast(type, to: UnsafePointer<_Metadata>.self)) } + /// The Swift type represented by this metadata. public var type: any Any.Type { unsafeBitCast(rawValue, to: Any.Type.self) }