enumの列挙子を配列で取得するのをprotocolで


___Swift3.0版は[こちら](http://qiita.com/su_k/items/c1c6a91324cf12151256)です。___

___(2016/03/22): Swift2.2対応しました。[^1]___
Swift2.1.1までの書き方も残しています。

## なぜ

enum に宣言した全ての`case`がほしい時に、

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

としてしまうのは、後に`case`が増えた時に漏れる可能性もあるし、他にも同じことをやろうと思った時に書き方が冗長的になってしまうので、protocolを定義してみました。

## 実装

### __Swift2.2__ での書き方

```swift
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
    }
}
```

#### Swift2.1.1との差分

- `EnumEnumerable`の *typealias* が **associatedtype** に変わっています。
- `anygenerator()`関数が *deprecated* になったので、 `AnyGenerator`のイニシャライザに変わっています。
- EnumerateSequenceの`init`が *deprecated* になったので、`AnySequence(generator).enumerate()`に変わっています。

## Swift2.1.1までの書き方

```swift
public protocol EnumEnumerable {
    typealias 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 EnumerateSequence(AnySequence(generator))
    }
    
    public static var cases: [Case] {
        return Array(generator)
    }
    
    public static var count: Int {
        return cases.count
    }
}
```

__※以下の解説はSwift2.1.1時点のものです。Swift2.2以降で若干コードに差異があります。__

ポイントとなるのは *generator()* の中身で、
参考にした情報[^2]曰く、enumはデフォルトでHashableに適合していて、caseを割り当てた順に、`0, 1, 2, ...`とhash値が振られるので、
*withUnsafePointer* と *UnsafePointer* を用いてhash値からcaseを復元します。
復元したcaseの **hashValue** と、復元する時に投げた **n** の値を見て、一致していたら **next** を返し、一致しなければ **nil** を返してgenerateを止めます。
nextを返した後は、nの値をインクリメントします。

例えば、

```swift
enum SomeTypes {
	case A, B, C, D
}
```

とした時は、 **next.hashValue** と **n** の値の遷移は以下のようになります。

```swift
next.hashValue: 0
n: 0
// return A
----
next.hashValue: 1
n: 1 
// return B
----
next.hashValue: 2
n: 2
// return C
----
next.hashValue: 3
n: 3
// return D
----
next.hashValue: 0
n: 4 
// return nil
// =>ここで異なる値になるので、nextとしてnilを返すことで、正しく全てのcaseが取得できる。
---- 

```

hashValueが`0→1→2→3→0`となるのはおそらくこの場合の割当が、A,B,C,Dで4つなので、`n % 4`としてhashValueが与えられるからだと思ってます。ちょっと自信ない。。
(この例で、nに10を入れて`next.hashValue`を見ると、 **2** になっているので間違ってはなさそう。)

あとは、enumerate()で列挙する場合と、当初の目的である配列で取得する場合とを用意します。
尚、enumerate()は、 *SequenceType* の

```swift
extension SequenceType {
    @warn_unused_result
    public func enumerate() -> EnumerateSequence<Self>
}

```

と同様に、 **EnumSequence** として返すようにしています。indexが不要の場合は、 **AnySequence** で返せば良いです。

```swift
@warn_unused_result
static func enumerate() -> AnySequence<Case> {
    return AnySequence(generator())
}
```

## 使い方

enumに *EnumEnumerable* を適合するだけです。

**`enum Hoge: Int, EnumEnumerable`**　でも、
**`enum Fuga: String, EnumEnumerable`**　でも、
**`enum Piyo: EnumEnumerable`**　でも、
問題なく使用できます。

```swift
enum Hoge: Int, EnumEnumerable {
    case A, B, C, D
}

enum Fuga: String, EnumEnumerable {
    case A, B, C, D, E
}
    
enum Piyo: EnumEnumerable {
    case A, B, C, D, E, F
}

Hoge.count // 4
Fuga.cases // [Fuga.A, Fuga.B, Fuga.C, Fuga.D, Fuga.E]
Piyo.enumerate().forEach { print($0.0,$0.1) }
/*
0 A
1 B
2 C
3 D
4 E
5 F
*/
```


## 注意
デフォルトでenumは *Hashable* に適合してはいるものの、以下のように **Associated Value**を持つ`case`を宣言してしまうと、それが無効になるので、上記の列挙方法は使えなくなります。

```swift
// これはできない
enum SomeTypes: EnumEnumerable {
    case A(String)
    case B(Int)
}
//----
SomeTypes.cases // error!
```

## 参考
- http://stackoverflow.com/a/24562707
- http://stackoverflow.com/a/28341290

[^1]: また、将来的に、Swift3.0でAnyGeneratorがAnyIteratorに変わる可能性があるので、近くなったらそれに合わせて更新します。
[^2]: http://stackoverflow.com/a/24562707 AssociatedValueを持たなければ、enumはデフォルトでHashableに適合していると言及されている。<br />`enum Piyo { case A }` としたときに、`Piyo.A.hashValue`を呼び出せるので、Hashableに適合しているのは確かである