If we literally just want the Bool
result for isBidirectional
, that’s actually pretty easy. Here’s a quick demo for all 5 of the standard Collection
subprotocols.
First some empty enums:
enum BidirectionalCollectionMarker<T> {}
enum LazyCollectionMarker<T> {}
enum MutableCollectionMarker<T> {}
enum RandomAccessCollectionMarker<T> {}
enum RangeReplaceableCollectionMarker<T> {}
Then some empty conformances:
protocol ConformanceMarker {}
extension BidirectionalCollectionMarker : ConformanceMarker where T: BidirectionalCollection {}
extension LazyCollectionMarker : ConformanceMarker where T: LazyCollectionProtocol {}
extension MutableCollectionMarker : ConformanceMarker where T: MutableCollection {}
extension RandomAccessCollectionMarker : ConformanceMarker where T: RandomAccessCollection {}
extension RangeReplaceableCollectionMarker: ConformanceMarker where T: RangeReplaceableCollection {}
And finally the Collection
properties:
extension Collection {
var isBidirectional : Bool { BidirectionalCollectionMarker<Self>.self is ConformanceMarker.Type }
var isLazy : Bool { LazyCollectionMarker<Self>.self is ConformanceMarker.Type }
var isMutable : Bool { MutableCollectionMarker<Self>.self is ConformanceMarker.Type }
var isRandomAccess : Bool { RandomAccessCollectionMarker<Self>.self is ConformanceMarker.Type }
var isRangeReplaceable: Bool { RangeReplaceableCollectionMarker<Self>.self is ConformanceMarker.Type }
}
For actual use, it probably makes sense to have static Collection.isX
properties as well, in which case the instance properties could just call Self.isX
.
In any event, here’s a helper for checking all the capabilities of a Collection
instance:
CollectionCapabilities
struct CollectionCapabilities {
var isBidirectional : Bool
var isLazy : Bool
var isMutable : Bool
var isRandomAccess : Bool
var isRangeReplaceable: Bool
}
extension Collection {
var capabilities: CollectionCapabilities {
CollectionCapabilities(
isBidirectional : isBidirectional,
isLazy : isLazy,
isMutable : isMutable,
isRandomAccess : isRandomAccess,
isRangeReplaceable: isRangeReplaceable
)
}
}
• • •
Edit: Here’s a slight variation that adds a 2nd empty protocol in order to shorten the line length of the Collection
properties, and make things read a little better:
Version 2
extension Collection {
var isBidirectional : Bool { BidirectionalCollectionMarker<Self>.conforms }
var isLazy : Bool { LazyCollectionMarker<Self>.conforms }
var isMutable : Bool { MutableCollectionMarker<Self>.conforms }
var isRandomAccess : Bool { RandomAccessCollectionMarker<Self>.conforms }
var isRangeReplaceable: Bool { RangeReplaceableCollectionMarker<Self>.conforms }
}
protocol ConformanceMarker {}
extension ConformanceMarker {
static var conforms: Bool { Self.self is Conforming.Type }
}
enum BidirectionalCollectionMarker<T> : ConformanceMarker {}
enum LazyCollectionMarker<T> : ConformanceMarker {}
enum MutableCollectionMarker<T> : ConformanceMarker {}
enum RandomAccessCollectionMarker<T> : ConformanceMarker {}
enum RangeReplaceableCollectionMarker<T>: ConformanceMarker {}
protocol Conforming {}
extension BidirectionalCollectionMarker : Conforming where T: BidirectionalCollection {}
extension LazyCollectionMarker : Conforming where T: LazyCollectionProtocol {}
extension MutableCollectionMarker : Conforming where T: MutableCollection {}
extension RandomAccessCollectionMarker : Conforming where T: RandomAccessCollection {}
extension RangeReplaceableCollectionMarker: Conforming where T: RangeReplaceableCollection {}