Swift3.0版、Enumのcaseを配列で返すProtocol Extension

## 注意書き
※この記事はSwift4.1までのものです。
Swift4.2からは `CaseIterable` が搭載されたのでそちらをお使いください

```swift
enum SomeType:String, CaseIterable {
    case A, B, C, D
}

print(SomeType.allCases)
```

https://github.com/apple/swift-evolution/blob/master/proposals/0194-derived-collection-of-enum-cases.md

---

## 概要
以前に、 [enumの列挙子を配列で取得するのをprotocolで](http://qiita.com/su_k/items/1781259463290e909092)という記事で、Enumで宣言したcaseを配列で返すprotocolを紹介したのですが、
`Xcode 8 beta`と`Swift3.0 preview-1`が出たということで、swift3.0に対応するように書き換えてみました。

### なぜ作ったか
enum に宣言した全てのcaseが配列でほしい時に、

```swift
enum SomeType {
    case A, B, C, D

    var cases: [SomeTypes] {
        return [.A, .B, .C, .D]
    }
}
```

としてしまうのは、後にcaseが増えた時に **漏れる可能性** もあるし、他のEnumに対しても同じことをやろうと思った時に書き方が **冗長的** になってしまうので、
protocolとextensionを活用して、

```swift
enum SomeType: EnumEnumerable {
   // ...
}

let allCases: [SomeType] = SomeType.cases // => [A, B, C, D]
```

とするだけで、caseの配列が取得できるようにしてみました。

## はじめに
2016/06/20現在、Xcode 8 beta、Swift3.0 preview-1をもとにしているので、今後実装方法が変わる可能性もあります。
その場合は適宜記事を編集して最新のものにします。

## 実装

- [Gist](https://gist.github.com/sgr-ksmt/5a0753676b7a851877b57ab2b94b56e4)

```swift:swift3.0でのEnumEnumerable
public protocol EnumEnumerable {
    associatedtype Case = Self
}

public extension EnumEnumerable where Case: Hashable {
    private static var iterator: AnyIterator<Case> {
        var n = 0
        return AnyIterator {
            defer { n += 1 }
  
            let next = withUnsafePointer(to: &n) {
                UnsafeRawPointer($0).assumingMemoryBound(to: Case.self).pointee
            }
            return next.hashValue == n ? next : nil
        }
    }
    
    public static func enumerate() -> EnumeratedSequence<AnySequence<Case>> {
        return AnySequence(self.iterator).enumerated()
    }
    
    public static var cases: [Case] {
        return Array(self.iterator)
    }
    
    public static var count: Int {
        return self.cases.count
    }
}
```


### 使い方
Xcode 8 betaで開いたPlaygroundにコピペしてサッと試すことができます。

任意のEnumに対して、 ***EnumEnumerable*** を適合させるだけです。

```swift:使い方
enum Fruit: Int, EnumEnumerable {
    case apple
    case banana
    case orange
}

_ = Fruit.cases // => [apple, banana, orange]
Fruit.cases.count // => 3
```

ただし、以下のようにAssociated ValueをもつEnumには使えません。

```swift:NG
// これはNG
enum OtherType: EnumEnumerable {
    case hoge(String)
    case fuga(Int)
}
```

## Swift2.xまでとの違い

ちなみに、Swift2.xまでの書き方は以下のようになっています。

```swift:Swift2.3までのEnumEnumerable
public protocol EnumEnumerable {
    associatedtype Case = Self
}

public extension EnumEnumerable where Case: Hashable {
    private static var generator: AnyGenerator<Case> {
        var n = 0
        return AnyGenerator {
            defer { n += 1 }
            let next = withUnsafePointer(&n) { UnsafePointer<Case>($0).memory }
            return next.hashValue == n ? next : nil
        }
    }

    @warn_unused_result
    public static func enumerate() -> EnumerateSequence<AnySequence<Case>> {
        return AnySequence(generator).enumerate()
    }

    public static var cases: [Case] {
        return Array(generator)
    }

    public static var count: Int {
        return cases.count
    }
}
```

変更点に関しては以下の通りです。

- AnyGenerator → **`AnyIterator`**
- UnsafePointer.memory → UnsafePointer. **`pointee`**
- EnumerateSequence → **`EnumeratedSequence`**
- AnySequence.enumerate() → **`AnySequence.enumerated()`**

いずれも、Swift3.0で承認されたAPI Guidelineに則った形でStandard Libraryに変更が適応されたことによる影響で、リネームされています。
[SE-0006](https://github.com/apple/swift-evolution/blob/master/proposals/0006-apply-api-guidelines-to-the-standard-library.md)あたりに書いてあります。

それ以外はSwift3.0でも問題なく動作しています。

## 以前書いた記事とか
- [enumの列挙子を配列で取得するのをprotocolで](http://qiita.com/su_k/items/1781259463290e909092)
- [AnyGeneratorの今後](http://blog.sgr-ksmt.org/2016/03/22/any_generator_future/)