diff --git a/Sources/OpenSwiftUI/CoreGlue/OpenSwiftUIGlue.swift b/Sources/OpenSwiftUI/CoreGlue/OpenSwiftUIGlue.swift index e8f8d57d..7ef5405d 100644 --- a/Sources/OpenSwiftUI/CoreGlue/OpenSwiftUIGlue.swift +++ b/Sources/OpenSwiftUI/CoreGlue/OpenSwiftUIGlue.swift @@ -17,6 +17,10 @@ public func OpenSwiftUIGlueClass() -> CoreGlue.Type { } final class OpenSwiftUIGlue: CoreGlue { + override var defaultImplicitRootType: DefaultImplicitRootTypeResult { + DefaultImplicitRootTypeResult(_VStackLayout.self) + } + override func makeDefaultLayoutComputer() -> MakeDefaultLayoutComputerResult { MakeDefaultLayoutComputerResult(value: ViewGraph.current.$defaultLayoutComputer) } diff --git a/Sources/OpenSwiftUICore/CoreGlue/CoreGlue.swift b/Sources/OpenSwiftUICore/CoreGlue/CoreGlue.swift index e3092857..fa9872c0 100644 --- a/Sources/OpenSwiftUICore/CoreGlue/CoreGlue.swift +++ b/Sources/OpenSwiftUICore/CoreGlue/CoreGlue.swift @@ -15,7 +15,11 @@ import OpenSwiftUI_SPI @objc(OpenSwiftUICoreGlue) open class CoreGlue: NSObject { package static var shared: CoreGlue = _initializeCoreGlue() as! CoreGlue - + + open var defaultImplicitRootType: DefaultImplicitRootTypeResult { + preconditionFailure("") + } + open func makeDefaultLayoutComputer() -> MakeDefaultLayoutComputerResult { preconditionFailure("") } @@ -23,6 +27,14 @@ open class CoreGlue: NSObject { @_spi(ForOpenSwiftUIOnly) extension CoreGlue { + public struct DefaultImplicitRootTypeResult { + package var value: any _VariadicView.AnyImplicitRoot.Type + + package init(_ value: any _VariadicView.AnyImplicitRoot.Type) { + self.value = value + } + } + public struct MakeDefaultLayoutComputerResult { package var value: Attribute diff --git a/Sources/OpenSwiftUICore/Modifier/CustomViewModifier.swift b/Sources/OpenSwiftUICore/Modifier/CustomViewModifier.swift index 374d16ae..e476ebf3 100644 --- a/Sources/OpenSwiftUICore/Modifier/CustomViewModifier.swift +++ b/Sources/OpenSwiftUICore/Modifier/CustomViewModifier.swift @@ -187,7 +187,7 @@ extension ViewModifierContentProvider { return makeViewBody(_Graph(), inputs) case let .list(makeViewListBody): return .multiView(inputs: inputs) { - makeViewListBody($0, .init($1.base, options: graphInputs[ViewListOptionsInput.self])) + makeViewListBody($0, .init($1.base, options: graphInputs.viewListOptions)) } } } diff --git a/Sources/OpenSwiftUICore/View/CustomView.swift b/Sources/OpenSwiftUICore/View/CustomView.swift index cd44fdae..7e2ce3fc 100644 --- a/Sources/OpenSwiftUICore/View/CustomView.swift +++ b/Sources/OpenSwiftUICore/View/CustomView.swift @@ -2,8 +2,8 @@ // CustomView.swift // OpenSwiftUICore // -// Audited for iOS 15.5 -// Status: WIP +// Audited for iOS 18.0 +// Status: Complete // ID: 9F92ACD17B554E8AB7D29ABB1E796415 (SwiftUI) // ID: CE1D93D8ECBBEB5FE2E32E69A123E7CB (SwiftUICore) @@ -26,17 +26,10 @@ extension View { let fields = DynamicPropertyCache.fields(of: Self.self) var inputs = inputs let (body, buffer) = makeBody(view: view, inputs: &inputs.base, fields: fields) - // FIXME - let outputs = _ViewDebug.makeView( - view: body, - inputs: inputs - ) { view, inputs in - Body._makeView(view: body, inputs: inputs) - } if let buffer { buffer.traceMountedProperties(to: body, fields: fields) } - return outputs + return Body.makeDebuggableView(view: body, inputs: inputs) } nonisolated package static func makeViewList(view: _GraphValue, inputs: _ViewListInputs) -> _ViewListOutputs { diff --git a/Sources/OpenSwiftUICore/View/DynamicViewContent.swift b/Sources/OpenSwiftUICore/View/DynamicViewContent.swift index eed6b9d8..bbc4badf 100644 --- a/Sources/OpenSwiftUICore/View/DynamicViewContent.swift +++ b/Sources/OpenSwiftUICore/View/DynamicViewContent.swift @@ -33,7 +33,7 @@ package struct DynamicViewContentOffsetTraitKey: _ViewTraitKey { package struct DynamicContentOffsetVisitor: ViewListVisitor { package var offset: Int? - package mutating func visit(view: _ViewList_View, traits: ViewTraitCollection) -> Bool { + package mutating func visit(view: ViewList.View, traits: ViewTraitCollection) -> Bool { offset = traits.value(for: DynamicViewContentOffsetTraitKey.self) return false } diff --git a/Sources/OpenSwiftUICore/View/IDView.swift b/Sources/OpenSwiftUICore/View/IDView.swift index 6454b5a6..a05c271a 100644 --- a/Sources/OpenSwiftUICore/View/IDView.swift +++ b/Sources/OpenSwiftUICore/View/IDView.swift @@ -53,16 +53,15 @@ extension View { extension IDView { @usableFromInline package static func _makeView(view: _GraphValue, inputs: _ViewInputs) -> _ViewOutputs { - // Disable SemanticFeature_v2 temporary as makeImplicitRoot has not been implemented yet -// if _SemanticFeature_v2.isEnabled { -// return makeImplicitRoot(view: view, inputs: inputs) -// } else { - let id = view.value[offset:{ .of(&$0.id) }] + if _SemanticFeature_v2.isEnabled { + return makeImplicitRoot(view: view, inputs: inputs) + } else { + let id = view.value[offset: { .of(&$0.id) }] let phase = IDPhase(id: id, phase: inputs.viewPhase, lastID: nil, delta: 0) var inputs = inputs inputs.viewPhase = Attribute(phase) return Content.makeDebuggableView(view: view[offset: { .of(&$0.content)}], inputs: inputs) -// } + } } } diff --git a/Sources/OpenSwiftUICore/View/Input/ViewList.swift b/Sources/OpenSwiftUICore/View/Input/ViewList.swift index 5cea4005..ba3bc333 100644 --- a/Sources/OpenSwiftUICore/View/Input/ViewList.swift +++ b/Sources/OpenSwiftUICore/View/Input/ViewList.swift @@ -15,6 +15,7 @@ package import OpenGraphShims /// Input values to `View._makeViewList()`. public struct _ViewListInputs { package var base: _GraphInputs + package var implicitID: Int package struct Options: OptionSet { @@ -746,7 +747,7 @@ extension ViewList.Elements { } } -// MARK: - View.List.ID +// MARK: - ViewList.ID @_spi(ForOpenSwiftUIOnly) public struct _ViewList_ID: Hashable { @@ -1950,21 +1951,3 @@ final package class _ViewList_ReleaseElements: Equatable { return lhsBase == rhsBase } } - -// FIXME: VariadicView Part - -// MARK: - _ViewList_View - -package struct _ViewList_View { - var elements: any ViewList.Elements - var id: _ViewList_ID - var index: Int - var count: Int - var contentSubgraph: Subgraph -} - -// MARK: - ViewListVisitor - -protocol ViewListVisitor { - mutating func visit(view: _ViewList_View, traits: ViewTraitCollection) -> Bool -} diff --git a/Sources/OpenSwiftUICore/View/Variadic/VariadicView.swift b/Sources/OpenSwiftUICore/View/Variadic/VariadicView.swift deleted file mode 100644 index 48813cbd..00000000 --- a/Sources/OpenSwiftUICore/View/Variadic/VariadicView.swift +++ /dev/null @@ -1,49 +0,0 @@ -/// A type of structured content that is passed as an argument to a -/// `Root`'s result builder, creating a `Tree` that conditionally conforms -/// to protocols like `View`. -/// -/// For example, `View`s can be passed to a `Layout` result builder -/// creating a `View`: -/// -/// HStack { -/// Image(name: "envelope") -/// Text("Your time away request has been approved") -/// Spacer() -/// Text(timestamp, format: .dateTime).layoutPriority(1) -/// } -/// -public enum _VariadicView { - public typealias Root = _VariadicView_Root - public typealias ViewRoot = _VariadicView_ViewRoot - public typealias Children = _VariadicView_Children -// public typealias UnaryViewRoot = _VariadicView_UnaryViewRoot -// public typealias MultiViewRoot = _VariadicView_MultiViewRoot - - @frozen - public struct Tree { - public var root: Root - public var content: Content - @inlinable - init(root: Root, content: Content) { - self.root = root - self.content = content - } - - @inlinable public init(_ root: Root, @ViewBuilder content: () -> Content) { - self.root = root - self.content = content() - } - } -} - -extension _VariadicView_ViewRoot { - func bodyError() -> Never { - preconditionFailure("body() should not be called on \(Self.self)") - } -} - -extension _VariadicView_ViewRoot where Body == Never { - public func body(children: _VariadicView.Children) -> Never { - bodyError() - } -} diff --git a/Sources/OpenSwiftUICore/View/Variadic/VariadicView_Children.swift b/Sources/OpenSwiftUICore/View/Variadic/VariadicView_Children.swift deleted file mode 100644 index e2206eec..00000000 --- a/Sources/OpenSwiftUICore/View/Variadic/VariadicView_Children.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// VariadicView_Children.swift -// OpenSwiftUI -// -// Audited for iOS 15.5 -// Status: TODO -// ID: 52A2FFECFBCF37BFFEED558E33EBD1E3 - -import OpenGraphShims - -/// An ad hoc collection of the children of a variadic view. -public struct _VariadicView_Children { - var list: ViewList - var contentSubgraph: OGSubgraph -} - -extension _VariadicView_Children: RandomAccessCollection { - public struct Element: PrimitiveView, UnaryView, Identifiable { - -// var view: _ViewList_View - var traits: ViewTraitCollection - - public var id: AnyHashable { -// view.viewID - preconditionFailure("TODO") - - } - public func id(as _: ID.Type = ID.self) -> ID? where ID : Hashable { - preconditionFailure("TODO") - } - - public subscript(key: Trait.Type) -> Trait.Value { - get { traits[key] } - set { traits[key] = newValue } - } - - public static func _makeView(view: _GraphValue<_VariadicView_Children.Element>, inputs: _ViewInputs) -> _ViewOutputs { - preconditionFailure("TODO") - } - } - - public var startIndex: Int { - preconditionFailure("TODO") - -// get - } - public var endIndex: Int { - preconditionFailure("TODO") - -// get - } - public subscript(index: Int) -> _VariadicView_Children.Element { - preconditionFailure("TODO") - -// get - } -} - -extension _VariadicView_Children { - private struct Child: Rule, AsyncAttribute { - typealias Value = ForEach<_VariadicView_Children, AnyHashable, _VariadicView_Children.Element> - - @Attribute var children: _VariadicView_Children - - var value: Value { - preconditionFailure("TODO") - } - } -} diff --git a/Sources/OpenSwiftUICore/View/Variadic/VariadicView_ImplicitRoot.swift b/Sources/OpenSwiftUICore/View/Variadic/VariadicView_ImplicitRoot.swift deleted file mode 100644 index 888c4bc6..00000000 --- a/Sources/OpenSwiftUICore/View/Variadic/VariadicView_ImplicitRoot.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// VariadicView_ImplicitRoot.swift -// OpenSwiftUI -// -// Audited for iOS 15.5 -// Status: Complete - -package protocol _VariadicView_AnyImplicitRoot { - static func visitType(visitor: inout V) where V: _VariadicView_ImplicitRootVisitor -} - -package protocol _VariadicView_ImplicitRootVisitor { - mutating func visit(type: R.Type) where R: _VariadicView_ImplicitRoot -} - -package protocol _VariadicView_ImplicitRoot: _VariadicView_AnyImplicitRoot, _VariadicView_ViewRoot { - static var implicitRoot: Self { get } -} - -extension _VariadicView_ImplicitRoot { - package static func visitType(visitor: inout V) where V: _VariadicView_ImplicitRootVisitor { - visitor.visit(type: Self.self) - } -} diff --git a/Sources/OpenSwiftUICore/View/Variadic/VariadicView_Root.swift b/Sources/OpenSwiftUICore/View/Variadic/VariadicView_Root.swift deleted file mode 100644 index 5b719280..00000000 --- a/Sources/OpenSwiftUICore/View/Variadic/VariadicView_Root.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// VariadicView_ImplicitRoot.swift -// OpenSwiftUI -// -// Audited for iOS 15.5 -// Status: Complete - -/// A type that creates a `Tree`, managing content subtrees passed to a result builder. -/// -/// - SeeAlso: _VariadicView.Root. -public protocol _VariadicView_Root { - static var _viewListOptions: Int { get } -} - -extension _VariadicView_Root { - public static var _viewListOptions: Int { - 0 - } - - package static var viewListOptions: _ViewListInputs.Options { - .init(rawValue: _viewListOptions) - } - - public static func _viewListCount( - inputs _: _ViewListCountInputs, - body _: (_ViewListCountInputs) -> Int? - ) -> Int? { - nil - } -} diff --git a/Sources/OpenSwiftUICore/View/Variadic/VariadicView_ViewRoot.swift b/Sources/OpenSwiftUICore/View/Variadic/VariadicView_ViewRoot.swift deleted file mode 100644 index da987d89..00000000 --- a/Sources/OpenSwiftUICore/View/Variadic/VariadicView_ViewRoot.swift +++ /dev/null @@ -1,103 +0,0 @@ -// -// VariadicView_ImplicitRoot.swift -// OpenSwiftUI -// -// Audited for iOS 15.5 -// Status: WIP -// ID: 00F12C0E37A19C593ECA0DBD3BE26541 - -import OpenGraphShims - -/// A type of root that creates a `View` when its result builder is invoked with -/// `View`. -/// - SeeAlso: _VariadicView.ViewRoot. -/// - Note: Requirements mirror `View`'s. -public protocol _VariadicView_ViewRoot: _VariadicView_Root { - associatedtype Body: View - - static func _makeView( - root: _GraphValue, - inputs: _ViewInputs, - body: (_Graph, _ViewInputs) -> _ViewListOutputs - ) -> _ViewOutputs - - static func _makeViewList( - root: _GraphValue, - inputs: _ViewListInputs, - body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs - ) -> _ViewListOutputs - - static func _viewListCount( - inputs: _ViewListCountInputs, - body: (_ViewListCountInputs) -> Int? - ) -> Int? - - @ViewBuilder - func body(children: _VariadicView.Children) -> Body -} - -extension _VariadicView_ViewRoot { - public static func _makeView( - root: _GraphValue, - inputs: _ViewInputs, - body: (_Graph, _ViewInputs) -> _ViewListOutputs - ) -> _ViewOutputs { - preconditionFailure("TODO") - } - - public static func _makeViewList( - root: _GraphValue, - inputs: _ViewListInputs, - body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs - ) -> _ViewListOutputs { - preconditionFailure("TODO") - } - - public static func _viewListCount(inputs: _ViewListCountInputs) -> Int? { - Body._viewListCount(inputs: inputs) - } -} - - -// MARK: - ViewRootBody - -private struct ViewRootBody { - @Attribute var root: Root - @Attribute var list: ViewList - let contentSubgraph: OGSubgraph -} - -extension _ViewInputs { - private struct ImplicitRootType: ViewInput { - static let defaultValue: _VariadicView_AnyImplicitRoot.Type = _VStackLayout.self - } -} - -package struct ViewListOptionsInput: ViewInput { - package static let defaultValue: _ViewListInputs.Options = [] -} - -extension _ViewOutputs { - package static func multiView(inputs: _ViewInputs, body: @escaping (_Graph, _ViewInputs) -> _ViewListOutputs) -> _ViewOutputs { - // TODO - return .init() - } -} - -extension View { - nonisolated static func makeImplicitRoot(view: _GraphValue, inputs: _ViewInputs) -> _ViewOutputs { - // TODO - return .init() - } -} - -extension ViewModifier { - nonisolated static func makeImplicitRoot( - modifier: _GraphValue, - inputs: _ViewInputs, - body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs - ) -> _ViewOutputs { - // TODO - return .init() - } -} diff --git a/Sources/OpenSwiftUICore/View/VariadicView.swift b/Sources/OpenSwiftUICore/View/VariadicView.swift new file mode 100644 index 00000000..4bb80f85 --- /dev/null +++ b/Sources/OpenSwiftUICore/View/VariadicView.swift @@ -0,0 +1,591 @@ +// +// VariadicView.swift +// OpenSwiftUICore +// +// Audited for iOS 18.0 +// Status: Complete +// ID: 00F12C0E37A19C593ECA0DBD3BE26541 (SwiftUI) +// ID: DC167C463E6601B3880A23A75ACAA63B (SwiftUICore) + +package import OpenGraphShims + +// MARK: - _VariadicView + +/// A type of structured content that is passed as an argument to a +/// `Root`'s result builder, creating a `Tree` that conditionally conforms +/// to protocols like `View`. +/// +/// For example, `View`s can be passed to a `Layout` result builder +/// creating a `View`: +/// +/// HStack { +/// Image(name: "envelope") +/// Text("Your time away request has been approved") +/// Spacer() +/// Text(timestamp, format: .dateTime).layoutPriority(1) +/// } +/// +public enum _VariadicView { + /// A type that creates a `Tree`, managing content subtrees passed as + /// result builder arguments. + /// + /// For example, a layout arranges an arbitrary number of children: + /// + /// HStack { + /// Image(name: "envelope") + /// Text("Your time away request has been approved") + /// Spacer() + /// Text(timestamp, format: .dateTime).layoutPriority(1) + /// } + /// + public typealias Root = _VariadicView_Root + + /// A type of root that creates a View when its result builder is invoked with View. + public typealias ViewRoot = _VariadicView_ViewRoot + + /// An ad hoc collection of the children of a variadic view. + public typealias Children = _VariadicView_Children + + public typealias UnaryViewRoot = _VariadicView_UnaryViewRoot + + public typealias MultiViewRoot = _VariadicView_MultiViewRoot + + package typealias AnyImplicitRoot = _VariadicView_AnyImplicitRoot + + package typealias ImplicitRoot = _VariadicView_ImplicitRoot + + package typealias ImplicitRootVisitor = _VariadicView_ImplicitRootVisitor + + /// A rooted tuple of content subtrees. + /// + /// A `Tree` is created by invoking the `Root` result builder with an + /// arbitrary number of content subtrees. + /// + /// Depending on the type of `Root` and `Content`, `Tree` will + /// conditionally conform to protocols like `View`. + @frozen + public struct Tree where Root: _VariadicView.Root { + public var root: Root + public var content: Content + + @inlinable + init(root: Root, content: Content) { + self.root = root + self.content = content + } + + @inlinable + public init(_ root: Root, @ViewBuilder content: () -> Content) { + self.root = root + self.content = content() + } + } +} + +@available(*, unavailable) +extension _VariadicView.Tree: Sendable {} + +@available(*, unavailable) +extension _VariadicView: Sendable {} + +// MARK: - _VariadicView.Root + +/// A type that creates a `Tree`, managing content subtrees passed to a result builder. +/// +/// - SeeAlso: _VariadicView.Root. +public protocol _VariadicView_Root { + static var _viewListOptions: Int { get } +} + +extension _VariadicView.Root { + public static var _viewListOptions: Int { 0 } + + package static var viewListOptions: _ViewListInputs.Options { + .init(rawValue: _viewListOptions) + } + + public static func _viewListCount( + inputs _: _ViewListCountInputs, + body _: (_ViewListCountInputs) -> Int? + ) -> Int? { + nil + } +} + +// MARK: - ViewListOptionsInput + +package struct ViewListOptionsInput: ViewInput { + package static let defaultValue: _ViewListInputs.Options = [] +} + +extension _GraphInputs { + @inline(__always) + var viewListOptions: _ViewListInputs.Options { + get { self[ViewListOptionsInput.self] } + set { self[ViewListOptionsInput.self] = newValue } + } +} + +extension _ViewInputs { + @inline(__always) + var viewListOptions: _ViewListInputs.Options { + get { self[ViewListOptionsInput.self] } + set { self[ViewListOptionsInput.self] = newValue } + } +} + +extension _ViewListInputs { + @inline(__always) + var viewListOptions: _ViewListInputs.Options { + get { self[ViewListOptionsInput.self] } + set { self[ViewListOptionsInput.self] = newValue } + } +} + +extension _ViewListCountInputs { + @inline(__always) + var viewListOptions: _ViewListInputs.Options { + get { self[ViewListOptionsInput.self] } + set { self[ViewListOptionsInput.self] = newValue } + } +} + +// MARK: - _VariadicView.ViewRoot + +/// A type of root that creates a `View` when its result builder is invoked with +/// `View`. +/// +/// - SeeAlso: _VariadicView.ViewRoot. +/// - Note: Requirements mirror `View`'s. +public protocol _VariadicView_ViewRoot: _VariadicView.Root { + static func _makeView( + root: _GraphValue, + inputs: _ViewInputs, + body: (_Graph, _ViewInputs) -> _ViewListOutputs + ) -> _ViewOutputs + + static func _makeViewList( + root: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs + + static func _viewListCount( + inputs: _ViewListCountInputs, + body: (_ViewListCountInputs) -> Int? + ) -> Int? + + associatedtype Body: View + + @ViewBuilder + func body(children: _VariadicView.Children) -> Body +} + +extension _VariadicView.ViewRoot where Body == Never { + public func body(children: _VariadicView.Children) -> Never { + preconditionFailure("body() should not be called on \(Self.self).") + } +} + +// MARK: - _VariadicView.UnaryViewRoot + +public protocol _VariadicView_UnaryViewRoot: _VariadicView.ViewRoot {} + +extension _VariadicView.UnaryViewRoot { + nonisolated public static func _makeViewList( + root: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs { + let weakRoot = WeakAttribute(root.value) + return .unaryViewList(viewType: Self.self, inputs: inputs) { inputs in + guard let attribute = weakRoot.attribute else { + return .init() + } + return _makeView(root: _GraphValue(attribute), inputs: inputs) { graph, inputs in + body(graph, _ViewListInputs(inputs.base)) + } + } + } + + nonisolated public static func _viewListCount( + inputs: _ViewListCountInputs, + body: (_ViewListCountInputs) -> Int? + ) -> Int? { + 1 + } +} + +// MARK: - _VariadicView.MultiViewRoot + +public protocol _VariadicView_MultiViewRoot: _VariadicView.ViewRoot {} + +extension _VariadicView.MultiViewRoot { + nonisolated public static func _makeView( + root: _GraphValue, + inputs: _ViewInputs, + body: (_Graph, _ViewInputs) -> _ViewListOutputs + ) -> _ViewOutputs { + withoutActuallyEscaping(body) { escapingBody in + .multiView(inputs: inputs) { graph, inputs in + let listOutputs = escapingBody(graph, inputs) + let list = listOutputs.makeAttribute(inputs: _ViewListInputs(inputs.base)) + let fields = DynamicPropertyCache.fields(of: Self.self) + var inputs = inputs + let (body, buffer) = makeBody(root: root, list: list, inputs: &inputs.base, fields: fields) + let implicitRootBodyInputs = inputs.implicitRootBodyInputs + let outputs = Body.makeDebuggableViewList(view: body, inputs: implicitRootBodyInputs) + if let buffer { + buffer.traceMountedProperties(to: body, fields: fields) + } + return outputs + } + } + } + + nonisolated public static func _viewListCount( + inputs: _ViewListCountInputs, + body: (_ViewListCountInputs) -> Int? + ) -> Int? { + body(inputs) + } +} + +// MARK: - _VariadicView.Children + +/// An ad hoc collection of the children of a variadic view. +public struct _VariadicView_Children { + package var list: any ViewList + + package var contentSubgraph: Subgraph + + package var transform: ViewList.SublistTransform + + package init(_ list: any ViewList, contentSubgraph: Subgraph, transform: ViewList.SublistTransform = .init()) { + self.list = list + self.contentSubgraph = contentSubgraph + self.transform = transform + } + + package var content: ViewList.Backing { + ViewList.Backing(self) + } +} + +@available(*, unavailable) +extension _VariadicView.Children: Sendable {} + +// MARK: - _VariadicView.ViewRoot + View Extension + +extension _VariadicView.ViewRoot { + nonisolated public static func _makeView( + root: _GraphValue, + inputs: _ViewInputs, + body: (_Graph, _ViewInputs) -> _ViewListOutputs + ) -> _ViewOutputs { + makeView(root: root, inputs: inputs, body: body) + } + + nonisolated public static func _makeViewList( + root: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs { + makeViewList(root: root, inputs: inputs, body: body) + } + + nonisolated public static func _viewListCount(inputs: _ViewListCountInputs) -> Int? { + Body._viewListCount(inputs: inputs) + } + + nonisolated static func makeView( + root: _GraphValue, + inputs: _ViewInputs, + body: (_Graph, _ViewInputs) -> _ViewListOutputs + ) -> _ViewOutputs { + let listOutputs = body(_Graph(), inputs) + let list = listOutputs.makeAttribute(inputs: _ViewListInputs(inputs.base)) + let fields = DynamicPropertyCache.fields(of: Self.self) + var inputs = inputs + let (body, buffer) = makeBody(root: root, list: list, inputs: &inputs.base, fields: fields) + let outputs = Body.makeDebuggableView(view: body, inputs: inputs) + if let buffer { + buffer.traceMountedProperties(to: body, fields: fields) + } + return outputs + } + + nonisolated static func makeViewList( + root: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs { + let listOutputs = body(_Graph(), inputs) + let list = listOutputs.makeAttribute(inputs: _ViewListInputs(inputs.base)) + let fields = DynamicPropertyCache.fields(of: Self.self) + var inputs = inputs + let (body, buffer) = makeBody(root: root, list: list, inputs: &inputs.base, fields: fields) + let outputs = Body.makeDebuggableViewList(view: body, inputs: inputs) + if let buffer { + buffer.traceMountedProperties(to: body, fields: fields) + } + return outputs + } + + nonisolated fileprivate static func makeBody( + root: _GraphValue, + list: Attribute, + inputs: inout _GraphInputs, + fields: DynamicPropertyCache.Fields + ) -> (_GraphValue, _DynamicPropertyBuffer?) { + let kind = Metadata(Self.self).kind + switch kind { + case .struct, .enum, .optional, .tuple: + let accessor = ViewRootBodyAccessor(list: list, contentSubgraph: .current!) + return accessor.makeBody(container: root, inputs: &inputs, fields: fields) + default: + preconditionFailure("views root must be value types (either a struct or an enum); \(Self.self) is a class.") + } + } +} + +// MARK: - ViewRootBodyAccessor + +private struct ViewRootBodyAccessor: BodyAccessor where Root: _VariadicView.ViewRoot { + typealias Container = Root + + typealias Body = Root.Body + + @Attribute var list: any ViewList + + var contentSubgraph: Subgraph + + func updateBody(of container: Container, changed: Bool) { + let (list, listChanged) = $list.changedValue() + guard changed || listChanged else { + return + } + let children = _VariadicView.Children(list, contentSubgraph: contentSubgraph) + setBody { + container.body(children: children) + } + } +} + +// MARK: - _VariadicView.Tree + View + +extension _VariadicView.Tree: View where Root: _VariadicView.ViewRoot, Content: View { + nonisolated public static func _makeView( + view: _GraphValue, + inputs: _ViewInputs + ) -> _ViewOutputs { + var inputs = inputs + inputs.viewListOptions = Root.viewListOptions + return Root._makeView( + root: view[offset: {.of(&$0.root)}], + inputs: inputs + ) { graph, inputs in + return Content.makeDebuggableViewList( + view: view[offset: {.of(&$0.content)}], + inputs: _ViewListInputs(inputs.base, options: inputs.viewListOptions) + ) + } + } + + nonisolated public static func _makeViewList( + view: _GraphValue, + inputs: _ViewListInputs + ) -> _ViewListOutputs { + var inputs = inputs + inputs.viewListOptions = Root.viewListOptions + return Root._makeViewList( + root: view[offset: {.of(&$0.root)}], + inputs: inputs + ) { graph, inputs in + var inputs = inputs + inputs.options.formUnion(inputs.viewListOptions) + return Content.makeDebuggableViewList( + view: view[offset: {.of(&$0.content)}], + inputs: inputs + ) + } + } + + nonisolated public static func _viewListCount(inputs: _ViewListCountInputs) -> Int? { + var inputs = inputs + inputs.viewListOptions = Root.viewListOptions + return Root._viewListCount(inputs: inputs) { inputs in + var inputs = inputs + inputs.options.formUnion(inputs.viewListOptions) + return Content._viewListCount(inputs: inputs) + } + } +} + +extension _VariadicView.Tree: PrimitiveView where Root: _VariadicView.ViewRoot, Content: View {} + +extension _VariadicView.Tree: UnaryView where Root: _VariadicView.ViewRoot, Content: View {} + +// MARK: - _VariadicView.AnyImplicitRoot + +package protocol _VariadicView_AnyImplicitRoot { + static func visitType(visitor: inout V) where V: _VariadicView.ImplicitRootVisitor +} + +// MARK: - _VariadicView.ImplicitRoot + +package protocol _VariadicView_ImplicitRoot: _VariadicView.AnyImplicitRoot, _VariadicView.ViewRoot { + static var implicitRoot: Self { get } +} + +// MARK: - _VariadicView.ImplicitRootVisitor + +package protocol _VariadicView_ImplicitRootVisitor { + mutating func visit(type: R.Type) where R: _VariadicView.ImplicitRoot +} + +extension _VariadicView.ImplicitRoot { + package static func visitType(visitor: inout V) where V: _VariadicView.ImplicitRootVisitor { + visitor.visit(type: Self.self) + } +} + +// MARK: - ImplicitRootType + +private struct ImplicitRootType: ViewInput { + #if canImport(Darwin) + static let defaultValue: _VariadicView_AnyImplicitRoot.Type = CoreGlue.shared.defaultImplicitRootType.value + #else + static let defaultValue: _VariadicView_AnyImplicitRoot.Type = _VStackLayout.self + #endif +} + +// MARK: - _ViewInputs + ImplicitRoot + +extension _ViewInputs { + package var implicitRootType: any _VariadicView.AnyImplicitRoot.Type { + get { self[ImplicitRootType.self] } + set { self[ImplicitRootType.self] = newValue } + } + + package var implicitRootBodyInputs: _ViewListInputs { + let options = viewListOptions + return _ViewListInputs( + base, + options: options.union(_SemanticFeature_v2.isEnabled ? [] : .disableTransitions) + ) + } +} + +// MARK: - _ViewListInputs + ImplicitRoot + +extension _ViewListInputs { + package var implicitRootType: any _VariadicView.AnyImplicitRoot.Type { + get { self[ImplicitRootType.self] } + set { self[ImplicitRootType.self] = newValue } + } +} + +// MARK: - MakeViewRoot + +private struct MakeViewRoot: _VariadicView.ImplicitRootVisitor { + var inputs: _ViewInputs + + var body: (_Graph, _ViewInputs) -> _ViewListOutputs + + var outputs: _ViewOutputs? + + mutating func visit(type: R.Type) where R : _VariadicView_ImplicitRoot { + let attribute = inputs.intern(R.implicitRoot, id: .implicitRoot) + inputs.viewListOptions = R.viewListOptions + let root = _GraphValue(attribute) + outputs = R._makeView( + root: _GraphValue(attribute), + inputs: inputs, + body: body + ) + } +} + +// MARK: - MakeModifiedRoot + +private struct MakeModifiedRoot: _VariadicView.ImplicitRootVisitor where Modifier: ViewModifier { + var modifier: _GraphValue + + var inputs: _ViewInputs + + var body: (_Graph, _ViewInputs) -> _ViewListOutputs + + var outputs: _ViewOutputs? + + mutating func visit(type: R.Type) where R : _VariadicView_ImplicitRoot { + let attribute = inputs.intern(R.implicitRoot, id: .implicitRoot) + inputs.viewListOptions = R.viewListOptions + let body = body + outputs = Modifier.makeDebuggableView( + modifier: modifier, + inputs: inputs + ) { graph, inputs in + R._makeView( + root: _GraphValue(attribute), + inputs: inputs, + body: body + ) + } + } +} + +// MARK: - _ViewOutputs + multiView + +extension _ViewOutputs { + package static func multiView( + inputs: _ViewInputs, + body: @escaping (_Graph, _ViewInputs) -> _ViewListOutputs + ) -> _ViewOutputs { + let implicitRootType = inputs.implicitRootType + var visitor = MakeViewRoot(inputs: inputs, body: body) + implicitRootType.visitType(visitor: &visitor) + return visitor.outputs! + } + + fileprivate static func multiView ( + applying modifier: _GraphValue, + inputs: _ViewInputs, + body: @escaping (_Graph, _ViewInputs) -> _ViewListOutputs + ) -> _ViewOutputs where Modifier: ViewModifier { + let implicitRootType = inputs.implicitRootType + var visitor = MakeModifiedRoot(modifier: modifier, inputs: inputs, body: body) + implicitRootType.visitType(visitor: &visitor) + return visitor.outputs! + } +} + +// MARK: - View + ImplicitRoot + +extension View { + nonisolated package static func makeImplicitRoot( + view: _GraphValue, + inputs: _ViewInputs + ) -> _ViewOutputs { + .multiView(inputs: inputs) { _, inputs in + makeDebuggableViewList(view: view, inputs: inputs.implicitRootBodyInputs) + } + } +} + +// MARK: - ViewModifier + ImplicitRoot + +extension ViewModifier { + nonisolated package static func makeImplicitRoot( + modifier: _GraphValue, + inputs: _ViewInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewOutputs { + .multiView( + applying: modifier, + inputs: inputs + ) { graph, inputs in + body(graph, inputs.implicitRootBodyInputs) + } + } +} diff --git a/Sources/OpenSwiftUICore/View/VariadicView_Children.swift b/Sources/OpenSwiftUICore/View/VariadicView_Children.swift new file mode 100644 index 00000000..8d98e443 --- /dev/null +++ b/Sources/OpenSwiftUICore/View/VariadicView_Children.swift @@ -0,0 +1,290 @@ +// +// VariadicView_Children.swift +// OpenSwiftUICore +// +// Audited for iOS 18.0 +// Status: WIP +// ID: 52A2FFECFBCF37BFFEED558E33EBD1E3 (?) +// ID: 9B09D1820E97ECBB666F7560EA2A2D2C (?) + +package import OpenGraphShims + +// MARK: - _VariadicView.Children + View [WIP] + +extension _VariadicView.Children: View, MultiView, PrimitiveView { + nonisolated public static func _makeViewList( + view: _GraphValue, + inputs: _ViewListInputs + ) -> _ViewListOutputs { + let child = _GraphValue(Child(children: view.value)) + return ForEach._makeViewList(view: child, inputs: inputs) + } + + nonisolated public static func _viewListCount( + inputs: _ViewListCountInputs + ) -> Int? { + nil + } + + private struct Child: Rule, AsyncAttribute { + typealias Value = ForEach<_VariadicView.Children, AnyHashable, _VariadicView.Children.Element> + + @Attribute var children: _VariadicView.Children + + var value: Value { + preconditionFailure("TODO") + } + } +} + +// MARK: - _VariadicView.Children + RandomAccessCollection [WIP] + +extension _VariadicView.Children: RandomAccessCollection { + public struct Element: PrimitiveView, UnaryView, Identifiable { + var view: ViewList.View + var traits: ViewTraitCollection + + public var id: AnyHashable { + preconditionFailure("TODO") + + } + public func id(as _: ID.Type = ID.self) -> ID? where ID : Hashable { + preconditionFailure("TODO") + } + + /// The value of each trait associated with the view. Changing + /// the traits will not affect the view in any way. + public subscript(key: Trait.Type) -> Trait.Value { + get { traits[key] } + set { traits[key] = newValue } + } + + public static func _makeView(view: _GraphValue, inputs: _ViewInputs) -> _ViewOutputs { + preconditionFailure("TODO") + } + } + + public var startIndex: Int { + preconditionFailure("TODO") + } + + public var endIndex: Int { + preconditionFailure("TODO") + } + + public subscript(index: Int) -> Element { + preconditionFailure("TODO") + } +} + +// MARK: - ViewListVisitor + +package protocol ViewListVisitor { + mutating func visit(view: ViewList.View, traits: ViewTraitCollection) -> Bool +} + +// MARK: - ViewList.Backing [WIP] + +extension ViewList { + package typealias Backing = _ViewList_Backing +} + +package struct _ViewList_Backing { + package var children: _VariadicView.Children + + package var viewCount: Swift.Int { + children.list.count + } + + package init(_ children: _VariadicView.Children) { + self.children = children + } + + 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 + preconditionFailure("TODO") + } + } + } +} + +extension ViewList.Backing { + package func visitAll(applying v: inout V) where V: ViewListVisitor { + preconditionFailure("TODO") + } + + package func visitViews(applying v: inout V, from start: Int) where V: ViewListVisitor { + preconditionFailure("TODO") + } +} + +extension ViewList.Backing { + package var ids: [AnyHashable] { + preconditionFailure("TODO") + } +} + +// MARK: - _ViewList.View + +extension ViewList { + package typealias View = _ViewList_View +} + +package struct _ViewList_View: PrimitiveView, View, UnaryView { + var elements: any ViewList.Elements + var releaseElements: ViewList.Elements.Release? + package var id: ViewList.ID + var index: Int + var count: Int + var contentSubgraph: Subgraph? + + package init( + elements: any ViewList.Elements, + id: ViewList.ID, + index: Int, + count: Int, + contentSubgraph: Subgraph + ) { + self.elements = elements + self.id = id + self.index = index + self.count = count + self.contentSubgraph = contentSubgraph + } + + package var elementID: ViewList.ID { + id.elementID(at: index) + } + + package var reuseIdentifier: Int { + elementID.reuseIdentifier + } + + package var viewID: AnyHashable { + let canonicalID = elementID.canonicalID + if count == 1, !canonicalID.requiresImplicitID { + return canonicalID.explicitID!.anyHashable + } else { + return AnyHashable(canonicalID) + } + } + + nonisolated package static func _makeView( + view: _GraphValue, + inputs: _ViewInputs + ) -> _ViewOutputs { + let outputs = inputs.makeIndirectOutputs() + let placeholderInfo = PlaceholderInfo( + placeholder: view.value, + inputs: inputs, + outputs: outputs + ) + let attribute = Attribute(placeholderInfo) + outputs.setIndirectDependency(attribute.identifier) + return outputs + } +} + +// MARK: - PlaceholderInfo [WIP] + +private struct PlaceholderInfo: StatefulRule, ObservedAttribute, AsyncAttribute { + @Attribute var placeholder: ViewList.View + let inputs: _ViewInputs + let outputs: _ViewOutputs + let parentSubgraph: Subgraph + var lastSubgraph: Subgraph? + var lastRelease: ViewList.Elements.Release? + var secondaryRelease: ViewList.Elements.Release? + var lastElements: (any ViewList.Elements)? + var lastMap: IndirectAttributeMap? + var contentObserver: (Subgraph, Int)? + var lastPhase: Attribute<_GraphInputs.Phase>? + + init(placeholder: Attribute, inputs: _ViewInputs, outputs: _ViewOutputs) { + 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! + } + + struct Value { + var id: ViewList.ID + var seed: UInt32 + var index: Int + } + + func makeItem(placeholder: ViewList.View, seed: UInt32) -> Value { + preconditionFailure("TODO") + } + + mutating func reuseItem(info: inout Value, placeholder: ViewList.View) -> Bool { + guard let lastElements, + lastElements.tryToReuseElement( + at: info.index, + by: placeholder.elements, + at: placeholder.index, + indirectMap: lastMap!, + testOnly: false + ) + else { + ReuseTrace.traceReuseInvalidSubgraphFailure(ViewList.View.self) + return false + } + lastPhase!.mutateBody( + as: PlaceholderViewPhase.self, + invalidating: true + ) { phase in + phase.resetDelta &+= 1 + } + secondaryRelease = placeholder.elements.retain() + info.id = placeholder.id + info.index = placeholder.index + return true + } + + mutating func eraseItem() { + outputs.detachIndirectOutputs() + if let lastSubgraph { + lastSubgraph.willInvalidate(isInserted: true) + lastSubgraph.invalidate() + self.lastSubgraph = nil + } + if let contentObserver { + // TODO: OSubgraphRemoveObserver + // contentObserver.0.removeObserver(contentObserver.1) + self.contentObserver = nil + } + lastRelease = nil + secondaryRelease = nil + lastElements = nil + lastMap = nil + lastPhase = nil + } + + mutating func updateValue() { + preconditionFailure("TODO") + } + + func destroy() { + if let contentObserver { + // TODO: OSubgraphRemoveObserver + // contentObserver.0.removeObserver(contentObserver.1) + } + } +} + +private struct PlaceholderViewPhase: Rule, AsyncAttribute { + @Attribute var phase1: _GraphInputs.Phase + @Attribute var phase2: _GraphInputs.Phase + var resetDelta: UInt32 + + var value: _GraphInputs.Phase { + var result = phase1 + result.merge(phase2) + result.resetSeed &+= resetDelta + return result + } +} diff --git a/Sources/OpenSwiftUICore/View/ViewRoot.swift b/Sources/OpenSwiftUICore/View/ViewRoot.swift deleted file mode 100644 index 1c4d5c08..00000000 --- a/Sources/OpenSwiftUICore/View/ViewRoot.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// ViewRoot.swift -// OpenSwiftUI -// -// Audited for iOS 15.5 -// Status: WIP -// ID: 00F12C0E37A19C593ECA0DBD3BE26541 -