Skip to content

Commit f88e420

Browse files
committed
Add ViewGraphFeatureBuffer
1 parent 229b5e6 commit f88e420

File tree

2 files changed

+146
-8
lines changed

2 files changed

+146
-8
lines changed

Sources/OpenSwiftUICore/View/Graph/ViewGraph.swift

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ package final class ViewGraph: GraphHost {
4848

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

51-
// private var features: ViewGraphFeaturesBuffer = .init()
51+
private var features: ViewGraphFeatureBuffer = .init(contents: .init())
5252

5353
package var centersRootView: Bool = true
5454

@@ -183,15 +183,20 @@ package final class ViewGraph: GraphHost {
183183
deinit {
184184
// FIXME
185185
removePreferenceOutlets(isInvalidating: true)
186+
features.contents.destroy()
186187
}
187188

188189
override package var graphDelegate: GraphDelegate? { delegate }
189190

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

192-
// TODO: ViewGraphFeature
193-
// package func append<T>(feature: T) where T: ViewGraphFeature
194-
// package subscript<T>(feature: T.Type) -> UnsafeMutablePointer<T>? where T: ViewGraphFeature
193+
package func append<T>(feature: T) where T: ViewGraphFeature {
194+
features.append(feature)
195+
}
196+
197+
package subscript<T>(feature: T.Type) -> UnsafeMutablePointer<T>? where T: ViewGraphFeature {
198+
features[feature]
199+
}
195200

196201
override package func instantiateOutputs() {
197202
#if canImport(Darwin)
@@ -231,9 +236,13 @@ package final class ViewGraph: GraphHost {
231236
) { rootGeometry in
232237
rootGeometry.$layoutDirection = inputs.mapEnvironment(\.layoutDirection)
233238
}
234-
// TODO: features related
235-
let outputs = makeRootView(rootView, inputs)
236-
// TODO: features related
239+
for feature in features {
240+
feature.modifyViewInputs(inputs: &inputs, graph: self)
241+
}
242+
var outputs = makeRootView(rootView, inputs)
243+
for feature in features {
244+
feature.modifyViewOutputs(outputs: &outputs, inputs: inputs, graph: self)
245+
}
237246
return outputs
238247
}
239248
$rootGeometry.mutateBody(
@@ -263,7 +272,9 @@ package final class ViewGraph: GraphHost {
263272
override package func uninstantiateOutputs() {
264273
#if canImport(Darwin)
265274
removePreferenceOutlets(isInvalidating: false)
266-
// TODO: features
275+
for feature in features {
276+
feature.uninstantiate(graph: self)
277+
}
267278
$rootGeometry.mutateBody(
268279
as: RootGeometry.self,
269280
invalidating: true

Sources/OpenSwiftUICore/View/Graph/ViewGraphFeature.swift

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//
55
// Audited for iOS 18.0
66
// Status: Complete
7+
// ID: 8A0FC0E1EA10CEEE185C2315B618A95C (SwiftUICore)
78

89
package protocol ViewGraphFeature {
910
mutating func modifyViewInputs(inputs: inout _ViewInputs, graph: ViewGraph)
@@ -24,3 +25,129 @@ extension ViewGraphFeature {
2425
package mutating func needsUpdate(graph: ViewGraph) -> Bool { false }
2526
package mutating func update(graph: ViewGraph) {}
2627
}
28+
29+
struct ViewGraphFeatureBuffer: Collection {
30+
var contents: UnsafeHeterogeneousBuffer
31+
32+
@discardableResult
33+
mutating func append<Feature>(_ feature: Feature) -> UnsafeHeterogeneousBuffer.Index where Feature: ViewGraphFeature {
34+
contents.append(feature, vtable: _VTable<Feature>.self)
35+
}
36+
37+
subscript<Feature>(_ type: Feature.Type) -> UnsafeMutablePointer<Feature>? where Feature: ViewGraphFeature {
38+
guard !contents.isEmpty else { return nil }
39+
for element in contents {
40+
guard element.hasType(type) else {
41+
continue
42+
}
43+
return element.body(as: type)
44+
}
45+
return nil
46+
}
47+
48+
typealias Index = UnsafeHeterogeneousBuffer.Index
49+
50+
struct Element: ViewGraphFeature {
51+
var base: UnsafeHeterogeneousBuffer.Element
52+
53+
private var vtable: VTable.Type {
54+
base.vtable(as: VTable.self)
55+
}
56+
57+
func modifyViewInputs(inputs: inout _ViewInputs, graph: ViewGraph) {
58+
vtable.modifyViewInputs(elt: base, inputs: &inputs, graph: graph)
59+
}
60+
61+
func modifyViewOutputs(outputs: inout _ViewOutputs, inputs: _ViewInputs, graph: ViewGraph) {
62+
vtable.modifyViewOutputs(elt: base, outputs: &outputs, inputs: inputs, graph: graph)
63+
}
64+
65+
func uninstantiate(graph: ViewGraph) {
66+
vtable.uninstantiate(elt: base, graph: graph)
67+
}
68+
69+
func isHiddenForReuseDidChange(graph: ViewGraph) {
70+
vtable.isHiddenForReuseDidChange(elt: base, graph: graph)
71+
}
72+
73+
func allowsAsyncUpdate(graph: ViewGraph) -> Bool? {
74+
vtable.allowsAsyncUpdate(elt: base, graph: graph)
75+
}
76+
77+
func needsUpdate(graph: ViewGraph) -> Bool {
78+
vtable.needsUpdate(elt: base, graph: graph)
79+
}
80+
81+
func update(graph: ViewGraph) {
82+
vtable.update(elt: base, graph: graph)
83+
}
84+
}
85+
86+
var startIndex: UnsafeHeterogeneousBuffer.Index { contents.startIndex }
87+
88+
var endIndex: UnsafeHeterogeneousBuffer.Index { contents.endIndex }
89+
90+
var isEmpty: Bool { contents.isEmpty }
91+
92+
subscript(position: UnsafeHeterogeneousBuffer.Index) -> Element {
93+
_read { yield Element(base: contents[position]) }
94+
}
95+
96+
func index(after i: UnsafeHeterogeneousBuffer.Index) -> UnsafeHeterogeneousBuffer.Index {
97+
contents.index(after: i)
98+
}
99+
100+
private class VTable: _UnsafeHeterogeneousBuffer_VTable {
101+
class func modifyViewInputs(elt: UnsafeHeterogeneousBuffer.Element, inputs: inout _ViewInputs, graph: ViewGraph) {}
102+
class func modifyViewOutputs(elt: UnsafeHeterogeneousBuffer.Element, outputs: inout _ViewOutputs, inputs: _ViewInputs, graph: ViewGraph) {}
103+
class func uninstantiate(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) {}
104+
class func isHiddenForReuseDidChange(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) {}
105+
class func needsUpdate(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) -> Bool { false }
106+
class func allowsAsyncUpdate(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) -> Bool? { nil }
107+
class func update(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) {}
108+
}
109+
110+
private final class _VTable<Feature>: VTable where Feature: ViewGraphFeature {
111+
override class func hasType<T>(_ type: T.Type) -> Bool {
112+
Feature.self == T.self
113+
}
114+
115+
override class func moveInitialize(elt: UnsafeHeterogeneousBuffer.Element, from: _UnsafeHeterogeneousBuffer_Element) {
116+
let dest = elt.body(as: Feature.self)
117+
let source = from.body(as: Feature.self)
118+
dest.initialize(to: source.move())
119+
}
120+
121+
override class func deinitialize(elt: UnsafeHeterogeneousBuffer.Element) {
122+
elt.body(as: Feature.self).deinitialize(count: 1)
123+
}
124+
125+
override class func modifyViewInputs(elt: UnsafeHeterogeneousBuffer.Element, inputs: inout _ViewInputs, graph: ViewGraph) {
126+
elt.body(as: Feature.self).pointee.modifyViewInputs(inputs: &inputs, graph: graph)
127+
}
128+
129+
override class func modifyViewOutputs(elt: UnsafeHeterogeneousBuffer.Element, outputs: inout _ViewOutputs, inputs: _ViewInputs, graph: ViewGraph) {
130+
elt.body(as: Feature.self).pointee.modifyViewOutputs(outputs: &outputs, inputs: inputs, graph: graph)
131+
}
132+
133+
override class func uninstantiate(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) {
134+
elt.body(as: Feature.self).pointee.uninstantiate(graph: graph)
135+
}
136+
137+
override class func isHiddenForReuseDidChange(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) {
138+
elt.body(as: Feature.self).pointee.isHiddenForReuseDidChange(graph: graph)
139+
}
140+
141+
override class func needsUpdate(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) -> Bool {
142+
elt.body(as: Feature.self).pointee.needsUpdate(graph: graph)
143+
}
144+
145+
override class func allowsAsyncUpdate(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) -> Bool? {
146+
elt.body(as: Feature.self).pointee.allowsAsyncUpdate(graph: graph)
147+
}
148+
149+
override class func update(elt: UnsafeHeterogeneousBuffer.Element, graph: ViewGraph) {
150+
elt.body(as: Feature.self).pointee.update(graph: graph)
151+
}
152+
}
153+
}

0 commit comments

Comments
 (0)