Skip to content

Commit

Permalink
Update DynamicPropertyCache (#28)
Browse files Browse the repository at this point in the history
* Update _GraphInputs

* remove mode parameter pass

* Update DynamicPropertyCache

* Update enum and optional’s fields implementation

* Update CacheTests

* Update FieldsLayout implementation

* Update DynamicPropertyCache implementation

* Remove internal structure

* Update DynamicProperty

* Update _DynamicPropertyBuffer

* Update OpenGraph dependency version

* Fix compiler warning
  • Loading branch information
Kyle-Ye committed Jan 28, 2024
1 parent 366262f commit 75db3fa
Show file tree
Hide file tree
Showing 13 changed files with 353 additions and 97 deletions.
2 changes: 1 addition & 1 deletion Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"location" : "https://github.com/OpenSwiftUIProject/OpenGraph",
"state" : {
"branch" : "main",
"revision" : "17b4ef3ead4c0c1bce51c965d6a1169f4e65c61d"
"revision" : "ca3f8991a8a9564d581a08d9ce43b216c9afe01b"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
struct CachedEnvironment {}
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ struct PropertyList: CustomStringConvertible {
if let result = find(elements.map { .passUnretained($0) }, key: keyType) {
guard !compareValues(
newValue,
result.takeUnretainedValue().value,
mode: ._3
result.takeUnretainedValue().value
) else {
return
}
Expand Down Expand Up @@ -270,7 +269,7 @@ private class TypedElement<Key: PropertyKey>: PropertyList.Element {
guard !ignoredTypes.contains(ObjectIdentifier(Key.self)) else {
return true
}
guard compareValues(value, typedElement.value, mode: ._3) else {
guard compareValues(value, typedElement.value) else {
return false
}
ignoredTypes.insert(ObjectIdentifier(Key.self))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,23 @@
//
// Created by Kyle on 2023/11/2.
// Lastest Version: iOS 15.5
// Status: WIP
// Status: Complete

/// An interface for a stored variable that updates an external property of a
/// view.
///
/// The view gives values to these properties prior to recomputing the view's
/// ``View/body-swift.property``.
public protocol DynamicProperty {
static func _makeProperty<V>(in buffer: inout _DynamicPropertyBuffer, container: _GraphValue<V>, fieldOffset: Int, inputs: inout _GraphInputs)
static func _makeProperty<Value>(
in buffer: inout _DynamicPropertyBuffer,
container: _GraphValue<Value>,
fieldOffset: Int,
inputs: inout _GraphInputs
)

static var _propertyBehaviors: UInt32 { get }

/// Updates the underlying value of the stored value.
///
/// OpenSwiftUI calls this function before rendering a view's
Expand All @@ -23,28 +30,7 @@ public protocol DynamicProperty {
}

extension DynamicProperty {
public static func _makeProperty<V>(in buffer: inout _DynamicPropertyBuffer, container: _GraphValue<V>, fieldOffset: Int, inputs: inout _GraphInputs) {
makeEmbeddedProperties(in: &buffer, container: container, fieldOffset: fieldOffset, inputs: &inputs)
// TODO
buffer.append(EmbeddedDynamicPropertyBox<Self>(), fieldOffset: fieldOffset)
}

static func makeEmbeddedProperties<V>(in buffer: inout _DynamicPropertyBuffer, container: _GraphValue<V>, fieldOffset: Int, inputs: inout _GraphInputs) -> () {
let fields = DynamicPropertyCache.fields(of: self)
// TODO
buffer.addFields(fields, container: container, inputs: &inputs, baseOffset: fieldOffset)
}

public mutating func update() {}
public static var _propertyBehaviors: UInt32 { 0 }
}

private struct EmbeddedDynamicPropertyBox<Value: DynamicProperty>: DynamicPropertyBox {
typealias Property = Value
func destroy() {}
func reset() {}
func update(property: inout Value, phase _: _GraphInputs.Phase) -> Bool {
property.update()
return false
}

public mutating func update() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//
// DynamicPropertyBehaviors.swift
// OpenSwiftUI
//
// Created by Kyle on 2024/1/6.
// Lastest Version: iOS 15.5
// Status: Complete

struct DynamicPropertyBehaviors: OptionSet {
let rawValue: UInt32
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ protocol DynamicPropertyBox<Property>: DynamicProperty {
func destroy()
func reset()
func update(property: inout Property, phase: _GraphInputs.Phase) -> Bool
func getState<S>(type: S.Type) -> Binding<S>?
func getState<Value>(type: Value.Type) -> Binding<Value>?
}

extension DynamicProperty {
func getState<S>(type: S.Type) -> Binding<S>? { nil }
extension DynamicPropertyBox {
func getState<Value>(type _: Value.Type) -> Binding<Value>? { nil }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
//
// DynamicPropertyCache.swift
// OpenSwiftUI
//
// Created by Kyle on 2024/1/10.
// Lastest Version: iOS 15.5
// Status: Complete
// ID: 49D2A32E637CD497C6DE29B8E060A506

internal import OpenGraphShims

// MARK: - DynamicPropertyCache

struct DynamicPropertyCache {
private static var cache = MutableBox([ObjectIdentifier: Fields]())

static func fields(of type: Any.Type) -> Fields {
if let fields = cache.value[ObjectIdentifier(type)] {
return fields
}
let fields: Fields
let typeID = OGTypeID(type)
switch typeID.kind {
case .enum, .optional:
var taggedFields: [TaggedFields] = []
_ = typeID.forEachField(options: [._2, ._4]) { name, offset, fieldType in
var fields: [Field] = []
let tupleType = OGTupleType(fieldType)
for index in tupleType.indices {
guard let dynamicPropertyType = tupleType.type(at: index) as? DynamicProperty.Type else {
break
}
let offset = tupleType.offset(at: index)
let field = Field(type: dynamicPropertyType, offset: offset, name: name)
fields.append(field)
}
if !fields.isEmpty {
let taggedField = TaggedFields(tag: offset, fields: fields)
taggedFields.append(taggedField)
}
return true
}
fields = Fields(layout: .sum(type, taggedFields))
case .struct, .tuple:
var fieldArray: [Field] = []
_ = typeID.forEachField(options: [._2]) { name, offset, fieldType in
guard let dynamicPropertyType = fieldType as? DynamicProperty.Type else {
return true
}
let field = Field(type: dynamicPropertyType, offset: offset, name: name)
fieldArray.append(field)
return true
}
fields = Fields(layout: .product(fieldArray))
default:
fields = Fields(layout: .product([]))
break
}
if fields.behaviors.contains(.init(rawValue: 3)) {
Log.runtimeIssues("%s is marked async, but contains properties that require the main thread.", [_typeName(type)])
}
cache.value[ObjectIdentifier(type)] = fields
return fields
}
}

// MARK: - DynamicPropertyCache.Fields

extension DynamicPropertyCache {
struct Fields {
var layout: Layout
var behaviors: DynamicPropertyBehaviors

enum Layout {
case product([Field])
case sum(Any.Type, [TaggedFields])
}

init(layout: Layout) {
var behaviors: UInt32 = 0
switch layout {
case let .product(fields):
for field in fields {
behaviors |= field.type._propertyBehaviors
}
case let .sum(_, taggedFields):
for taggedField in taggedFields {
for field in taggedField.fields {
behaviors |= field.type._propertyBehaviors
}
}
}
self.layout = layout
self.behaviors = .init(rawValue: behaviors)
}
}
}

// MARK: - DynamicPropertyCache.Field

extension DynamicPropertyCache {
struct Field {
var type: DynamicProperty.Type
var offset: Int
var name: UnsafePointer<Int8>?
}
}

// MARK: - DynamicPropertyCache.TaggedFields

extension DynamicPropertyCache {
struct TaggedFields {
var tag: Int
var fields: [Field]
}
}

// MARK: - EmbeddedDynamicPropertyBox

private struct EmbeddedDynamicPropertyBox<Value: DynamicProperty>: DynamicPropertyBox {
typealias Property = Value
func destroy() {}
func reset() {}
func update(property: inout Property, phase _: _GraphInputs.Phase) -> Bool {
property.update()
return false
}
}

extension DynamicProperty {
public static func _makeProperty<Value>(
in buffer: inout _DynamicPropertyBuffer,
container: _GraphValue<Value>,
fieldOffset: Int,
inputs: inout _GraphInputs
) {
makeEmbeddedProperties(
in: &buffer,
container: container,
fieldOffset: fieldOffset,
inputs: &inputs
)
buffer.append(
EmbeddedDynamicPropertyBox<Self>(),
fieldOffset: fieldOffset
)
}

static func makeEmbeddedProperties<Value>(
in buffer: inout _DynamicPropertyBuffer,
container: _GraphValue<Value>,
fieldOffset: Int,
inputs: inout _GraphInputs
) -> () {
let fields = DynamicPropertyCache.fields(of: self)
buffer.addFields(
fields,
container: container,
inputs: &inputs,
baseOffset: fieldOffset
)
}
}

This file was deleted.

This file was deleted.

Loading

0 comments on commit 75db3fa

Please sign in to comment.