Skip to content

Commit

Permalink
1.8.2
Browse files Browse the repository at this point in the history
  • Loading branch information
nathantannar4 committed Jul 10, 2024
1 parent 0d2d564 commit 518c63f
Show file tree
Hide file tree
Showing 15 changed files with 594 additions and 305 deletions.
2 changes: 2 additions & 0 deletions Sources/EngineCore/AnyViewVisitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ private struct AnyViewStorageVisitor<

mutating func visit<Content: View>(type: Content.Type) {
let content = unsafeBitCast(value, to: Content.self)
var context = context
context.id.append(Content.self)
content.visit(visitor: visitor, context: context, stop: &stop)
}
}
43 changes: 43 additions & 0 deletions Sources/EngineCore/ConditionalContentVisitor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Copyright (c) Nathan Tannar
//

import SwiftUI

extension _ConditionalContent: MultiView where TrueContent: View, FalseContent: View {

public func makeSubviewIterator() -> some MultiViewIterator {
ConditionalContentSubviewIterator(content: unsafeBitCast(self, to: _Storage.self))
}

enum _Storage {
case trueContent(TrueContent)
case falseContent(FalseContent)
}
}

private struct ConditionalContentSubviewIterator<
TrueContent: View,
FalseContent: View
>: MultiViewIterator {

var content: _ConditionalContent<TrueContent, FalseContent>._Storage

func visit<
Visitor: MultiViewVisitor
>(
visitor: UnsafeMutablePointer<Visitor>,
context: Context,
stop: inout Bool
) {
var context = context
switch content {
case .trueContent(let trueContent):
context.id.append(TrueContent.self)
trueContent.visit(visitor: visitor, context: context, stop: &stop)
case .falseContent(let falseContent):
context.id.append(FalseContent.self)
falseContent.visit(visitor: visitor, context: context, stop: &stop)
}
}
}
125 changes: 53 additions & 72 deletions Sources/EngineCore/CustomViewVisitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,38 @@ private struct CustomViewIterator<
context: context,
stop: &stop
)
} else if let conformance = MultiViewProtocolDescriptor.conformance(of: Content.Body.self) {
conformance.visit(
content: content.body,
visitor: visitor,
context: context,
stop: &stop
)
} else if Content.Body.self != Never.self,
let conformance = MultiViewProtocolDescriptor.conformance(of: Content.Body.self)
{
let body = content.body
if IsMultiViewVisitor.isMultiView(
body,
conformance: conformance
) {
var context = context
// SwiftUI v6 wraps in AnyView
var isAnyView = false
#if DEBUG
if #available(iOS 18.0, macOS 15.0, tvOS 18.0, watchOS 11.0, visionOS 2.0, *) {
isAnyView = true
}
#endif
if !isAnyView {
context.id.append(Content.Body.self)
}
conformance.visit(
content: content.body,
visitor: visitor,
context: context,
stop: &stop
)
} else {
visitor.value.visit(
content: content,
context: context,
stop: &stop
)
}
} else {
visitor.value.visit(
content: content,
Expand All @@ -42,79 +67,35 @@ private struct CustomViewIterator<
}

extension View {

public func visit<
Visitor: ViewVisitor
>(
visitor: UnsafeMutablePointer<Visitor>
) {
#if os(iOS) || os(tvOS)
if let conformance = UIViewRepresentableProtocolDescriptor.conformance(of: Self.self) {
conformance.visit(visitor: visitor)
} else if let conformance = UIViewControllerRepresentableProtocolDescriptor.conformance(of: Self.self) {
conformance.visit(visitor: visitor)
} else {
visitor.pointee.visit(type: Self.self)
}
#elseif os(macOS)
if let conformance = NSViewRepresentableProtocolDescriptor.conformance(of: Self.self) {
conformance.visit(visitor: visitor)
} else if let conformance = NSViewControllerRepresentableProtocolDescriptor.conformance(of: Self.self) {
conformance.visit(visitor: visitor)
} else {
visitor.pointee.visit(type: Self.self)
}
#endif
}

public func makeSubviewIterator() -> some MultiViewIterator {
CustomViewIterator(content: self)
}
}

@_disfavoredOverload
@inline(__always)
public func visit<
Visitor: MultiViewVisitor
>(
visitor: UnsafeMutablePointer<Visitor>
) {
var stop = false
visit(visitor: visitor, stop: &stop)
}
private struct IsMultiViewVisitor: MultiViewVisitor {
var count = 0

@_disfavoredOverload
@inline(__always)
public func visit<
Visitor: MultiViewVisitor
>(
visitor: UnsafeMutablePointer<Visitor>,
mutating func visit<Content: View>(
content: Content,
context: Context,
stop: inout Bool
) {
visit(visitor: visitor, context: .init(Self.self), stop: &stop)
count += 1
stop = count > 1
}

@_disfavoredOverload
public func visit<
Visitor: MultiViewVisitor
>(
visitor: UnsafeMutablePointer<Visitor>,
context: MultiViewIteratorContext,
stop: inout Bool
) {
if let conformance = MultiViewProtocolDescriptor.conformance(of: Self.self) {
conformance.visit(
content: self,
visitor: visitor,
context: context,
stop: &stop
)
} else {
let iterator = CustomViewIterator(content: self)
iterator.visit(
visitor: visitor,
context: context,
stop: &stop
)
}
static func isMultiView<Content: View>(
_ content: Content,
conformance: ProtocolConformance<MultiViewProtocolDescriptor>
) -> Bool {
var visitor = IsMultiViewVisitor()
var stop = false
conformance.visit(
content: content,
visitor: &visitor,
context: .init(Content.self),
stop: &stop
)
return visitor.count != 1
}
}
4 changes: 2 additions & 2 deletions Sources/EngineCore/ForEachVisitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ private struct ForEachSubviewIterator<
stop: inout Bool
) {
let offset: (Data.Index) -> AnyHashable
if let idGenerator = try? swift_getFieldValue("idGenerator", Any.self, self),
let keyPath = Mirror(reflecting: idGenerator).children.first?.value as? KeyPath<Data.Element, ID>
if let keyPath = Mirror(reflecting: content).descendant("idGenerator", "keyPath") as? KeyPath<Data.Element, ID>
{
offset = { index in
content.data[index][keyPath: keyPath]
Expand All @@ -49,6 +48,7 @@ private struct ForEachSubviewIterator<
let element = content.content(content.data[index])
var context = context
context.id.append(offset: offset(index))
context.id.append(Content.self)
element.visit(
visitor: visitor,
context: context,
Expand Down
21 changes: 20 additions & 1 deletion Sources/EngineCore/GroupVisitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,25 @@ extension Group: MultiView where Content: View {
}

public func makeSubviewIterator() -> some MultiViewIterator {
content.makeSubviewIterator()
GroupSubviewIterator(content: self)
}
}

private struct GroupSubviewIterator<
Content: View
>: MultiViewIterator {

var content: Group<Content>

func visit<
Visitor: MultiViewVisitor
>(
visitor: UnsafeMutablePointer<Visitor>,
context: Context,
stop: inout Bool
) {
var context = context
context.id.append(Content.self)
content.content.visit(visitor: visitor, context: context, stop: &stop)
}
}
92 changes: 63 additions & 29 deletions Sources/EngineCore/MultiViewVisitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,7 @@ public protocol MultiViewVisitor {
@frozen
public struct MultiViewElementContext {

public struct ID: Hashable {

private indirect enum Storage: Hashable {
case root(TypeIdentifier)
case subview(Storage, TypeIdentifier)
case offset(Storage, AnyHashable)
}
private var storage: Storage

init<Content: View>(_: Content.Type) {
self.storage = .root(TypeIdentifier(Content.self))
}

mutating func append<Content: View>(_: Content.Type) {
storage = .subview(storage, TypeIdentifier(Content.self))
}

mutating func append<Offset: Hashable>(offset: Offset) {
storage = .offset(storage, AnyHashable(offset))
}
}
public typealias ID = ViewTypeIdentifier

public struct Traits: OptionSet {
public var rawValue: UInt8
Expand Down Expand Up @@ -92,14 +72,20 @@ public protocol MultiViewIterator {

public struct MultiViewIteratorContext {

var traits: MultiViewElementContext.Traits
var modifier: Any?
var id: MultiViewElementContext.ID
public var id: MultiViewElementContext.ID
public var traits: MultiViewElementContext.Traits
public var modifier: Any?

public init<Content: View>(_: Content.Type = Content.self) {
init(id: MultiViewElementContext.ID) {
self.id = id
self.traits = []
self.modifier = nil
}

public init<Content: View>(_: Content.Type = Content.self) {
self.id = .init(Content.self)
self.traits = []
self.modifier = nil
}

public func union(_ traits: MultiViewElementContext.Traits) -> Self {
Expand Down Expand Up @@ -128,6 +114,56 @@ public struct MultiViewIteratorContext {
}
}

extension View {

@_disfavoredOverload
@inline(__always)
public func visit<
Visitor: MultiViewVisitor
>(
visitor: UnsafeMutablePointer<Visitor>
) {
var stop = false
visit(visitor: visitor, stop: &stop)
}

@_disfavoredOverload
@inline(__always)
public func visit<
Visitor: MultiViewVisitor
>(
visitor: UnsafeMutablePointer<Visitor>,
stop: inout Bool
) {
visit(visitor: visitor, context: MultiViewIteratorContext(Self.self), stop: &stop)
}

@_disfavoredOverload
public func visit<
Visitor: MultiViewVisitor
>(
visitor: UnsafeMutablePointer<Visitor>,
context: MultiViewIteratorContext,
stop: inout Bool
) {
if let conformance = MultiViewProtocolDescriptor.conformance(of: Self.self) {
conformance.visit(
content: self,
visitor: visitor,
context: context,
stop: &stop
)
} else {
var iterator = makeSubviewIterator()
iterator.visit(
visitor: visitor,
context: context,
stop: &stop
)
}
}
}

extension MultiView {

/// Unwraps the type to be visited by the `Visitor`
Expand All @@ -149,7 +185,7 @@ extension MultiView {
visitor: UnsafeMutablePointer<Visitor>,
stop: inout Bool
) {
visit(visitor: visitor, context: .init(Self.self), stop: &stop)
visit(visitor: visitor, context: MultiViewIteratorContext(Self.self), stop: &stop)
}

@inlinable
Expand Down Expand Up @@ -228,8 +264,6 @@ extension MultiViewVisitor {
context: MultiViewIteratorContext,
stop: inout Bool
) {
var context = context
context.id.append(Content.self)
if let modifier = context.modifier {
stop = withUnsafeMutablePointer(to: &self) { ptr in
func project<Modifier>(_ modifier: Modifier) -> Bool {
Expand All @@ -246,7 +280,7 @@ extension MultiViewVisitor {
return _openExistential(modifier, do: project)
}
} else {
visit(content: content, context: .init(context: context), stop: &stop)
visit(content: content, context: MultiViewElementContext(context: context), stop: &stop)
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions Sources/EngineCore/OptionalVisitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ private struct OptionalSubviewIterator<
// Do nothing
break
case .some(let element):
var context = context
context.id.append(Wrapped.self)
element.visit(visitor: visitor, context: context, stop: &stop)
}
}
Expand Down
Loading

0 comments on commit 518c63f

Please sign in to comment.