プロトコルの活用実例を観察する

EquatableやSequenceType、その他色々なプロトコルが用意されていますが、実際のコードでどのような使えばいいのかがいまいち思い描けないものもあったので、GitHubに上がっているコードを見て学習しようと思います。比較的よく使いそうなプロトコルに絞って見てみます。
プロトコル名にはApple公式ドキュメントのリンク、実例には該当のコードが載っているページのリンクを貼っているので、詳しく見たい方はリンクをクリックしてください。

# [Equatable](https://developer.apple.com/reference/swift/equatable)

値が等しいかどうかの比較が可能な型を表すプロトコルです。定義すべき演算子は`func == (lhs: Self, rhs: Self) -> Bool`です。`==`を定義すると自動的に`!=`も使えるようになるそうです。

## [facebook-sdk-swift](https://github.com/facebook/facebook-sdk-swift/blob/82d4f4bc4226bd9d0494a604cb2f39632f6a0b57/Sources/Share/Content/Photo/Photo.swift)の例

```swift
extension Photo: Equatable {
  public static func == (lhs: Photo, rhs: Photo) -> Bool {
    return lhs.sdkPhotoRepresentation == rhs.sdkPhotoRepresentation
  }
}
```

## [realm-cocoa](https://github.com/realm/realm-cocoa/blob/62cf723ed69b7646cab12717e28a32f07ba029d3/RealmSwift/Schema.swift)の例

```swift
extension Schema: Equatable {}

public func == (lhs: Schema, rhs: Schema) -> Bool { // swiftlint:disable:this valid_docs
    return lhs.rlmSchema.isEqualToSchema(rhs.rlmSchema)
}
```

# [Comparable](https://developer.apple.com/reference/swift/comparable)

大小比較が可能な型を表すプロトコルで、Equatableを継承しています。そのためEquatableの演算子`==`はもちろん利用できます。演算子`<`を定義すると自動的に`>`, `<=`, `>=`も利用できるようになります。`func < (lhs: Self, rhs: Self) -> Bool`と`func == (lhs: Self, rhs: Self) -> Bool`は実装する必要があります。

## [SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON/blob/25cd88578b630c9b1ed8f37b235919e8cdd7e300/Source/SwiftyJSON.swift)の例

```swift
public enum JSONIndex:Comparable
{
    case array(Int)
    case dictionary(DictionaryIndex<String, JSON>)
    case null

    static public func ==(lhs: JSONIndex, rhs: JSONIndex) -> Bool
    {
        switch (lhs, rhs)
        {
        case (.array(let left), .array(let right)):
            return left == right
        case (.dictionary(let left), .dictionary(let right)):
            return left == right
        case (.null, .null): return true
        default:
            return false
        }
    }

    static public func <(lhs: JSONIndex, rhs: JSONIndex) -> Bool
    {
        switch (lhs, rhs)
        {
        case (.array(let left), .array(let right)):
            return left < right
        case (.dictionary(let left), .dictionary(let right)):
            return left < right
        default:
            return false
        }
    }
}
```

## [SwiftDate](https://github.com/malcommac/SwiftDate/blob/02fe0a612a75d09c87571569f692a13a5a2ae419/Sources/SwiftDate/DateTimeInterval.swift)の例

```swift
public struct DateTimeInterval : Comparable {
	public static func ==(lhs: DateTimeInterval, rhs: DateTimeInterval) -> Bool {
		return lhs.start == rhs.start && lhs.duration == rhs.duration
	}
	
	public static func <(lhs: DateTimeInterval, rhs: DateTimeInterval) -> Bool {
		return lhs.compare(rhs) == .orderedAscending
	}
}
```

# [CustomStringConvertible](https://developer.apple.com/reference/swift/customstringconvertible)

selfを表す文字列表現を返す時に使います。NSObjectを継承しているオブジェクトであればdescription関数をprintすると何かしら出力されますが、カスタムクラスだとそれがないので自分でdescription関数を用意する場合はこれを使うことになります。

## [facebook-sdk-swift](https://github.com/facebook/facebook-sdk-swift/blob/82d4f4bc4226bd9d0494a604cb2f39632f6a0b57/Sources/Core/AppEvents/AppEventName.swift)の例

```swift
extension AppEventName: CustomStringConvertible {
  public var description: String {
    return rawValue
  }
}
```

