Skip to content

Instantly share code, notes, and snippets.

@iwill
Last active November 17, 2021 08:33
Show Gist options
  • Save iwill/f40bdff08f001130764b7034d26ad23b to your computer and use it in GitHub Desktop.
Save iwill/f40bdff08f001130764b7034d26ad23b 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() }
}
@iwill
Copy link
Author

iwill commented Mar 2, 2021

struct StructType: Protocol {
    let int: Int
    func methodOfProtocol() -> Int {
        return int
    }
}
let lhs = AnyProtocol(StructType(int: 1)), rhs = AnyProtocol(StructType(int: 1))
lhs == rhs // true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment