Package that declares empty protocols for base classes of various system frameworks.
Marker protocols is an approach of partially erasing type constraints for writing generic extensions for types in Swift.
Such protocols can be required by different packages and declaring them in-place may cause name collisions.
This lightweight package declares a set of core marker protocols to potentially address such collisions.
Marker protocols are useful for building type-aware generic extensions.
extension AVCaptureDevice {
func withExclusiveLock(
// ❌ `Self` can't be used on non-final class AVCaptureDevice
perform configuration: (AVCaptureDevice) async -> Void
) async throws {
try self.lockForConfiguration()
await configuration(self)
self.unlockForConfiguration()
}
}
let instance: CustomAVCaptureDevice = .init()
instance.withExlusiveLock { device in
// ❌ Type of device is erased to AVCaptureDevice
// not just base AVCaptureDevice
}import AVFoundationMarkerProtocols
extension _AVCaptureDeviceProtocol {
func withExclusiveLock(
// ✅ `Self` can be used on a marker protocol
perform configuration: (Self) async -> Void
) async throws {
try self.lockForConfiguration()
await configuration(self)
self.unlockForConfiguration()
}
}
let instance: CustomAVCaptureDevice = .init()
instance.withExlusiveLock { device in
// ✅ Type of device is kept - CustomAVCaptureDevice
}Lets say you want to build some layout proxy for Cocoa views
-
Target API
view.layout.chain.of.calls()
-
Chainable proxy type
public struct LayoutProxy<Target: UIView> { public let target: Target internal init(_ target: Target) { self.target = target } }
extension UIView {
// ❌ `Self` can't be used on non-final class UIView
// Using this property on any type will always
// erase a type of the view
var layout: LayoutProxy<UIView> { .init(self) }
}extension _UIViewProtocol {
// ✅ `Self` can be used here and the type
// of the view is kept at the call site
var layout: LayoutProxy<Self> { .init(self) }
}struct GenericContainer<Content> {
var content: Content
}extension GenericContainer {
// This declaration is completely fine, except
// of being a bit too verbose
func unwrapped<Value>(with value: Value) -> GenericContainer<Value>
where Content == Value {
.init(content: content ?? value)
}
// ❌ Won't compile since properties can't be
// generic and we can't declare `Value` type here
var unsafelyUnwrapped: GenericContainer<Value> { /*...*/ }
}extension GenericContainer where Content: _OptionalProtocol {
func unwrapped(with value: Value) -> GenericContainer<Value> {
.init(with: content._optional ?? value)
}
var unsafelyUnwrapped: GenericContainer<Content.Wrapped> {
get { .init(content: content._optional!) }
set { self.content = newValue.content }
}
}_OptionalProtocol<Wrapped>_AnyKeyPathProtocol- alternative toSwift._AppendKeyPathprotocol
_CALayerProtocol- Exports
FoundationMarkerProtocols
_AVCaptureDeviceProtocol- Exports
FoundationMarkerProtocols
_NotificationCenterProtocol- Exports
SwiftMarkerProtocols
_UIViewProtocol/_NSViewProtocol_UIViewControllerProtocol/_NSViewControllerProtocol- Exports
FoundationMarkerProtocols
Tip
UIKitis basically a CocoaTouch frameworkAppKitis basically Cocoa framework withoutCoreData
Both frameworks could have shared Cocoa prefix for their types, so capturecontext/cocoa-aliases package provides Cocoa-prefixed aliases for UI/NS prefixed Cocoa types, it also exports aliased _CocoaViewProtocol and _CocoaViewControllerProtocol marker protocols.
This is an umbrella product that exports all available marker protocols.
Primary targets for this package are other packages
.package(
url: "https://github.com/capturecontext/swift-marker-protocols.git",
.upToNextMajor(from: "1.1.0")
)Do not forget about target dependencies:
.product(
name: "MarkerProtocols",
package: "swift-marker-protocols"
)This library is released under the MIT license. See LICENSE for details.