From b632e54d00a7f023fd8e68d87ec319049c3ecc04 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 26 Oct 2025 15:05:04 +0800 Subject: [PATCH 1/3] Update ViewList.Backing implementation --- .../View/Input/ViewListView.swift | 81 ++++++++++++++++--- 1 file changed, 69 insertions(+), 12 deletions(-) diff --git a/Sources/OpenSwiftUICore/View/Input/ViewListView.swift b/Sources/OpenSwiftUICore/View/Input/ViewListView.swift index 990edd9a..8d821496 100644 --- a/Sources/OpenSwiftUICore/View/Input/ViewListView.swift +++ b/Sources/OpenSwiftUICore/View/Input/ViewListView.swift @@ -2,7 +2,7 @@ // ViewListView.swift // OpenSwiftUICore // -// Audited for 6.0.87 +// Audited for 6.5.4 // Status: WIP // ID: 52A2FFECFBCF37BFFEED558E33EBD1E3 (?) // ID: 9B09D1820E97ECBB666F7560EA2A2D2C (?) @@ -15,7 +15,7 @@ package protocol ViewListVisitor { mutating func visit(view: ViewList.View, traits: ViewTraitCollection) -> Bool } -// MARK: - ViewList.Backing [WIP] +// MARK: - ViewList.Backing extension ViewList { package typealias Backing = _ViewList_Backing @@ -24,7 +24,7 @@ extension ViewList { package struct _ViewList_Backing { package var children: _VariadicView.Children - package var viewCount: Swift.Int { + package var viewCount: Int { children.list.count } @@ -35,29 +35,82 @@ package struct _ViewList_Backing { package func visitViews(applying v: inout V, from start: inout Int) -> Bool where V: ViewListVisitor { Update.ensure { children.list.applySublists(from: &start, list: nil) { sublist in - _openSwiftUIUnimplementedFailure() + var index = sublist.start + let count = sublist.count + if index < count { + repeat { + let view = ViewList.View( + elements: sublist.elements, + id: sublist.id, + index: index, + count: count, + contentSubgraph: children.contentSubgraph + ) + guard v.visit(view: view, traits: sublist.traits) else { + return false + } + index &+= 1 + } while count != index + } + return true } } } } extension ViewList.Backing { - package func visitAll(applying v: inout V) where V: ViewListVisitor { - _openSwiftUIUnimplementedFailure() + package func visitAll( + applying v: inout V + ) where V: ViewListVisitor { + var start = 0 + _ = visitViews(applying: &v, from: &start) } - package func visitViews(applying v: inout V, from start: Int) where V: ViewListVisitor { - _openSwiftUIUnimplementedFailure() + package func visitViews( + applying v: inout V, + from start: Int + ) where V: ViewListVisitor { + var start = start + _ = visitViews(applying: &v, from: &start) } } extension ViewList.Backing { package var ids: [AnyHashable] { - _openSwiftUIUnimplementedFailure() + Update.ensure { + var start = 0 + var ids: [AnyHashable] = [] + children.list.applySublists(from: &start, list: nil) { sublist in + var index = sublist.start + let count = sublist.count + if index < count { + repeat { + Swift.assert(index < count) + let view = ViewList.View( + elements: sublist.elements, + id: sublist.id, + index: index, + count: count, + contentSubgraph: children.contentSubgraph + ) + let canonicalID = view.id.canonicalID + let id: AnyHashable + if let explicitID = canonicalID.explicitID { + id = AnyHashable(explicitID.anyValue) + } else { + id = AnyHashable(canonicalID) + } + ids.append(id) + } while count != index + } + return true + } + return ids + } } } -// MARK: - _ViewList.View +// MARK: - ViewList.View extension ViewList { package typealias View = _ViewList_View @@ -113,6 +166,10 @@ package struct _ViewList_View: PrimitiveView, View, UnaryView { } } + package var subviewID: ViewList.ID { + id.elementID(at: index) + } + nonisolated package static func _makeView( view: _GraphValue, inputs: _ViewInputs @@ -148,8 +205,6 @@ private struct PlaceholderInfo: StatefulRule, ObservedAttribute, AsyncAttribute self._placeholder = placeholder self.inputs = inputs self.outputs = outputs - // FIXME: The Subgraph.current call on the init default value or the call site will trigger a compiler crash (SIL -> IR) on Release build - // We workaround it by setting it to .current here self.parentSubgraph = .current! } @@ -219,6 +274,8 @@ private struct PlaceholderInfo: StatefulRule, ObservedAttribute, AsyncAttribute } } +// MARK: - PlaceholderViewPhase + private struct PlaceholderViewPhase: Rule, AsyncAttribute { @Attribute var phase1: _GraphInputs.Phase @Attribute var phase2: _GraphInputs.Phase From 75fb603a7319d08f8da8cf50ef527de2ce3e526f Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 26 Oct 2025 17:00:47 +0800 Subject: [PATCH 2/3] Update ViewListView --- .../View/Input/ViewListView.swift | 113 +++++++++++++++--- 1 file changed, 95 insertions(+), 18 deletions(-) diff --git a/Sources/OpenSwiftUICore/View/Input/ViewListView.swift b/Sources/OpenSwiftUICore/View/Input/ViewListView.swift index 8d821496..992820e2 100644 --- a/Sources/OpenSwiftUICore/View/Input/ViewListView.swift +++ b/Sources/OpenSwiftUICore/View/Input/ViewListView.swift @@ -3,9 +3,9 @@ // OpenSwiftUICore // // Audited for 6.5.4 -// Status: WIP -// ID: 52A2FFECFBCF37BFFEED558E33EBD1E3 (?) -// ID: 9B09D1820E97ECBB666F7560EA2A2D2C (?) +// Status: Complete +// ID: 52A2FFECFBCF37BFFEED558E33EBD1E3 (SwiftUI?) +// ID: 9B09D1820E97ECBB666F7560EA2A2D2C (SwiftUICore?) package import OpenAttributeGraphShims @@ -101,6 +101,7 @@ extension ViewList.Backing { id = AnyHashable(canonicalID) } ids.append(id) + index &+= 1 } while count != index } return true @@ -175,18 +176,25 @@ package struct _ViewList_View: PrimitiveView, View, UnaryView { inputs: _ViewInputs ) -> _ViewOutputs { let outputs = inputs.makeIndirectOutputs() - let placeholderInfo = PlaceholderInfo( - placeholder: view.value, - inputs: inputs, - outputs: outputs + let placeholderInfo = Attribute( + PlaceholderInfo( + placeholder: view.value, + inputs: inputs, + outputs: outputs + ) ) - let attribute = Attribute(placeholderInfo) - outputs.setIndirectDependency(attribute.identifier) + outputs.setIndirectDependency(placeholderInfo.identifier) return outputs } } -// MARK: - PlaceholderInfo [WIP] +// MARK: - ViewListShouldParentToPlaceholderSubgraph + +package struct ViewListShouldParentToPlaceholderSubgraph: GraphInput { + package static let defaultValue: Bool = true +} + +// MARK: - PlaceholderInfo private struct PlaceholderInfo: StatefulRule, ObservedAttribute, AsyncAttribute { @Attribute var placeholder: ViewList.View @@ -214,8 +222,57 @@ private struct PlaceholderInfo: StatefulRule, ObservedAttribute, AsyncAttribute var index: Int } - func makeItem(placeholder: ViewList.View, seed: UInt32) -> Value { - _openSwiftUIUnimplementedFailure() + mutating func makeItem(placeholder: ViewList.View, seed: UInt32) -> Value { + guard let contentSubgraph = placeholder.contentSubgraph, + contentSubgraph.isValid else { + return .init(id: .init(), seed: seed, index: .min) + } + let child = Subgraph(graph: parentSubgraph.graph) + parentSubgraph.addChild(child) + let shouldParentToPlaceholder = inputs.base[ViewListShouldParentToPlaceholderSubgraph.self] + if parentSubgraph != contentSubgraph, shouldParentToPlaceholder { + contentSubgraph.addChild(child, tag: 1) + } + child.apply { + // TODO: GraphReuseOptions on v7 + let indirectMap = IndirectAttributeMap(subgraph: child) + let elementOutputs = placeholder.elements.makeOneElement( + at: placeholder.index, + inputs: inputs, + indirectMap: indirectMap + ) { elementInputs, makeElement in + lastPhase = Attribute(PlaceholderViewPhase( + phase1: elementInputs.viewPhase, + phase2: inputs.viewPhase, + resetDelta: .zero + )) + var newInputs = elementInputs + newInputs.base[ViewListShouldParentToPlaceholderSubgraph.self] = true + newInputs.copyCaches() + newInputs.base.changedDebugProperties.formUnion([.transform, .position, .size]) + newInputs.base.merge(inputs.base, ignoringPhase: true) + newInputs.base.mergedInputs.insert(lastPhase!.identifier) + return makeElement(newInputs) + } + elementOutputs.map { + outputs.attachIndirectOutputs(to: $0) + } + lastMap = indirectMap + } + lastSubgraph = child + lastRelease = placeholder.elements.retain() + lastElements = placeholder.elements + if contentSubgraph.graph != child.graph { + let token = contentSubgraph.addObserver { [parentSubgraph, attribute] in + guard parentSubgraph.isValid else { return } + let infoPointer = UnsafeMutableRawPointer(mutating: attribute.identifier._bodyPointer) + .assumingMemoryBound(to: Self.self) + infoPointer.pointee.contentObserver = nil + infoPointer.pointee.eraseItem() + } + contentObserver = (contentSubgraph, token) + } + return Value(id: placeholder.id, seed: seed, index: placeholder.index) } mutating func reuseItem(info: inout Value, placeholder: ViewList.View) -> Bool { @@ -251,8 +308,7 @@ private struct PlaceholderInfo: StatefulRule, ObservedAttribute, AsyncAttribute self.lastSubgraph = nil } if let contentObserver { - // TODO: OSubgraphRemoveObserver - // contentObserver.0.removeObserver(contentObserver.1) + contentObserver.0.removeObserver(contentObserver.1) self.contentObserver = nil } lastRelease = nil @@ -263,14 +319,35 @@ private struct PlaceholderInfo: StatefulRule, ObservedAttribute, AsyncAttribute } mutating func updateValue() { - _openSwiftUIUnimplementedFailure() + guard hasValue else { + if lastSubgraph != nil { + eraseItem() + } + value = makeItem(placeholder: placeholder, seed: 0) + return + } + if value.index != placeholder.index || value.id == placeholder.id { + let newValue: Value + if reuseItem(info: &value, placeholder: placeholder) { + newValue = value + } else { + let seed = value.seed &+ 1 + if lastSubgraph != nil { + eraseItem() + } + newValue = makeItem(placeholder: placeholder, seed: seed) + } + value = newValue + } } - func destroy() { + mutating func destroy() { if let contentObserver { - // TODO: OSubgraphRemoveObserver - // contentObserver.0.removeObserver(contentObserver.1) + contentObserver.0.removeObserver(contentObserver.1) + self.contentObserver = nil } + lastRelease = nil + secondaryRelease = nil } } From d9cca692d50d70fb618bb6e6b288c1c36a8981db Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 26 Oct 2025 17:13:11 +0800 Subject: [PATCH 3/3] Fix == check for Subgraph and Graph on Linux build --- Sources/OpenSwiftUICore/View/Input/ViewListView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/OpenSwiftUICore/View/Input/ViewListView.swift b/Sources/OpenSwiftUICore/View/Input/ViewListView.swift index 992820e2..097ffb98 100644 --- a/Sources/OpenSwiftUICore/View/Input/ViewListView.swift +++ b/Sources/OpenSwiftUICore/View/Input/ViewListView.swift @@ -230,7 +230,7 @@ private struct PlaceholderInfo: StatefulRule, ObservedAttribute, AsyncAttribute let child = Subgraph(graph: parentSubgraph.graph) parentSubgraph.addChild(child) let shouldParentToPlaceholder = inputs.base[ViewListShouldParentToPlaceholderSubgraph.self] - if parentSubgraph != contentSubgraph, shouldParentToPlaceholder { + if parentSubgraph !== contentSubgraph, shouldParentToPlaceholder { contentSubgraph.addChild(child, tag: 1) } child.apply { @@ -262,7 +262,7 @@ private struct PlaceholderInfo: StatefulRule, ObservedAttribute, AsyncAttribute lastSubgraph = child lastRelease = placeholder.elements.retain() lastElements = placeholder.elements - if contentSubgraph.graph != child.graph { + if contentSubgraph.graph !== child.graph { let token = contentSubgraph.addObserver { [parentSubgraph, attribute] in guard parentSubgraph.isValid else { return } let infoPointer = UnsafeMutableRawPointer(mutating: attribute.identifier._bodyPointer)