-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8455bd0
commit 7f781a8
Showing
10 changed files
with
458 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
// | ||
// Copyright (c) Nathan Tannar | ||
// | ||
|
||
import SwiftUI | ||
|
||
import EngineCore | ||
|
||
/// A static type-erased `View`. | ||
/// | ||
/// > Warning: The ``TypeDescriptor/descriptor`` should match the type | ||
/// returned by `content` | ||
@frozen | ||
public struct StaticContent<Descriptor: TypeDescriptor>: View { | ||
|
||
@usableFromInline | ||
var content: Any | ||
|
||
@inlinable | ||
public init( | ||
_ descriptor: Descriptor.Type = Descriptor.self, | ||
content: () -> Any | ||
) { | ||
self.content = content() | ||
} | ||
|
||
public var body: Never { | ||
bodyError() | ||
} | ||
|
||
public static func _makeView( | ||
view: _GraphValue<Self>, | ||
inputs: _ViewInputs | ||
) -> _ViewOutputs { | ||
func project<T>(_ type: T.Type) -> _ViewOutputs { | ||
let conformance = ViewProtocolDescriptor.conformance(of: T.self)! | ||
var visitor = ViewOutputsVisitor(view: view[\.content], inputs: inputs) | ||
conformance.visit(visitor: &visitor) | ||
return visitor.outputs | ||
} | ||
let type = unsafeBitCast(Descriptor.descriptor, to: Any.Type.self) | ||
return _openExistential(type, do: project) | ||
} | ||
|
||
public static func _makeViewList( | ||
view: _GraphValue<Self>, | ||
inputs: _ViewListInputs | ||
) -> _ViewListOutputs { | ||
func project<T>(_ type: T.Type) -> _ViewListOutputs { | ||
let conformance = ViewProtocolDescriptor.conformance(of: T.self)! | ||
var visitor = ViewListOutputsVisitor(view: view[\.content], inputs: inputs) | ||
conformance.visit(visitor: &visitor) | ||
return visitor.outputs | ||
} | ||
let type = unsafeBitCast(Descriptor.descriptor, to: Any.Type.self) | ||
return _openExistential(type, do: project) | ||
} | ||
|
||
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) | ||
public static func _viewListCount( | ||
inputs: _ViewListCountInputs | ||
) -> Int? { | ||
func project<T>(_ type: T.Type) -> Int? { | ||
let conformance = ViewProtocolDescriptor.conformance(of: T.self)! | ||
var visitor = ViewListOutputsCountVisitor(inputs: inputs) | ||
conformance.visit(visitor: &visitor) | ||
return visitor.outputs | ||
} | ||
let type = unsafeBitCast(Descriptor.descriptor, to: Any.Type.self) | ||
return _openExistential(type, do: project) | ||
} | ||
} | ||
|
||
private struct StaticContentBody<Content: View>: View { | ||
var content: Any | ||
|
||
var body: Content { | ||
content as! Content | ||
} | ||
} | ||
|
||
private struct ViewOutputsVisitor: ViewVisitor { | ||
var view: _GraphValue<Any> | ||
var inputs: _ViewInputs | ||
|
||
var outputs: _ViewOutputs! | ||
|
||
mutating func visit<Content>(type: Content.Type) where Content: View { | ||
let view = unsafeBitCast(view, to: _GraphValue<StaticContentBody<Content>>.self) | ||
outputs = StaticContentBody<Content>._makeView(view: view, inputs: inputs) | ||
} | ||
} | ||
|
||
private struct ViewListOutputsVisitor: ViewVisitor { | ||
var view: _GraphValue<Any> | ||
var inputs: _ViewListInputs | ||
|
||
var outputs: _ViewListOutputs! | ||
|
||
mutating func visit<Content>(type: Content.Type) where Content: View { | ||
let view = unsafeBitCast(view, to: _GraphValue<StaticContentBody<Content>>.self) | ||
outputs = StaticContentBody<Content>._makeViewList(view: view, inputs: inputs) | ||
} | ||
} | ||
|
||
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) | ||
private struct ViewListOutputsCountVisitor: ViewVisitor { | ||
var inputs: _ViewListCountInputs | ||
|
||
var outputs: Int? | ||
|
||
mutating func visit<Content>(type: Content.Type) where Content: View { | ||
outputs = StaticContentBody<Content>._viewListCount(inputs: inputs) | ||
} | ||
} | ||
|
||
// MARK: - Previews | ||
|
||
struct StaticContent_Previews: PreviewProvider { | ||
|
||
struct Content: View { | ||
var body: some View { | ||
Text("Hello, World") | ||
} | ||
} | ||
|
||
struct Descriptor: TypeDescriptor { | ||
static var descriptor: UnsafeRawPointer { | ||
TypeIdentifier(Content.self).metadata | ||
} | ||
} | ||
|
||
static var previews: some View { | ||
VStack { | ||
StaticContent<Descriptor> { | ||
Content() | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// | ||
// Copyright (c) Nathan Tannar | ||
// | ||
|
||
import SwiftUI | ||
|
||
import EngineCore | ||
|
||
/// A static type-erased `ViewModifier`. | ||
/// | ||
/// > Warning: The ``TypeDescriptor/descriptor`` should match the type | ||
/// returned by `modifier` | ||
@frozen | ||
public struct StaticModifier<Descriptor: TypeDescriptor>: ViewModifier { | ||
|
||
@usableFromInline | ||
var modifier: Any | ||
|
||
@inlinable | ||
public init( | ||
_ descriptor: Descriptor.Type = Descriptor.self, | ||
modifier: () -> Any | ||
) { | ||
self.modifier = modifier() | ||
} | ||
|
||
public func body(content: Content) -> Never { | ||
bodyError() | ||
} | ||
|
||
public static func _makeView( | ||
modifier: _GraphValue<Self>, | ||
inputs: _ViewInputs, | ||
body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs | ||
) -> _ViewOutputs { | ||
func project<T>(_ type: T.Type) -> _ViewOutputs { | ||
let conformance = ViewModifierProtocolDescriptor.conformance(of: T.self)! | ||
var visitor = ViewOutputsVisitor(view: modifier[\.modifier], inputs: inputs, body: body) | ||
conformance.visit(visitor: &visitor) | ||
return visitor.outputs | ||
} | ||
let type = unsafeBitCast(Descriptor.descriptor, to: Any.Type.self) | ||
return _openExistential(type, do: project) | ||
} | ||
|
||
public static func _makeViewList( | ||
modifier: _GraphValue<Self>, | ||
inputs: _ViewListInputs, | ||
body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs | ||
) -> _ViewListOutputs { | ||
func project<T>(_ type: T.Type) -> _ViewListOutputs { | ||
let conformance = ViewModifierProtocolDescriptor.conformance(of: T.self)! | ||
var visitor = ViewListOutputsVisitor(view: modifier[\.modifier], inputs: inputs, body: body) | ||
conformance.visit(visitor: &visitor) | ||
return visitor.outputs | ||
} | ||
let type = unsafeBitCast(Descriptor.descriptor, to: Any.Type.self) | ||
return _openExistential(type, do: project) | ||
} | ||
|
||
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) | ||
public static func _viewListCount( | ||
inputs: _ViewListCountInputs, | ||
body: (_ViewListCountInputs) -> Int? | ||
) -> Int? { | ||
func project<T>(_ type: T.Type) -> Int? { | ||
withoutActuallyEscaping(body) { body in | ||
let conformance = ViewModifierProtocolDescriptor.conformance(of: T.self)! | ||
var visitor = ViewListOutputsCountVisitor(inputs: inputs, body: body) | ||
conformance.visit(visitor: &visitor) | ||
return visitor.outputs | ||
} | ||
} | ||
let type = unsafeBitCast(Descriptor.descriptor, to: Any.Type.self) | ||
return _openExistential(type, do: project) | ||
} | ||
} | ||
|
||
private struct StaticModifierBody<Modifier: ViewModifier>: ViewModifier { | ||
var modifier: Any | ||
|
||
func body(content: Content) -> some View { | ||
content.modifier(modifier as! Modifier) | ||
} | ||
} | ||
|
||
private struct ViewOutputsVisitor: ViewModifierVisitor { | ||
var view: _GraphValue<Any> | ||
var inputs: _ViewInputs | ||
var body: (_Graph, _ViewInputs) -> _ViewOutputs | ||
|
||
var outputs: _ViewOutputs! | ||
|
||
mutating func visit<Modifier>(type: Modifier.Type) where Modifier: ViewModifier { | ||
let modifier = unsafeBitCast(view, to: _GraphValue<StaticModifierBody<Modifier>>.self) | ||
outputs = StaticModifierBody<Modifier>._makeView(modifier: modifier, inputs: inputs, body: body) | ||
} | ||
} | ||
|
||
private struct ViewListOutputsVisitor: ViewModifierVisitor { | ||
var view: _GraphValue<Any> | ||
var inputs: _ViewListInputs | ||
var body: (_Graph, _ViewListInputs) -> _ViewListOutputs | ||
|
||
var outputs: _ViewListOutputs! | ||
|
||
mutating func visit<Modifier>(type: Modifier.Type) where Modifier: ViewModifier { | ||
let modifier = unsafeBitCast(view, to: _GraphValue<StaticModifierBody<Modifier>>.self) | ||
outputs = StaticModifierBody<Modifier>._makeViewList(modifier: modifier, inputs: inputs, body: body) | ||
} | ||
} | ||
|
||
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) | ||
private struct ViewListOutputsCountVisitor: ViewModifierVisitor { | ||
var inputs: _ViewListCountInputs | ||
var body: (_ViewListCountInputs) -> Int? | ||
|
||
var outputs: Int? | ||
|
||
mutating func visit<Modifier>(type: Modifier.Type) where Modifier: ViewModifier { | ||
outputs = StaticModifierBody<Modifier>._viewListCount(inputs: inputs, body: body) | ||
} | ||
} | ||
|
||
// MARK: - Previews | ||
|
||
struct StaticModifier_Previews: PreviewProvider { | ||
|
||
struct Modifier: ViewModifier { | ||
func body(content: Content) -> some View { | ||
content.border(Color.red) | ||
} | ||
} | ||
|
||
struct Descriptor: TypeDescriptor { | ||
static var descriptor: UnsafeRawPointer { | ||
TypeIdentifier(Modifier.self).metadata | ||
} | ||
} | ||
|
||
static var previews: some View { | ||
VStack { | ||
Text("Hello, World") | ||
.modifier { | ||
StaticModifier<Descriptor> { | ||
Modifier() | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.