# [ExpressibleByStringLiteral](https://developer.apple.com/reference/swift/expressiblebystringliteral)

`ExpressibleByExtendedGraphemeClusterLiteral`を継承し、それがさらに`ExpressibleByUnicodeScalarLiteral`を継承しています。任意の長さの文字列リテラルを使用して初期化できます。`String`, `StaticString`はこのプロトコルを継承しています。

## [realm-cocoa](https://github.com/realm/realm-cocoa/blob/62cf723ed69b7646cab12717e28a32f07ba029d3/RealmSwift/SortDescriptor.swift)の例

```swift
extension SortDescriptor: ExpressibleByStringLiteral {

    public typealias UnicodeScalarLiteralType = StringLiteralType
    public typealias ExtendedGraphemeClusterLiteralType = StringLiteralType

    public init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
        self.init(property: value)
    }

    public init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {
        self.init(property: value)
    }

    public init(stringLiteral value: StringLiteralType) {
        self.init(property: value)
    }
}
```

# [IteratorProtocol](https://developer.apple.com/reference/swift/iteratorprotocol)

シーケンスの値を1つずつ供給するプロトコルなので、Sequenceプロトコルと密接に関係しています。Sequenceはイテレータを作成することによって要素にアクセスできます。Swiftはシーケンスまたはコレクションのイテレータを内部的に使用することによってfor-inループを可能にしています。
※Swift3で名前が`GeneratorType`から`IteratorProtocol`になりました。

## [realm-cocoa](https://github.com/realm/realm-cocoa/blob/216333cf82e1afcba5e6c4547e6fb983165d510f/Realm/Swift/RLMSupport.swift)の例

```swift
public final class RLMIterator: IteratorProtocol {
    private let iteratorBase: NSFastEnumerationIterator

    internal init(collection: RLMCollection) {
        iteratorBase = NSFastEnumerationIterator(collection)
    }

    public func next() -> RLMObject? {
        return iteratorBase.next() as! RLMObject?
    }
}
```

# [Sequence](https://developer.apple.com/reference/swift/sequence)

for-inで繰り返しが可能な型を表すプロトコルです。
※Swift3で名前が`SequenceType`から`Sequence`になりました。
※繰り返しのためにインスタンス自体を変化させる可能性があるので安全な繰り返しにはCollectionTypeを使った方が良いようです。

## [Surge](https://github.com/mattt/Surge/blob/88bc48b14b649f67384faec4db10c32cda207693/Source/Matrix.swift)の例

```swift
extension Matrix: Sequence {
    public func makeIterator() -> AnyIterator<ArraySlice<Element>> {
        let endIndex = rows * columns
        var nextRowStartIndex = 0

        return AnyIterator {
            if nextRowStartIndex == endIndex {
                return nil
            }

            let currentRowStartIndex = nextRowStartIndex
            nextRowStartIndex += self.columns

            return self.grid[currentRowStartIndex..<nextRowStartIndex]
        }
    }
}
```

## [Kingfisher](https://github.com/onevcat/Kingfisher/blob/144e9b897fb0a3b1e21f25415e6bd4ea770fc61f/Sources/String%2BMD5.swift)の例

```swift
struct BytesSequence: Sequence {
    let chunkSize: Int
    let data: [UInt8]
    
    func makeIterator() -> BytesIterator {
        return BytesIterator(chunkSize: chunkSize, data: data)
    }
}
```

# [Collection](https://developer.apple.com/reference/swift/collection)

Sequence、Indexableを継承しています。Sequenceプロトコルから継承するメソッドに加え、特定の位置にある要素にアクセスできるメソッドも使うことができるようになります。
※Swift3で名前が`CollectionType`から`Collection`になりました。

## [AudioKit](https://github.com/audiokit/AudioKit/blob/2d202484d59e23aab9fdef4cd6e05ff9b73967bb/AudioKit/Common/MIDI/AKMIDI%2BSendingMIDI.swift)の例

```swift
internal struct MIDIDestinations: Collection {
    typealias Index = Int

    init() { }

    var startIndex: Index {
        return 0
    }

    var endIndex: Index {
        return MIDIGetNumberOfDestinations()
    }

    subscript (index: Index) -> MIDIEndpointRef {
      return MIDIGetDestination(index)
    }

    func index(after index: Index) -> Index {
      return index + 1
    }
}
```