Skip to content
Merged
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
194 changes: 164 additions & 30 deletions Sources/OpenSwiftUICore/View/Input/ViewListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// ViewListView.swift
// OpenSwiftUICore
//
// Audited for 6.0.87
// Status: WIP
// ID: 52A2FFECFBCF37BFFEED558E33EBD1E3 (?)
// ID: 9B09D1820E97ECBB666F7560EA2A2D2C (?)
// Audited for 6.5.4
// Status: Complete
// ID: 52A2FFECFBCF37BFFEED558E33EBD1E3 (SwiftUI?)
// ID: 9B09D1820E97ECBB666F7560EA2A2D2C (SwiftUICore?)

package import OpenAttributeGraphShims

Expand All @@ -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
Expand All @@ -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
}

Expand All @@ -35,29 +35,83 @@ package struct _ViewList_Backing {
package func visitViews<V>(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<V>(applying v: inout V) where V: ViewListVisitor {
_openSwiftUIUnimplementedFailure()
package func visitAll<V>(
applying v: inout V
) where V: ViewListVisitor {
var start = 0
_ = visitViews(applying: &v, from: &start)
}

package func visitViews<V>(applying v: inout V, from start: Int) where V: ViewListVisitor {
_openSwiftUIUnimplementedFailure()
package func visitViews<V>(
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)
index &+= 1
} while count != index
}
return true
}
return ids
}
}
}

// MARK: - _ViewList.View
// MARK: - ViewList.View

extension ViewList {
package typealias View = _ViewList_View
Expand Down Expand Up @@ -113,23 +167,34 @@ package struct _ViewList_View: PrimitiveView, View, UnaryView {
}
}

package var subviewID: ViewList.ID {
id.elementID(at: index)
}

nonisolated package static func _makeView(
view: _GraphValue<Self>,
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
Expand All @@ -148,8 +213,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!
}

Expand All @@ -159,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 {
Expand Down Expand Up @@ -196,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
Expand All @@ -208,17 +319,40 @@ 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
}
}

// MARK: - PlaceholderViewPhase

private struct PlaceholderViewPhase: Rule, AsyncAttribute {
@Attribute var phase1: _GraphInputs.Phase
@Attribute var phase2: _GraphInputs.Phase
Expand Down