// Based on https://gist.github.com/dabrahams/852dfdb0b628e68567b4d97499f196f9 struct Dispatch { func apply(_ a: A, _ f: (Model) -> R) -> R { f(a as! Model) } } protocol RandomAccessCollectionDispatch { func fastCount(_ x: C) -> Int? } extension Dispatch: RandomAccessCollectionDispatch where Model: RandomAccessCollection { func fastCount(_ x: C) -> Int? { apply(x) { $0.count } } } extension Collection { internal var randomAccessDispatch: RandomAccessCollectionDispatch? { Dispatch() as? RandomAccessCollectionDispatch } } struct ConditionalCollection: Collection { typealias Index = Base.Index var base: Base var startIndex: Index { base.startIndex } var endIndex: Index { base.endIndex } func index(after i: Index) -> Index { base.index(after: i) } subscript(position: Index) -> Base.Element { base[position] } } extension ConditionalCollection: BidirectionalCollection where Base: BidirectionalCollection { func index(before i: Base.Index) -> Base.Index { base.index(before: i) } } extension ConditionalCollection: RandomAccessCollection where Base: RandomAccessCollection { func distance(from start: Base.Index, to end: Base.Index) -> Int { base.distance(from: start, to: end) } func index(_ i: Base.Index, offsetBy distance: Int) -> Base.Index { base.index(i, offsetBy: distance) } } func conformanceTest(_ c: C) { print(c.randomAccessDispatch?.fastCount(c) as Any) } conformanceTest(1...10) // 10 conformanceTest("asdf") // nil conformanceTest(ConditionalCollection(base: 1...10)) // 10 conformanceTest(ConditionalCollection(base: "asdf")) // nil