diff --git a/Package.resolved b/Package.resolved index e2cd12269..0c0b78252 100644 --- a/Package.resolved +++ b/Package.resolved @@ -25,7 +25,7 @@ "location" : "https://github.com/OpenSwiftUIProject/OpenGraph", "state" : { "branch" : "main", - "revision" : "40b020c8e1cf93f0eab1e5f70476bc31fe429620" + "revision" : "90da6a61a746df56dcdde3ef05cdd04d64377c2b" } }, { diff --git a/Sources/OpenSwiftUI/CoreGlue/OpenSwiftUIGlue.swift b/Sources/OpenSwiftUI/CoreGlue/OpenSwiftUIGlue.swift index 6ab01adb2..e8f8d57d5 100644 --- a/Sources/OpenSwiftUI/CoreGlue/OpenSwiftUIGlue.swift +++ b/Sources/OpenSwiftUI/CoreGlue/OpenSwiftUIGlue.swift @@ -6,12 +6,13 @@ // Status: Empty @_spi(ForOpenSwiftUIOnly) -import OpenSwiftUICore +public import OpenSwiftUICore #if canImport(Darwin) -@_cdecl("OpenSwiftUIGlueClass") -func OpenSwiftUIGlueClass() -> CoreGlue.Type { +@_spi(ForOpenSwiftUIOnly) +@_silgen_name("OpenSwiftUIGlueClass") +public func OpenSwiftUIGlueClass() -> CoreGlue.Type { OpenSwiftUIGlue.self } diff --git a/Sources/OpenSwiftUICore/Data/BodyAccessor/BodyAccessor.swift b/Sources/OpenSwiftUICore/Data/BodyAccessor/BodyAccessor.swift deleted file mode 100644 index 0ca491cef..000000000 --- a/Sources/OpenSwiftUICore/Data/BodyAccessor/BodyAccessor.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// BodyAccessor.swift -// OpenSwiftUI -// -// Audited for iOS 15.5 -// Status: Complete - -import OpenGraphShims - -package protocol BodyAccessor { - associatedtype Container - associatedtype Body - func updateBody(of container: Container, changed: Bool) -} - -extension BodyAccessor { - package func setBody(_ body: () -> Body) { - let value = traceRuleBody(Container.self) { - OGGraph.withoutUpdate(body) - } - withUnsafePointer(to: value) { value in - OGGraph.setOutputValue(value) - } - } -} diff --git a/Sources/OpenSwiftUICore/Data/BodyAccessor/BodyAccessorRule.swift b/Sources/OpenSwiftUICore/Data/BodyAccessor/BodyAccessorRule.swift deleted file mode 100644 index 19322c041..000000000 --- a/Sources/OpenSwiftUICore/Data/BodyAccessor/BodyAccessorRule.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// BodyAccessorRule.swift -// OpenSwiftUI -// -// Audited for iOS 15.5 -// Status: Complete - -package import OpenGraphShims - -package protocol BodyAccessorRule { - static var container: Any.Type { get } - static func value(as: Value.Type, attribute: AnyAttribute) -> Value? - static func buffer(as: Value.Type, attribute: AnyAttribute) -> _DynamicPropertyBuffer? - static func metaProperties(as: Value.Type, attribute: AnyAttribute) -> [(String, AnyAttribute)] -} diff --git a/Sources/OpenSwiftUICore/View/Debug/ChangedBodyProperty.swift b/Sources/OpenSwiftUICore/Data/DynamicProperty/ChangedBodyProperty.swift similarity index 100% rename from Sources/OpenSwiftUICore/View/Debug/ChangedBodyProperty.swift rename to Sources/OpenSwiftUICore/Data/DynamicProperty/ChangedBodyProperty.swift diff --git a/Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicProperty.swift b/Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicProperty.swift index 7ad4fa6c8..8f0a7e536 100644 --- a/Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicProperty.swift +++ b/Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicProperty.swift @@ -1,13 +1,13 @@ // // DynamicProperty.swift -// OpenSwiftUI +// OpenSwiftUICore // // Audited for iOS 18.0 // Status: Complete -// ID: 49D2A32E637CD497C6DE29B8E060A506 (RELEASE_2021) -// ID: A4C1D658B3717A3062FEFC91A812D6EB (RELEASE_2024) +// ID: 49D2A32E637CD497C6DE29B8E060A506 (SwiftUI) +// ID: A4C1D658B3717A3062FEFC91A812D6EB (SwiftUICore) -import OpenGraphShims +package import OpenGraphShims // MARK: - DynamicProperty @@ -210,7 +210,11 @@ package struct DynamicPropertyCache { } } -// TO BE AUDITED +package protocol BodyAccessor { + associatedtype Container + associatedtype Body + func updateBody(of container: Container, changed: Bool) +} extension BodyAccessor { package func makeBody( @@ -253,8 +257,29 @@ extension BodyAccessor { } } } + + @inline(__always) + package func setBody(_ body: () -> Body) { + let value = traceRuleBody(Container.self) { + OGGraph.withoutUpdate(body) + } + withUnsafePointer(to: value) { value in + OGGraph.setOutputValue(value) + } + } } +// MARK: - BodyAccessorRule + +package protocol BodyAccessorRule { + static var container: Any.Type { get } + static func value(as: T.Type, attribute: AnyAttribute) -> T? + static func buffer(as: T.Type, attribute: AnyAttribute) -> _DynamicPropertyBuffer? + static func metaProperties(as: T.Type, attribute: AnyAttribute) -> [(String, AnyAttribute)] +} + +// TO BE AUDITED + // MARK: - RuleThreadFlags private protocol RuleThreadFlags { diff --git a/Sources/OpenSwiftUICore/Graph/GraphReuse.swift b/Sources/OpenSwiftUICore/Graph/GraphReuse.swift index 0588f6de7..6cbfdacad 100644 --- a/Sources/OpenSwiftUICore/Graph/GraphReuse.swift +++ b/Sources/OpenSwiftUICore/Graph/GraphReuse.swift @@ -8,10 +8,6 @@ package import OpenGraphShims -// TODO: Move down to OpenGraph Package -package typealias Subgraph = OGSubgraph -package typealias Graph = OGGraph - public final class IndirectAttributeMap { package final let subgraph: Subgraph package final var map: [AnyAttribute: AnyAttribute] diff --git a/Sources/OpenSwiftUICore/Graph/ReuseTrace.swift b/Sources/OpenSwiftUICore/Graph/ReuseTrace.swift index c63eb0025..f3e602f71 100644 --- a/Sources/OpenSwiftUICore/Graph/ReuseTrace.swift +++ b/Sources/OpenSwiftUICore/Graph/ReuseTrace.swift @@ -5,7 +5,7 @@ // Audited for iOS 18.0 // Status: WIP -import OpenGraphShims +package import OpenGraphShims package struct ReuseTrace { package static func register(graph: Graph) { diff --git a/Sources/OpenSwiftUICore/Modifier/CustomViewModifier.swift b/Sources/OpenSwiftUICore/Modifier/CustomViewModifier.swift new file mode 100644 index 000000000..374d16ae4 --- /dev/null +++ b/Sources/OpenSwiftUICore/Modifier/CustomViewModifier.swift @@ -0,0 +1,301 @@ +// +// CustomViewModifier.swift +// OpenSwiftUICore +// +// Audited for iOS 18.0 +// Status: Complete +// ID: 0EAFD5A78D9C0B607C3C0964CF3A3038 (SwiftUI) +// ID: 2BA0A33A15B7F322F46AFB9D0D1A262D (SwiftUICore) + +import OpenGraphShims + +// MARK: - _ViewModifier_Content + +public struct _ViewModifier_Content: PrimitiveView where Modifier: ViewModifier { + nonisolated public static func _makeView( + view: _GraphValue, + inputs: _ViewInputs + ) -> _ViewOutputs { + providerMakeView(view: view, inputs: inputs) + } + + nonisolated public static func _makeViewList( + view: _GraphValue, + inputs: _ViewListInputs + ) -> _ViewListOutputs { + providerMakeViewList(view: view, inputs: inputs) + } + + nonisolated public static func _viewListCount( + inputs: _ViewListCountInputs, + body: (_ViewListCountInputs) -> Int? + ) -> Int? { + nil + } + + @_alwaysEmitIntoClient + nonisolated public static func _viewListCount(inputs: _ViewListCountInputs) -> Int? { + _viewListCount(inputs: inputs) { _ in nil } + } +} + +// MARK: - PlaceholderContentView + +/// A placeholder used to construct an inline modifier, transition, or other +/// helper type. +/// +/// You don't use this type directly. Instead OpenSwiftUI creates this type on +/// your behalf. +public struct PlaceholderContentView: View { + package init() {} + + nonisolated public static func _makeView(view: _GraphValue, inputs: _ViewInputs) -> _ViewOutputs { + providerMakeView(view: view, inputs: inputs) + } + + nonisolated public static func _makeViewList(view: _GraphValue, inputs: _ViewListInputs) -> _ViewListOutputs { + providerMakeViewList(view: view, inputs: inputs) + } + + nonisolated public static func _viewListCount(inputs: _ViewListCountInputs) -> Int? { + providerViewListCount(inputs: inputs) + } + + public typealias Body = Never +} + +@available(*, unavailable) +extension PlaceholderContentView: Sendable {} + +extension _ViewInputs { + package mutating func pushModifierBody(_ type: Token.Type, body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs) { + append(BodyInputElement.view(body), to: BodyInput.self) + } +} +extension _ViewListInputs { + package mutating func pushModifierBody(_ type: Token.Type, body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs) { + base.append(BodyInputElement.list(body), to: BodyInput.self) + } +} + +@available(*, unavailable) +extension _ViewModifier_Content: Sendable {} + +// MARK: - ViewModifier + Extension + +extension ViewModifier { + nonisolated public static func _makeView( + modifier: _GraphValue, + inputs: _ViewInputs, + body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs + ) -> _ViewOutputs { + makeView(modifier: modifier, inputs: inputs, body: body) + } + + nonisolated public static func _makeViewList( + modifier: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs { + makeViewList(modifier: modifier, inputs: inputs, body: body) + } + + nonisolated public static func _viewListCount( + inputs: _ViewListCountInputs, + body: (_ViewListCountInputs) -> Int? + ) -> Int? { + viewListCount(inputs: inputs, body: body) + } + + nonisolated package static func makeView( + modifier: _GraphValue, + inputs: _ViewInputs, + body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs + ) -> _ViewOutputs { + let fields = DynamicPropertyCache.fields(of: Self.self) + var inputs = inputs + let (view, buffer) = makeBody(modifier: modifier, inputs: &inputs.base, fields: fields) + inputs.append(.view(body), to: BodyInput.self) + let outputs = Body.makeDebuggableView(view: view, inputs: inputs) + if let buffer { + buffer.traceMountedProperties(to: modifier, fields: fields) + } + return outputs + } + + nonisolated package static func makeViewList( + modifier: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs { + let fields = DynamicPropertyCache.fields(of: Self.self) + var inputs = inputs + let (view, buffer) = makeBody(modifier: modifier, inputs: &inputs.base, fields: fields) + inputs.base.append(.list(body), to: BodyInput.self) + let outputs = Body.makeDebuggableViewList(view: view, inputs: inputs) + if let buffer { + buffer.traceMountedProperties(to: modifier, fields: fields) + } + return outputs + } + + nonisolated package static func viewListCount( + inputs: _ViewListCountInputs, + body: (_ViewListCountInputs) -> Int? + ) -> Int? { + withoutActuallyEscaping(body) { escapingBody in + var inputs = inputs + inputs.append(escapingBody, to: BodyCountInput.self) + return Body._viewListCount(inputs: inputs) + } + } + + nonisolated private static func makeBody( + modifier: _GraphValue, + inputs: inout _GraphInputs, + fields: DynamicPropertyCache.Fields + ) -> (_GraphValue, _DynamicPropertyBuffer?) { + let kind = Metadata(Self.self).kind + switch kind { + case .struct, .enum, .optional, .tuple: + return ModifierBodyAccessor().makeBody(container: modifier, inputs: &inputs, fields: fields) + default: + preconditionFailure("view modifiers must be value types: \(Self.self)") + } + } +} + +// MARK: - ViewModifierContentProvider + +private protocol ViewModifierContentProvider: PrimitiveView {} + +extension _ViewModifier_Content: ViewModifierContentProvider {} +extension PlaceholderContentView: ViewModifierContentProvider {} + +extension ViewModifierContentProvider { + nonisolated fileprivate static func providerMakeView( + view: _GraphValue, + inputs: _ViewInputs + ) -> _ViewOutputs { + let graphInputs = inputs.base + var inputs = inputs + guard let body = inputs.popLast(BodyInput.self) else { + return _ViewOutputs() + } + switch body { + case let .view(makeViewBody): + return makeViewBody(_Graph(), inputs) + case let .list(makeViewListBody): + return .multiView(inputs: inputs) { + makeViewListBody($0, .init($1.base, options: graphInputs[ViewListOptionsInput.self])) + } + } + } + + nonisolated fileprivate static func providerMakeViewList( + view: _GraphValue, + inputs: _ViewListInputs + ) -> _ViewListOutputs { + var inputs = inputs + guard let body = inputs.base.popLast(BodyInput.self) else { + return .emptyViewList(inputs: inputs) + } + switch body { + case let .view(makeViewBody): + return .unaryViewList( + viewType: Self.self, + inputs: inputs + ) { + makeViewBody(_Graph(), $0) + } + case let .list(makeViewListBody): + return makeViewListBody(_Graph(), inputs) + } + } + + nonisolated fileprivate static func providerViewListCount( + inputs: _ViewListCountInputs + ) -> Int? { + var inputs = inputs + guard let input = inputs.popLast(BodyCountInput.self) else { + return 0 + } + guard !inputs.customModifierTypes.contains(ObjectIdentifier(Self.self)) else { + return nil + } + inputs.customModifierTypes.append(ObjectIdentifier(Self.self)) + return input(inputs) + } +} + +// MARK: - BodyInput + +private struct BodyInput: ViewInput { + static var defaultValue: Stack { Stack() } +} + +// MARK: - BodyInputElement + +private enum BodyInputElement: GraphReusable, Equatable { + typealias MakeViewBody = (_Graph, _ViewInputs) -> _ViewOutputs + typealias MakeViewListBody = (_Graph, _ViewListInputs) -> _ViewListOutputs + + case view(MakeViewBody) + case list(MakeViewListBody) + + static var isTriviallyReusable: Bool { + _SemanticFeature_v5.isEnabled + } + + func makeReusable(indirectMap: IndirectAttributeMap) { + return + } + + func tryToReuse(by other: BodyInputElement, indirectMap: IndirectAttributeMap, testOnly: Bool) -> Bool { + switch self { + case let .view(makeViewBody): + guard case let .view(otherMakeViewBody) = other else { + ReuseTrace.traceReuseInternalFailure() + return false + } + return Self.isTriviallyReusable || compareValues(makeViewBody, otherMakeViewBody) + case let .list(makeViewListBody): + guard case let .list(otherMakeViewListBody) = other else { + ReuseTrace.traceReuseInternalFailure() + return false + } + return Self.isTriviallyReusable || compareValues(makeViewListBody, otherMakeViewListBody) + } + } + + static func == (lhs: BodyInputElement, rhs: BodyInputElement) -> Bool { + if case let .view(lhsBody) = lhs, case let .view(rhsBody) = rhs { + compareValues(lhsBody, rhsBody) + } else if case let .list(lhsBody) = lhs, case let .list(rhsBody) = rhs{ + compareValues(lhsBody, rhsBody) + } else { + false + } + } +} + +// MARK: - BodyCountInput + +private struct BodyCountInput: ViewInput { + static var defaultValue: Stack<(_ViewListCountInputs) -> Int?> { .init() } +} + +// MARK: - ModifierBodyAccessor + +private struct ModifierBodyAccessor: BodyAccessor where Container: ViewModifier { + typealias Body = Container.Body + + func updateBody(of container: Container, changed: Bool) { + guard changed else { + return + } + setBody { + container.body(content: Container.Content()) + } + } +} diff --git a/Sources/OpenSwiftUICore/Modifier/EmptyModifier.swift b/Sources/OpenSwiftUICore/Modifier/EmptyModifier.swift deleted file mode 100644 index f50908ee9..000000000 --- a/Sources/OpenSwiftUICore/Modifier/EmptyModifier.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// EmptyModifier.swift -// OpenSwiftUI -// -// Audited for iOS 15.5 -// Status: Blocked by PrimitiveSceneModifier - -/// An empty, or identity, modifier, used during development to switch -/// modifiers at compile time. -/// -/// Use the empty modifier to switch modifiers at compile time during -/// development. In the example below, in a debug build the ``Text`` -/// view inside `ContentView` has a yellow background and a red border. -/// A non-debug build reflects the default system, or container supplied -/// appearance. -/// -/// struct EmphasizedLayout: ViewModifier { -/// func body(content: Content) -> some View { -/// content -/// .background(Color.yellow) -/// .border(Color.red) -/// } -/// } -/// -/// struct ContentView: View { -/// var body: some View { -/// Text("Hello, World!") -/// .modifier(modifier) -/// } -/// -/// var modifier: some ViewModifier { -/// #if DEBUG -/// return EmphasizedLayout() -/// #else -/// return EmptyModifier() -/// #endif -/// } -/// } -/// -@frozen -public struct EmptyModifier: PrimitiveViewModifier/*, PrimitiveSceneModifier*/ { - public static let identity = EmptyModifier() - - @inlinable - public init() {} - - public static func _makeView( - modifier: _GraphValue, - inputs: _ViewInputs, - body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs - ) -> _ViewOutputs { - body(_Graph(), inputs) - } - - public static func _makeViewList( - modifier: _GraphValue, - inputs: _ViewListInputs, - body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs - ) -> _ViewListOutputs { - body(_Graph(), inputs) - } - - public static func _viewListCount( - inputs: _ViewListCountInputs, - body: (_ViewListCountInputs) -> Int? - ) -> Int? { - body(inputs) - } -} diff --git a/Sources/OpenSwiftUICore/Modifier/ModifiedContent.swift b/Sources/OpenSwiftUICore/Modifier/ModifiedContent.swift deleted file mode 100644 index 4901cc53e..000000000 --- a/Sources/OpenSwiftUICore/Modifier/ModifiedContent.swift +++ /dev/null @@ -1,121 +0,0 @@ -// -// ModifiedContent.swift -// OpenSwiftUI -// -// Audited for iOS 15.5 -// Status: WIP - -extension View { - @inlinable - nonisolated public func modifier(_ modifier: T) -> ModifiedContent { - .init(content: self, modifier: modifier) - } -} - -/// A value with a modifier applied to it. -@frozen -public struct ModifiedContent { - public typealias Body = Never - - /// The content that the modifier transforms into a new view or new - /// view modifier. - public var content: Content - - /// The view modifier. - public var modifier: Modifier - - /// A structure that the defines the content and modifier needed to produce - /// a new view or view modifier. - /// - /// If `content` is a ``View`` and `modifier` is a ``ViewModifier``, the - /// result is a ``View``. If `content` and `modifier` are both view - /// modifiers, then the result is a new ``ViewModifier`` combining them. - /// - /// - Parameters: - /// - content: The content that the modifier changes. - /// - modifier: The modifier to apply to the content. - @inlinable - public init(content: Content, modifier: Modifier) { - self.content = content - self.modifier = modifier - } -} - -extension ModifiedContent: Equatable where Content: Equatable, Modifier: Equatable { - public static func == (a: ModifiedContent, b: ModifiedContent) -> Bool { - a.content == b.content && a.modifier == b.modifier - } -} - -extension ModifiedContent: View where Content: View, Modifier: ViewModifier { - public static func _makeView( - view: _GraphValue, - inputs: _ViewInputs - ) -> _ViewOutputs { - _ViewDebug.makeView( - view: view[offset: { .of(&$0.modifier) }], - inputs: inputs - ) { modifier, inputs in - Modifier._makeView( - modifier: modifier, - inputs: inputs - ) { _, inputs in - _ViewDebug.makeView( - view: view[offset: { .of(&$0.content) }], - inputs: inputs - ) { view, inputs in - Content._makeView(view: view, inputs: inputs) - } - } - } - } - - public static func _makeViewList( - view: _GraphValue, - inputs: _ViewListInputs - ) -> _ViewListOutputs { - Modifier.makeDebuggableViewList( - modifier: view[offset: { .of(&$0.modifier) }], - inputs: inputs - ) { _, inputs in - Content.makeDebuggableViewList( - view: view[offset: { .of(&$0.content) }], - inputs: inputs - ) - } - } - - public static func _viewListCount( - inputs: _ViewListCountInputs - ) -> Int? { - Modifier._viewListCount(inputs: inputs) { inputs in - Content._viewListCount(inputs: inputs) - } - } - - public var body: ModifiedContent.Body { - bodyError() - } -} - -extension ModifiedContent: ViewModifier where Content: ViewModifier, Modifier: ViewModifier { -// public static func _makeView(modifier: _GraphValue>, inputs: _ViewInputs, body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs) -> _ViewOutputs { -// -// } -// public static func _makeViewList(modifier: _GraphValue>, inputs: _ViewListInputs, body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs) -> _ViewListOutputs { -// -// } -// public static func _viewListCount(inputs: _ViewListCountInputs, body: (_ViewListCountInputs) -> Int?) -> Int? { -// -// } -} - -extension ViewModifier { - /// Returns a new modifier that is the result of concatenating - /// `self` with `modifier`. - @inlinable - @inline(__always) - public func concat(_ modifier: T) -> ModifiedContent { - .init(content: self, modifier: modifier) - } -} diff --git a/Sources/OpenSwiftUICore/Modifier/ViewModifier.swift b/Sources/OpenSwiftUICore/Modifier/ViewModifier.swift new file mode 100644 index 000000000..d72f877c2 --- /dev/null +++ b/Sources/OpenSwiftUICore/Modifier/ViewModifier.swift @@ -0,0 +1,529 @@ +// +// ViewModifier.swift +// OpenSwiftUICore +// +// Audited for iOS 18.0 +// Status: Complete + +import OpenGraphShims + +// MARK: - ViewModifier + +/// A modifier that you apply to a view or another view modifier, producing a +/// different version of the original value. +/// +/// Adopt the ``ViewModifier`` protocol when you want to create a reusable +/// modifier that you can apply to any view. The example below combines several +/// modifiers to create a new modifier that you can use to create blue caption +/// text surrounded by a rounded rectangle: +/// +/// struct BorderedCaption: ViewModifier { +/// func body(content: Content) -> some View { +/// content +/// .font(.caption2) +/// .padding(10) +/// .overlay( +/// RoundedRectangle(cornerRadius: 15) +/// .stroke(lineWidth: 1) +/// ) +/// .foregroundColor(Color.blue) +/// } +/// } +/// +/// You can apply ``View/modifier(_:)`` directly to a view, but a more common +/// and idiomatic approach uses ``View/modifier(_:)`` to define an extension to +/// ``View`` itself that incorporates the view modifier: +/// +/// extension View { +/// func borderedCaption() -> some View { +/// modifier(BorderedCaption()) +/// } +/// } +/// +/// You can then apply the bordered caption to any view, similar to this: +/// +/// Image(systemName: "bus") +/// .resizable() +/// .frame(width:50, height:50) +/// Text("Downtown Bus") +/// .borderedCaption() +/// +/// ![A screenshot showing the image of a bus with a caption reading +/// Downtown Bus. A view extension, using custom a modifier, renders the +/// caption in blue text surrounded by a rounded +/// rectangle.](OpenSwiftUI-View-ViewModifier.png) +@MainActor +@preconcurrency +public protocol ViewModifier { + /// Makes a new view using the view modifier and inputs that you provide. + nonisolated static func _makeView( + modifier: _GraphValue, + inputs: _ViewInputs, + body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs + ) -> _ViewOutputs + + nonisolated static func _makeViewList( + modifier: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs + + /// The number of views that `_makeViewList()` would produce, or + /// nil if unknown. + nonisolated static func _viewListCount( + inputs: _ViewListCountInputs, + body: (_ViewListCountInputs) -> Int? + ) -> Int? + + /// The type of view representing the body. + associatedtype Body: View + + /// Gets the current body of the caller. + /// + /// `content` is a proxy for the view that will have the modifier + /// represented by `Self` applied to it. + @ViewBuilder + func body(content: Content) -> Body + + /// The content view type passed to `body()`. + typealias Content = _ViewModifier_Content +} + +// MARK: - PrimitiveViewModifier + +package protocol PrimitiveViewModifier: ViewModifier where Body == Never {} + +extension ViewModifier where Body == Never { + public func body(content _: Content) -> Never { + bodyError() + } + + public static func _viewListCount( + inputs: _ViewListCountInputs, + body: (_ViewListCountInputs) -> Int? + ) -> Int? { + body(inputs) + } +} + +extension ViewModifier { + func bodyError() -> Never { + preconditionFailure("body() should not be called on \(Self.self).") + } +} + +// MARK: - UnaryViewModifier + +package protocol UnaryViewModifier: ViewModifier {} + +extension UnaryViewModifier { + nonisolated static func _makeViewList( + modifier: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs { + makeUnaryViewList(modifier: modifier, inputs: inputs, body: body) + } + + nonisolated static func _viewListCount( + inputs: _ViewListCountInputs, + body: (_ViewListCountInputs) -> Int? + ) -> Int? { + 1 + } +} + +// MARK: - MultiViewModifier + +package protocol MultiViewModifier: ViewModifier {} + +extension MultiViewModifier { + nonisolated static func _makeViewList( + modifier: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs { + makeMultiViewList(modifier: modifier, inputs: inputs, body: body) + } +} + +// MARK: - ViewModifier + _GraphInputsModifier + +extension ViewModifier where Self: _GraphInputsModifier, Body == Never { + public static func _makeView( + modifier: _GraphValue, + inputs: _ViewInputs, + body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs + ) -> _ViewOutputs { + var inputs = inputs + _makeInputs(modifier: modifier, inputs: &inputs.base) + return body(_Graph(), inputs) + } + + public static func _makeViewList( + modifier: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs { + var inputs = inputs + _makeInputs(modifier: modifier, inputs: &inputs.base) + return body(_Graph(), inputs) + } + + public static func _viewListCount( + inputs: _ViewListCountInputs, + body: (_ViewListCountInputs) -> Int? + ) -> Int? { + body(inputs) + } +} + +// MARK: - ViewInputsModifier + +package protocol ViewInputsModifier: ViewModifier where Body == Never { + static var graphInputsSemantics: Semantics? { get } + nonisolated static func _makeViewInputs(modifier: _GraphValue, inputs: inout _ViewInputs) +} + +extension ViewInputsModifier { + package static var graphInputsSemantics: Semantics? { + nil + } + + nonisolated public static func _makeView( + modifier: _GraphValue, + inputs: _ViewInputs, + body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs + ) -> _ViewOutputs { + var viewInputs = inputs + _makeViewInputs(modifier: modifier, inputs: &viewInputs) + return body(_Graph(), viewInputs) + } + + nonisolated public static func _makeViewList( + modifier: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs { + guard let graphInputsSemantics, isLinkedOnOrAfter(graphInputsSemantics) else { + return makeMultiViewList(modifier: modifier, inputs: inputs, body: body) + } + var viewInputs = _ViewInputs.invalidInputs(inputs.base) + _makeViewInputs(modifier: modifier, inputs: &viewInputs) + var viewListInputs = inputs + viewListInputs.base = viewInputs.base + return body(_Graph(), viewListInputs) + } + + /// The number of views that `_makeViewList()` would produce, or + /// nil if unknown. + nonisolated public static func _viewListCount( + inputs: _ViewListCountInputs, + body: (_ViewListCountInputs) -> Int? + ) -> Int? { + body(inputs) + } +} + +// MARK: - ViewModifier + makeViewList extension + +extension ViewModifier { + nonisolated package static func makeUnaryViewList( + modifier: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs { + let weakModifier = WeakAttribute(modifier.value) + return .unaryViewList( + viewType: Self.self, + inputs: inputs + ) { viewInputs in + guard let attribute = weakModifier.attribute else { + return _ViewOutputs() + } + return makeImplicitRoot( + modifier: _GraphValue(attribute), + inputs: viewInputs, + body: body + ) + } + } + + nonisolated package static func makeMultiViewList( + modifier: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs { + var outputs = body(_Graph(), inputs) + outputs.multiModifier(modifier, inputs: inputs) + return outputs + } +} + +// MARK: - EmptyModifier + +/// An empty, or identity, modifier, used during development to switch +/// modifiers at compile time. +/// +/// Use the empty modifier to switch modifiers at compile time during +/// development. In the example below, in a debug build the ``Text`` +/// view inside `ContentView` has a yellow background and a red border. +/// A non-debug build reflects the default system, or container supplied +/// appearance. +/// +/// struct EmphasizedLayout: ViewModifier { +/// func body(content: Content) -> some View { +/// content +/// .background(Color.yellow) +/// .border(Color.red) +/// } +/// } +/// +/// struct ContentView: View { +/// var body: some View { +/// Text("Hello, World!") +/// .modifier(modifier) +/// } +/// +/// var modifier: some ViewModifier { +/// #if DEBUG +/// return EmphasizedLayout() +/// #else +/// return EmptyModifier() +/// #endif +/// } +/// } +/// +@frozen +public struct EmptyModifier: PrimitiveViewModifier, ViewModifier { + public static let identity = EmptyModifier() + + @inlinable + public init() {} + + nonisolated public static func _makeView( + modifier: _GraphValue, + inputs: _ViewInputs, + body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs + ) -> _ViewOutputs { + body(_Graph(), inputs) + } + + nonisolated public static func _makeViewList( + modifier: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs { + body(_Graph(), inputs) + } + + nonisolated public static func _viewListCount( + inputs: _ViewListCountInputs, + body: (_ViewListCountInputs) -> Int? + ) -> Int? { + body(inputs) + } +} + +// MARK: - View + modifier + +extension View { + /// Applies a modifier to a view and returns a new view. + /// + /// Use this modifier to combine a ``View`` and a ``ViewModifier``, to + /// create a new view. For example, if you create a view modifier for + /// a new kind of caption with blue text surrounded by a rounded rectangle: + /// + /// struct BorderedCaption: ViewModifier { + /// func body(content: Content) -> some View { + /// content + /// .font(.caption2) + /// .padding(10) + /// .overlay( + /// RoundedRectangle(cornerRadius: 15) + /// .stroke(lineWidth: 1) + /// ) + /// .foregroundColor(Color.blue) + /// } + /// } + /// + /// You can use ``modifier(_:)`` to extend ``View`` to create new modifier + /// for applying the `BorderedCaption` defined above: + /// + /// extension View { + /// func borderedCaption() -> some View { + /// modifier(BorderedCaption()) + /// } + /// } + /// + /// Then you can apply the bordered caption to any view: + /// + /// Image(systemName: "bus") + /// .resizable() + /// .frame(width:50, height:50) + /// Text("Downtown Bus") + /// .borderedCaption() + /// + /// ![A screenshot showing the image of a bus with a caption reading + /// Downtown Bus. A view extension, using custom a modifier, renders the + /// caption in blue text surrounded by a rounded + /// rectangle.](OpenSwiftUI-View-ViewModifier.png) + /// + /// - Parameter modifier: The modifier to apply to this view. + @inlinable + nonisolated public func modifier(_ modifier: T) -> ModifiedContent { + .init(content: self, modifier: modifier) + } +} + +// MARK: - ModifiedContent + +/// A value with a modifier applied to it. +@frozen +public struct ModifiedContent { + public typealias Body = Never + + /// The content that the modifier transforms into a new view or new + /// view modifier. + public var content: Content + + /// The view modifier. + public var modifier: Modifier + + /// A structure that the defines the content and modifier needed to produce + /// a new view or view modifier. + /// + /// If `content` is a ``View`` and `modifier` is a ``ViewModifier``, the + /// result is a ``View``. If `content` and `modifier` are both view + /// modifiers, then the result is a new ``ViewModifier`` combining them. + /// + /// - Parameters: + /// - content: The content that the modifier changes. + /// - modifier: The modifier to apply to the content. + @inlinable + nonisolated public init(content: Content, modifier: Modifier) { + self.content = content + self.modifier = modifier + } +} + +@available(*, unavailable) +extension ModifiedContent: Sendable {} + +// MARK: - ModifiedContent + Equatable + +extension ModifiedContent: Equatable where Content: Equatable, Modifier: Equatable { + public static func == (a: ModifiedContent, b: ModifiedContent) -> Bool { + a.content == b.content && a.modifier == b.modifier + } +} + +// MARK: - ModifiedContent + View + +extension ModifiedContent: View where Content: View, Modifier: ViewModifier { + public static func _makeView( + view: _GraphValue, + inputs: _ViewInputs + ) -> _ViewOutputs { + Modifier.makeDebuggableView( + modifier: view[offset: { .of(&$0.modifier) }], + inputs: inputs + ) { + Content.makeDebuggableView( + view: view[offset: { .of(&$0.content) }], + inputs: $1 + ) + } + } + + public static func _makeViewList( + view: _GraphValue, + inputs: _ViewListInputs + ) -> _ViewListOutputs { + Modifier.makeDebuggableViewList( + modifier: view[offset: { .of(&$0.modifier) }], + inputs: inputs + ) { + Content.makeDebuggableViewList( + view: view[offset: { .of(&$0.content) }], + inputs: $1 + ) + } + } + + public static func _viewListCount( + inputs: _ViewListCountInputs + ) -> Int? { + Modifier._viewListCount(inputs: inputs) { + Content._viewListCount(inputs: $0) + } + } + + public var body: Body { + bodyError() + } +} + +// MARK: - ModifiedContent + ViewModifier + +extension ModifiedContent: ViewModifier where Content: ViewModifier, Modifier: ViewModifier { + public static func _makeView( + modifier: _GraphValue, + inputs: _ViewInputs, + body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs + ) -> _ViewOutputs { + Modifier.makeDebuggableView( + modifier: modifier[offset: { .of(&$0.modifier) }], + inputs: inputs + ) { + Content.makeDebuggableView( + modifier: modifier[offset: { .of(&$0.content) }], + inputs: $1, + body: body + ) + } + } + + public static func _makeViewList( + modifier: _GraphValue, + inputs: _ViewListInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewListOutputs { + Modifier.makeDebuggableViewList( + modifier: modifier[offset: { .of(&$0.modifier) }], + inputs: inputs + ) { + Content.makeDebuggableViewList( + modifier: modifier[offset: { .of(&$0.content) }], + inputs: $1, + body: body + ) + } + } + + public static func _viewListCount( + inputs: _ViewListCountInputs, + body: (_ViewListCountInputs) -> Int? + ) -> Int? { + Modifier._viewListCount(inputs: inputs) { + Content._viewListCount(inputs: $0, body: body) + } + } +} + +// MARK: - ViewModifier + modifier + +extension ViewModifier { + /// Returns a new modifier that is the result of concatenating + /// `self` with `modifier`. + @inlinable + nonisolated public func concat(_ modifier: T) -> ModifiedContent { + .init(content: self, modifier: modifier) + } +} + +// MARK: - ModifiedContent + CustomViewDebugReflectable + +extension ModifiedContent: CustomViewDebugReflectable { + package var customViewDebugMirror: Mirror? { nil } +} diff --git a/Sources/OpenSwiftUICore/Modifier/AppearanceActionModifier.swift b/Sources/OpenSwiftUICore/Modifier/ViewModifier/AppearanceActionModifier.swift similarity index 100% rename from Sources/OpenSwiftUICore/Modifier/AppearanceActionModifier.swift rename to Sources/OpenSwiftUICore/Modifier/ViewModifier/AppearanceActionModifier.swift diff --git a/Sources/OpenSwiftUICore/Modifier/ClipEffect.swift b/Sources/OpenSwiftUICore/Modifier/ViewModifier/ClipEffect.swift similarity index 100% rename from Sources/OpenSwiftUICore/Modifier/ClipEffect.swift rename to Sources/OpenSwiftUICore/Modifier/ViewModifier/ClipEffect.swift diff --git a/Sources/OpenSwiftUICore/Modifier/ViewModifier/CustomViewModifier.swift b/Sources/OpenSwiftUICore/Modifier/ViewModifier/CustomViewModifier.swift deleted file mode 100644 index fe1228c66..000000000 --- a/Sources/OpenSwiftUICore/Modifier/ViewModifier/CustomViewModifier.swift +++ /dev/null @@ -1,192 +0,0 @@ -// -// CustomViewModifier.swift -// OpenSwiftUI -// -// Audited for iOS 15.5 -// Status: WIP -// ID: 0EAFD5A78D9C0B607C3C0964CF3A3038 - -import OpenGraphShims - -// MARK: - ViewModifier + Extension - -extension ViewModifier { - static func makeView( - modifier: _GraphValue, - inputs: _ViewInputs, - body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs - ) -> _ViewOutputs { - let fields = DynamicPropertyCache.fields(of: Self.self) - var inputs = inputs - let (view, buffer) = makeBody(modifier: modifier, inputs: &inputs.base, fields: fields) - inputs.append(.view(body), to: _ViewModifier_Content.BodyInput.self) - let outputs = _ViewDebug.makeView( - view: view, - inputs: inputs - ) { view, inputs in - Body._makeView(view: view, inputs: inputs) - } - if let buffer { - buffer.traceMountedProperties(to: view, fields: fields) - } - return outputs - } - - static func makeViewList( - modifier: _GraphValue, - inputs: _ViewListInputs, - body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs - ) -> _ViewListOutputs { - preconditionFailure("TODO") - } - - static func viewListCount( - inputs: _ViewListCountInputs, - body: (_ViewListCountInputs) -> Int? - ) -> Int? { - preconditionFailure("TODO") - } - - private static func makeBody( - modifier: _GraphValue, - inputs: inout _GraphInputs, - fields: DynamicPropertyCache.Fields - ) -> (_GraphValue, _DynamicPropertyBuffer?) { - let kind = Metadata(Self.self).kind - switch kind { - case .struct, .enum, .optional, .tuple: - let accessor = ModifierBodyAccessor() - return accessor.makeBody(container: modifier, inputs: &inputs, fields: fields) - default: - preconditionFailure("view modifiers must be value types: \(Self.self)") - } - } -} - -// MARK: - ModifierBodyAccessor - -private struct ModifierBodyAccessor: BodyAccessor { - typealias Body = Container.Body - - func updateBody(of container: Container, changed: Bool) { - guard changed else { - return - } - setBody { - container.body(content: _ViewModifier_Content()) - } - } -} - -// MARK: - _ViewModifier_Content - -public struct _ViewModifier_Content: PrimitiveView { - public static func _makeView( - view: _GraphValue, - inputs: _ViewInputs - ) -> _ViewOutputs { - var inputs = inputs - guard let body = inputs.popLast(BodyInput.self) else { - return _ViewOutputs() - } - switch body { - case let .view(makeViewBody): - return makeViewBody(_Graph(), inputs) - case let .list(makeViewListBody): - preconditionFailure("TODO: \(String(describing: makeViewListBody))") - } - } - - public static func _makeViewList( - view: _GraphValue, - inputs: _ViewListInputs - ) -> _ViewListOutputs { - preconditionFailure("TODO") - } - - public static func _viewListCount( - inputs: _ViewListCountInputs, - body: (_ViewListCountInputs) -> Int? - ) -> Int? { - preconditionFailure("TODO") - } -} - -extension _ViewModifier_Content { - fileprivate struct BodyInput: ViewInput { - static var defaultValue: [Body] { - [] - } - - typealias MakeViewBody = (_Graph, _ViewInputs) -> _ViewOutputs - typealias MakeViewListBody = (_Graph, _ViewListInputs) -> _ViewListOutputs - - enum Body: Equatable { - case view(MakeViewBody) - case list(MakeViewListBody) - - static func == (lhs: _ViewModifier_Content.BodyInput.Body, rhs: _ViewModifier_Content.BodyInput.Body) -> Bool { - if case let .view(lhsBody) = lhs, case let .view(rhsBody) = rhs { - compareValues(lhsBody, rhsBody) - } else if case let .list(lhsBody) = lhs, case let .list(rhsBody) = rhs{ - compareValues(lhsBody, rhsBody) - } else { - false - } - } - } - } -} - -// MARK: - BodyInput - -// FIXME -private struct BodyInput {} - -private enum BodyInputElement: GraphReusable, Equatable { - typealias MakeViewBody = (_Graph, _ViewInputs) -> _ViewOutputs - typealias MakeViewListBody = (_Graph, _ViewListInputs) -> _ViewListOutputs - - case view(MakeViewBody) - case list(MakeViewListBody) - - static func == (lhs: BodyInputElement, rhs: BodyInputElement) -> Bool { - if case let .view(lhsBody) = lhs, case let .view(rhsBody) = rhs { - compareValues(lhsBody, rhsBody, options: .init(rawValue: 0x103)) - } else if case let .list(lhsBody) = lhs, case let .list(rhsBody) = rhs{ - compareValues(lhsBody, rhsBody, options: .init(rawValue: 0x103)) - } else { - false - } - } - - static var isTriviallyReusable: Bool { - _SemanticFeature_v5.isEnabled - } - - func makeReusable(indirectMap: IndirectAttributeMap) { - return - } - - func tryToReuse(by other: BodyInputElement, indirectMap: IndirectAttributeMap, testOnly: Bool) -> Bool { - switch self { - case let .view(makeViewBody): - guard case let .view(otherMakeViewBody) = other else { - ReuseTrace.traceReuseInternalFailure() - return false - } - return Self.isTriviallyReusable || compareValues(makeViewBody, otherMakeViewBody, options: .init(rawValue: 0x103)) - case let .list(makeViewListBody): - guard case let .list(otherMakeViewListBody) = other else { - ReuseTrace.traceReuseInternalFailure() - return false - } - return Self.isTriviallyReusable || compareValues(makeViewListBody, otherMakeViewListBody, options: .init(rawValue: 0x103)) - } - } -} - - -private struct BodyCountInput: ViewInput { - static var defaultValue: Stack<_ViewListCountInputs> { .init() } -} diff --git a/Sources/OpenSwiftUICore/Modifier/ViewModifier/ViewInputsModifier.swift b/Sources/OpenSwiftUICore/Modifier/ViewModifier/ViewInputsModifier.swift deleted file mode 100644 index ccd6e8a2a..000000000 --- a/Sources/OpenSwiftUICore/Modifier/ViewModifier/ViewInputsModifier.swift +++ /dev/null @@ -1,11 +0,0 @@ -// -// ViewInputsModifier.swift -// OpenSwiftUICore -// -// Audited for iOS 18.0 -// Status: WIP - -package protocol ViewInputsModifier: ViewModifier where Body == Never { - static var graphInputsSemantics: Semantics? { get } - nonisolated static func _makeViewInputs(modifier: _GraphValue, inputs: inout _ViewInputs) -} diff --git a/Sources/OpenSwiftUICore/Modifier/ViewModifier/ViewModifier.swift b/Sources/OpenSwiftUICore/Modifier/ViewModifier/ViewModifier.swift deleted file mode 100644 index efa5c3c87..000000000 --- a/Sources/OpenSwiftUICore/Modifier/ViewModifier/ViewModifier.swift +++ /dev/null @@ -1,163 +0,0 @@ -// -// ViewModifier.swift -// OpenSwiftUICore -// -// Audited for iOS 15.5 -// Status: Complete - -/// A modifier that you apply to a view or another view modifier, producing a -/// different version of the original value. -/// -/// Adopt the ``ViewModifier`` protocol when you want to create a reusable -/// modifier that you can apply to any view. The example below combines several -/// modifiers to create a new modifier that you can use to create blue caption -/// text surrounded by a rounded rectangle: -/// -/// struct BorderedCaption: ViewModifier { -/// func body(content: Content) -> some View { -/// content -/// .font(.caption2) -/// .padding(10) -/// .overlay( -/// RoundedRectangle(cornerRadius: 15) -/// .stroke(lineWidth: 1) -/// ) -/// .foregroundColor(Color.blue) -/// } -/// } -/// -/// You can apply ``View/modifier(_:)`` directly to a view, but a more common -/// and idiomatic approach uses ``View/modifier(_:)`` to define an extension to -/// ``View`` itself that incorporates the view modifier: -/// -/// extension View { -/// func borderedCaption() -> some View { -/// modifier(BorderedCaption()) -/// } -/// } -/// -/// You can then apply the bordered caption to any view, similar to this: -/// -/// Image(systemName: "bus") -/// .resizable() -/// .frame(width:50, height:50) -/// Text("Downtown Bus") -/// .borderedCaption() -/// -/// ![A screenshot showing the image of a bus with a caption reading -/// Downtown Bus. A view extension, using custom a modifier, renders the -/// caption in blue text surrounded by a rounded -/// rectangle.](OpenSwiftUI-View-ViewModifier.png) -@MainActor -@preconcurrency -public protocol ViewModifier { - /// Makes a new view using the view modifier and inputs that you provide. - nonisolated static func _makeView( - modifier: _GraphValue, - inputs: _ViewInputs, - body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs - ) -> _ViewOutputs - - nonisolated static func _makeViewList( - modifier: _GraphValue, - inputs: _ViewListInputs, - body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs - ) -> _ViewListOutputs - - /// The number of views that `_makeViewList()` would produce, or - /// nil if unknown. - nonisolated static func _viewListCount( - inputs: _ViewListCountInputs, - body: (_ViewListCountInputs) -> Int? - ) -> Int? - - /// The type of view representing the body. - associatedtype Body: View - - /// Gets the current body of the caller. - /// - /// `content` is a proxy for the view that will have the modifier - /// represented by `Self` applied to it. - @ViewBuilder - func body(content: Content) -> Body - - /// The content view type passed to `body()`. - typealias Content = _ViewModifier_Content -} - -package protocol PrimitiveViewModifier: ViewModifier where Body == Never {} - -extension ViewModifier where Body == Never { - public func body(content _: Content) -> Never { - bodyError() - } - - public static func _viewListCount( - inputs: _ViewListCountInputs, - body: (_ViewListCountInputs) -> Int? - ) -> Int? { - body(inputs) - } -} - -extension ViewModifier where Self: _GraphInputsModifier, Body == Never { - public static func _makeView( - modifier: _GraphValue, - inputs: _ViewInputs, - body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs - ) -> _ViewOutputs { - var inputs = inputs - _makeInputs(modifier: modifier, inputs: &inputs.base) - let outputs = body(_Graph(), inputs) - return outputs - } - - public static func _makeViewList( - modifier: _GraphValue, - inputs: _ViewListInputs, - body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs - ) -> _ViewListOutputs { - var inputs = inputs - _makeInputs(modifier: modifier, inputs: &inputs.base) - let outputs = body(_Graph(), inputs) - return outputs - } - - public static func _viewListCount( - inputs: _ViewListCountInputs, - body: (_ViewListCountInputs) -> Int? - ) -> Int? { - body(inputs) - } -} - -extension ViewModifier { - func bodyError() -> Never { - preconditionFailure("body() should not be called on \(Self.self).") - } -} - -extension ViewModifier { - public static func _makeView( - modifier: _GraphValue, - inputs: _ViewInputs, - body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs - ) -> _ViewOutputs { - makeView(modifier: modifier, inputs: inputs, body: body) - } - - public static func _makeViewList( - modifier: _GraphValue, - inputs: _ViewListInputs, - body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs - ) -> _ViewListOutputs { - makeViewList(modifier: modifier, inputs: inputs, body: body) - } - - public static func _viewListCount( - inputs: _ViewListCountInputs, - body: (_ViewListCountInputs) -> Int? - ) -> Int? { - viewListCount(inputs: inputs, body: body) - } -} diff --git a/Sources/OpenSwiftUICore/Modifier/ViewModifier/TODO/_EnvironmentKeyWritingModifier.swift b/Sources/OpenSwiftUICore/Modifier/ViewModifier/_EnvironmentKeyWritingModifier.swift similarity index 100% rename from Sources/OpenSwiftUICore/Modifier/ViewModifier/TODO/_EnvironmentKeyWritingModifier.swift rename to Sources/OpenSwiftUICore/Modifier/ViewModifier/_EnvironmentKeyWritingModifier.swift diff --git a/Sources/OpenSwiftUICore/View/AnyView.swift b/Sources/OpenSwiftUICore/View/AnyView.swift index ea2425404..596cc9ee3 100644 --- a/Sources/OpenSwiftUICore/View/AnyView.swift +++ b/Sources/OpenSwiftUICore/View/AnyView.swift @@ -131,15 +131,17 @@ private final class AnyViewStorage: AnyViewStorageBase where V: View { override func makeChildView(view: Attribute, inputs: _ViewInputs) -> _ViewOutputs { var inputs = inputs inputs.base.pushStableType(V.self) - let view = _GraphValue(AnyViewChild(view: view)) - return V.makeDebuggableView(view: view, inputs: inputs) + let childView = Attribute(AnyViewChild(view: view)) + childView.value = self.view + return V.makeDebuggableView(view: _GraphValue(childView), inputs: inputs) } override func makeChildViewList(view: Attribute, inputs: _ViewListInputs) -> _ViewListOutputs { var inputs = inputs inputs.base.pushStableType(V.self) - let view = _GraphValue(AnyViewChild(view: view)) - return V.makeDebuggableViewList(view: view, inputs: inputs) + let childView = Attribute(AnyViewChild(view: view)) + childView.value = self.view + return V.makeDebuggableViewList(view: _GraphValue(childView), inputs: inputs) } override func visitContent(_ visitor: inout Visitor) where Visitor: ViewVisitor { diff --git a/Sources/OpenSwiftUICore/View/Debug/ViewDebug.swift b/Sources/OpenSwiftUICore/View/Debug/ViewDebug.swift index 3f408383c..7b2e23839 100644 --- a/Sources/OpenSwiftUICore/View/Debug/ViewDebug.swift +++ b/Sources/OpenSwiftUICore/View/Debug/ViewDebug.swift @@ -8,7 +8,7 @@ // ID: 43DA1754B0518AF1D72B90677BF266DB (SwiftUICore) public import Foundation -import OpenGraphShims +package import OpenGraphShims import OpenSwiftUI_SPI /// Namespace for view debug information. diff --git a/Sources/OpenSwiftUICore/View/DynamicView.swift b/Sources/OpenSwiftUICore/View/DynamicView.swift index cc3010ac8..8673ab355 100644 --- a/Sources/OpenSwiftUICore/View/DynamicView.swift +++ b/Sources/OpenSwiftUICore/View/DynamicView.swift @@ -34,7 +34,7 @@ extension DynamicView { metadata: metadata, view: view.value, inputs: inputs, - outputs: inputs.makeIndirectOutputs() + outputs: outputs ) let attribute = Attribute(container) attribute.flags = .active @@ -157,7 +157,7 @@ private struct DynamicViewList: StatefulRule, AsyncAttribute where V: Dynamic continue } item.retain() - // parentSubgraph.addChild(item.subgraph) + parentSubgraph.addChild(item.subgraph) item.subgraph.didReinsert() lastItem = item setValue(for: item, id: lastID) diff --git a/Sources/OpenSwiftUICore/View/Graph/ViewRendererHost.swift b/Sources/OpenSwiftUICore/View/Graph/ViewRendererHost.swift index 9ff6cd1ba..52b4ec867 100644 --- a/Sources/OpenSwiftUICore/View/Graph/ViewRendererHost.swift +++ b/Sources/OpenSwiftUICore/View/Graph/ViewRendererHost.swift @@ -255,7 +255,7 @@ extension ViewRendererHost { } renderingPhase = .none if nextTime.seconds.isFinite { - var delay = max(nextTime.seconds, time.seconds) - time.seconds + let delay = max(nextTime.seconds, time.seconds) - time.seconds requestUpdate(after: max(delay, 1e-6)) } } diff --git a/Sources/OpenSwiftUICore/View/Input/ViewList.swift b/Sources/OpenSwiftUICore/View/Input/ViewList.swift index ddb7b00a7..5cea40051 100644 --- a/Sources/OpenSwiftUICore/View/Input/ViewList.swift +++ b/Sources/OpenSwiftUICore/View/Input/ViewList.swift @@ -1063,10 +1063,7 @@ public struct BodyUnaryViewGenerator: UnaryViewGenerator { } public func tryToReuse(by other: BodyUnaryViewGenerator, indirectMap: IndirectAttributeMap, testOnly: Bool) -> Bool { - // FIXME: - // 1. pass body to OGCompareValues directly instaed of withUnsafePointer - // 2. Add 0x103 case instead of rawValue - guard compareValues(body, other.body, mode: .init(rawValue: 0x103)) else { + guard compareValues(body, other.body) else { ReuseTrace.traceReuseBodyMismatchedFailure() Log.graphReuse("Reuse failed: \(Self.self) failed comparison") return false diff --git a/Sources/OpenSwiftUICore/View/Variadic/VariadicView_ViewRoot.swift b/Sources/OpenSwiftUICore/View/Variadic/VariadicView_ViewRoot.swift index afff3b0be..da987d896 100644 --- a/Sources/OpenSwiftUICore/View/Variadic/VariadicView_ViewRoot.swift +++ b/Sources/OpenSwiftUICore/View/Variadic/VariadicView_ViewRoot.swift @@ -73,6 +73,17 @@ extension _ViewInputs { } } +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 @@ -80,4 +91,13 @@ extension View { } } -// TODO: ViewModifier +extension ViewModifier { + nonisolated static func makeImplicitRoot( + modifier: _GraphValue, + inputs: _ViewInputs, + body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs + ) -> _ViewOutputs { + // TODO + return .init() + } +}