Skip to content

Instantly share code, notes, and snippets.

@erichsu
Forked from iwill/TypeErasure.swift
Created November 17, 2021 08:33
Show Gist options
  • Save erichsu/9ff7eecfa2fc9e4afbb289fa96156e61 to your computer and use it in GitHub Desktop.
Save erichsu/9ff7eecfa2fc9e4afbb289fa96156e61 to your computer and use it in GitHub Desktop.
Code Snippet: Type Erasure for Protocol with AssociatedType, Self and static methods
// Type-Erasure
// - seealso: [AnyIterator](https://github.com/apple/swift/blob/2fe4254cb712fa101a220f95b6ade8f99f43dc74/stdlib/public/core/ExistentialCollection.swift.gyb#L45)
// MARK: remove `Equatable` if not needed
public protocol Protocol: Equatable {
// MARK: `Protocol` requirements
associatedtype AssociatedType
func methodOfProtocol() -> Self.AssociatedType
}
public struct AnyProtocol<AssociatedType> {
private let _box: _AnyProtocolBoxBase<AssociatedType>
public init<T: Protocol>(_ base: T) where T.AssociatedType == AssociatedType {
let box = _ProtocolBox(base)
self._box = box
// MARK: remove if `Protocol` does not adopt `Equatable`
self._isEqual = { box._base == ($0._box as? _ProtocolBox<T>)?._base }
}
// MARK: remove if `Protocol` does not adopt `Equatable`
private let _isEqual: (AnyProtocol) -> Bool
public static func == (lhs: AnyProtocol<AssociatedType>, rhs: AnyProtocol<AssociatedType>) -> Bool {
return lhs._isEqual(rhs) || rhs._isEqual(lhs)
}
}
extension AnyProtocol: Protocol {
// MARK: `Protocol` conformance
public func methodOfProtocol() -> AssociatedType {
return _box.methodOfProtocol()
}
}
fileprivate class _AnyProtocolBoxBase<AssociatedType>: Protocol {
@inline(never) private static func _abstract(file: StaticString = #file, line: UInt = #line) -> Never { fatalError("Method must be overridden!", file: file, line: line) }
// MARK: remove if `Protocol` does not adopt `Equatable`
@inlinable static func == (lhs: _AnyProtocolBoxBase<AssociatedType>, rhs: _AnyProtocolBoxBase<AssociatedType>) -> Bool { _abstract() }
// MARK: `Protocol` conformance
@inlinable internal func methodOfProtocol() -> AssociatedType { Self._abstract() }
}
fileprivate final class _ProtocolBox<Base: Protocol>: _AnyProtocolBoxBase<Base.AssociatedType> {
internal var _base: Base
internal init(_ base: Base) { self._base = base }
// MARK: `Protocol` conformance
override func methodOfProtocol() -> Base.AssociatedType { return _base.methodOfProtocol() }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment