Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update DynamicPropertyCache #28

Merged
merged 12 commits into from
Jan 28, 2024
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
Loading