Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,9 @@ package struct UnsafeHeterogeneousBuffer: Collection {
}

private mutating func allocate(_ bytes: Int) -> UnsafeMutableRawPointer {
var count = _count
var offset = 0
var size = 0
while count != 0 {
let itemSize = buf
.advanced(by: offset)
.assumingMemoryBound(to: Item.self)
.pointee
.size
offset &+= Int(itemSize)
count &-= 1
offset = count == 0 ? 0 : offset
size &+= Int(itemSize)
for element in self {
size += Int(element.item.pointee.size)
}
// Grow buffer if needed
if Int(available) < bytes {
Expand Down Expand Up @@ -108,7 +98,6 @@ package struct UnsafeHeterogeneousBuffer: Collection {
oldBuffer += size
newBuffer += size
} while count != 0 || itemSize != 0

}
buf.deallocate()
}
Expand All @@ -118,18 +107,8 @@ package struct UnsafeHeterogeneousBuffer: Collection {

package func destroy() {
defer { buf?.deallocate() }
guard _count != 0 else {
return
}
var count = _count
var offset = 0
while count != 0 {
let itemPointer = buf
.advanced(by: offset)
.assumingMemoryBound(to: Item.self)
itemPointer.pointee.vtable.deinitialize(elt: .init(item: itemPointer))
offset &+= Int(itemPointer.pointee.size)
count &-= 1
for element in self {
element.item.pointee.vtable.deinitialize(elt: element)
}
}

Expand Down
27 changes: 19 additions & 8 deletions Sources/OpenSwiftUICore/View/Graph/ViewGraph.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ package final class ViewGraph: GraphHost {

package weak var delegate: (any ViewGraphDelegate)? = nil

// private var features: ViewGraphFeaturesBuffer = .init()
private var features: ViewGraphFeatureBuffer = .init(contents: .init())

package var centersRootView: Bool = true

Expand Down Expand Up @@ -183,15 +183,20 @@ package final class ViewGraph: GraphHost {
deinit {
// FIXME
removePreferenceOutlets(isInvalidating: true)
features.contents.destroy()
}

override package var graphDelegate: GraphDelegate? { delegate }

override package var parentHost: GraphHost? { preferenceBridge?.viewGraph }

// TODO: ViewGraphFeature
// package func append<T>(feature: T) where T: ViewGraphFeature
// package subscript<T>(feature: T.Type) -> UnsafeMutablePointer<T>? where T: ViewGraphFeature
package func append<T>(feature: T) where T: ViewGraphFeature {
features.append(feature)
}

package subscript<T>(feature: T.Type) -> UnsafeMutablePointer<T>? where T: ViewGraphFeature {
features[feature]
}

override package func instantiateOutputs() {
#if canImport(Darwin)
Expand Down Expand Up @@ -231,9 +236,13 @@ package final class ViewGraph: GraphHost {
) { rootGeometry in
rootGeometry.$layoutDirection = inputs.mapEnvironment(\.layoutDirection)
}
// TODO: features related
let outputs = makeRootView(rootView, inputs)
// TODO: features related
for feature in features {
feature.modifyViewInputs(inputs: &inputs, graph: self)
}
var outputs = makeRootView(rootView, inputs)
for feature in features {
feature.modifyViewOutputs(outputs: &outputs, inputs: inputs, graph: self)
}
return outputs
}
$rootGeometry.mutateBody(
Expand Down Expand Up @@ -263,7 +272,9 @@ package final class ViewGraph: GraphHost {
override package func uninstantiateOutputs() {
#if canImport(Darwin)
removePreferenceOutlets(isInvalidating: false)
// TODO: features
for feature in features {
feature.uninstantiate(graph: self)
}
$rootGeometry.mutateBody(
as: RootGeometry.self,
invalidating: true
Expand Down
127 changes: 127 additions & 0 deletions Sources/OpenSwiftUICore/View/Graph/ViewGraphFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//
// Audited for iOS 18.0
// Status: Complete
// ID: 8A0FC0E1EA10CEEE185C2315B618A95C (SwiftUICore)

package protocol ViewGraphFeature {
mutating func modifyViewInputs(inputs: inout _ViewInputs, graph: ViewGraph)
Expand All @@ -24,3 +25,129 @@ extension ViewGraphFeature {
package mutating func needsUpdate(graph: ViewGraph) -> Bool { false }
package mutating func update(graph: ViewGraph) {}
}

struct ViewGraphFeatureBuffer: Collection {
var contents: UnsafeHeterogeneousBuffer

@discardableResult
mutating func append<Feature>(_ feature: Feature) -> UnsafeHeterogeneousBuffer.Index where Feature: ViewGraphFeature {
contents.append(feature, vtable: _VTable<Feature>.self)
}

subscript<Feature>(_ type: Feature.Type) -> UnsafeMutablePointer<Feature>? where Feature: ViewGraphFeature {
guard !contents.isEmpty else { return nil }
for element in contents {
guard element.hasType(type) else {
continue
}
return element.body(as: type)
}
return nil
}

typealias Index = UnsafeHeterogeneousBuffer.Index

struct Element: ViewGraphFeature {
var base: UnsafeHeterogeneousBuffer.Element

private var vtable: VTable.Type {
base.vtable(as: VTable.self)
}

func modifyViewInputs(inputs: inout _ViewInputs, graph: ViewGraph) {
vtable.modifyViewInputs(elt: base, inputs: &inputs, graph: graph)
}

func modifyViewOutputs(outputs: inout _ViewOutputs, inputs: _ViewInputs, graph: ViewGraph) {
vtable.modifyViewOutputs(elt: base, outputs: &outputs, inputs: inputs, graph: graph)
}

func uninstantiate(graph: ViewGraph) {
vtable.uninstantiate(elt: base, graph: graph)
}

func isHiddenForReuseDidChange(graph: ViewGraph) {
vtable.isHiddenForReuseDidChange(elt: base, graph: graph)
}

func allowsAsyncUpdate(graph: ViewGraph) -> Bool? {
vtable.allowsAsyncUpdate(elt: base, graph: graph)
}

func needsUpdate(graph: ViewGraph) -> Bool {
vtable.needsUpdate(elt: base, graph: graph)
}

func update(graph: ViewGraph) {
vtable.update(elt: base, graph: graph)
}
}

var startIndex: UnsafeHeterogeneousBuffer.Index { contents.startIndex }

var endIndex: UnsafeHeterogeneousBuffer.Index { contents.endIndex }

var isEmpty: Bool { contents.isEmpty }

subscript(position: UnsafeHeterogeneousBuffer.Index) -> Element {
_read { yield Element(base: contents[position]) }
}

func index(after i: UnsafeHeterogeneousBuffer.Index) -> UnsafeHeterogeneousBuffer.Index {
contents.index(after: i)
}

private class VTable: _UnsafeHeterogeneousBuffer_VTable {
class func modifyViewInputs(elt: UnsafeHeterogeneousBuffer.Element, inputs: inout _ViewInputs, graph: ViewGraph) {}
class func modifyViewOutputs(elt: UnsafeHeterogeneousBuffer.Element, outputs: inout _ViewOutputs, inputs: _ViewInputs, graph: ViewGraph) {}
class func uninstantiate(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) {}
class func isHiddenForReuseDidChange(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) {}
class func needsUpdate(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) -> Bool { false }
class func allowsAsyncUpdate(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) -> Bool? { nil }
class func update(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) {}
}

private final class _VTable<Feature>: VTable where Feature: ViewGraphFeature {
override class func hasType<T>(_ type: T.Type) -> Bool {
Feature.self == T.self
}

override class func moveInitialize(elt: UnsafeHeterogeneousBuffer.Element, from: _UnsafeHeterogeneousBuffer_Element) {
let dest = elt.body(as: Feature.self)
let source = from.body(as: Feature.self)
dest.initialize(to: source.move())
}

override class func deinitialize(elt: UnsafeHeterogeneousBuffer.Element) {
elt.body(as: Feature.self).deinitialize(count: 1)
}

override class func modifyViewInputs(elt: UnsafeHeterogeneousBuffer.Element, inputs: inout _ViewInputs, graph: ViewGraph) {
elt.body(as: Feature.self).pointee.modifyViewInputs(inputs: &inputs, graph: graph)
}

override class func modifyViewOutputs(elt: UnsafeHeterogeneousBuffer.Element, outputs: inout _ViewOutputs, inputs: _ViewInputs, graph: ViewGraph) {
elt.body(as: Feature.self).pointee.modifyViewOutputs(outputs: &outputs, inputs: inputs, graph: graph)
}

override class func uninstantiate(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) {
elt.body(as: Feature.self).pointee.uninstantiate(graph: graph)
}

override class func isHiddenForReuseDidChange(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) {
elt.body(as: Feature.self).pointee.isHiddenForReuseDidChange(graph: graph)
}

override class func needsUpdate(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) -> Bool {
elt.body(as: Feature.self).pointee.needsUpdate(graph: graph)
}

override class func allowsAsyncUpdate(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) -> Bool? {
elt.body(as: Feature.self).pointee.allowsAsyncUpdate(graph: graph)
}

override class func update(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) {
elt.body(as: Feature.self).pointee.update(graph: graph)
}
}
}
Loading