-
-
Save rickpasveer/ab4d3d538082796d68af8b47a14f388d to your computer and use it in GitHub Desktop.
Helper functions for enumerating values of a Swift enum
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
protocol ConvertibleFromRawInt { | |
static func fromRaw(raw: Int) -> Self? | |
} | |
// Note: Tried to use Swift's standard RawRepresentable protocol rather | |
// than ConvertibleFromRawInt, but couldn't get it to compile. | |
// Don't know whether it is a Swift bug or something I was doing wrong. | |
// Generator for a sequence of contiguous ConvertibleFromRawInt values | |
class ConvertibleFromRawIntGenerator<T: ConvertibleFromRawInt>: GeneratorType { | |
typealias Element = T | |
var nextRawValue: Int | |
init(firstRawValue: Int) { | |
nextRawValue = firstRawValue | |
} | |
func next() -> T? { | |
return T.fromRaw(nextRawValue++) | |
} | |
} | |
// Generator for a sequence of ConvertibleFromRawIntValues bounded by low and high raw values | |
class ConvertibleFromRawIntRangeGenerator<T: ConvertibleFromRawInt>: GeneratorType { | |
typealias Element = T | |
var nextRawValue: Int | |
var lastRawValue: Int | |
init(firstRawValue: Int, lastRawValue: Int) { | |
self.nextRawValue = firstRawValue | |
self.lastRawValue = lastRawValue | |
} | |
init(range: Range<Int>) { | |
self.nextRawValue = range.startIndex | |
self.lastRawValue = range.endIndex - 1 | |
} | |
func next() -> T? { | |
if (nextRawValue <= lastRawValue) { | |
return T.fromRaw(nextRawValue++) | |
} | |
else { | |
return nil | |
} | |
} | |
} | |
// Given the first raw value of a ConvertibleFromRawInt type, generate values until fromRaw() returns nil | |
func enumerateFromRawValue<T: ConvertibleFromRawInt>(firstRawValue: Int) -> AnySequence<T> { | |
return AnySequence<T>({ ConvertibleFromRawIntGenerator(firstRawValue: firstRawValue) }) | |
} | |
// Given first and last raw values of a range of valid raw values for a ConvertibleFromRawType type, generate a sequence of corresponding values | |
func enumerate<T: ConvertibleFromRawInt>(firstRawValue: Int, lastRawValue: Int) -> AnySequence<T> { | |
return AnySequence<T>({ ConvertibleFromRawIntRangeGenerator(firstRawValue: firstRawValue, lastRawValue: lastRawValue) }) | |
} | |
// Given a range of valid raw values for a ConvertibleFromRawType type, generate a sequence of corresponding values | |
func enumerate<T: ConvertibleFromRawInt>(range: Range<Int>) -> AnySequence<T> { | |
return AnySequence<T>({ ConvertibleFromRawIntRangeGenerator(range: range) }) | |
} | |
// Examples | |
enum Suit: Int { | |
case Clubs, Diamonds, Hearts, Spades | |
} | |
extension Suit: CustomStringConvertible { | |
var description: String { | |
switch (self) { | |
case .Clubs: return "Clubs" | |
case .Diamonds: return "Diamonds" | |
case .Hearts: return "Hearts" | |
case .Spades: return "Spades" | |
} | |
} | |
} | |
// Enumerate all the suits | |
extension Suit: ConvertibleFromRawInt { | |
static func enumerate() -> AnySequence<Suit> { | |
return enumerateFromRawValue(Suit.Clubs.rawValue) | |
} | |
static func fromRaw(raw: Int) -> Suit? { | |
return Suit(rawValue: raw) | |
} | |
} | |
for suit in Suit.enumerate() { | |
print("\(suit.description) = \(suit.rawValue)\n") | |
} | |
/* Output: | |
Clubs = 0 | |
Diamonds = 1 | |
Hearts = 2 | |
Spades = 3 | |
*/ | |
enum Rank: Int { | |
case Wild = 0 | |
case Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace | |
} | |
extension Rank: CustomStringConvertible { | |
var description: String { | |
switch (self) { | |
case .Two: return "Two" | |
case .Three: return "Three" | |
case .Four: return "Four" | |
case .Five: return "Five" | |
case .Six: return "Six" | |
case .Seven: return "Seven" | |
case .Eight: return "Eight" | |
case .Nine: return "Nine" | |
case .Ten: return "Ten" | |
case .Jack: return "Jack" | |
case .Queen: return "Queen" | |
case .King: return "King" | |
case .Ace: return "Ace" | |
default: return "(Rank \(self.rawValue))" | |
} | |
} | |
} | |
// Enumerate all the Ranks, skipping over "Wild" | |
extension Rank: ConvertibleFromRawInt { | |
// Enumerate rank values [ Two, Three, ..., King, Ace ] | |
static func enumerate() -> AnySequence<Rank> { | |
return enumerateFromRawValue(Rank.Two.rawValue) | |
} | |
static func fromRaw(raw: Int) -> Rank? { | |
return Rank(rawValue: raw) | |
} | |
} | |
for rank in Rank.enumerate() { | |
print("\(rank.description) = \(rank.rawValue)\n") | |
} | |
/* Output | |
Two = 2 | |
Three = 3 | |
Four = 4 | |
Five = 5 | |
Six = 6 | |
Seven = 7 | |
Eight = 8 | |
Nine = 9 | |
Ten = 10 | |
Jack = 11 | |
Queen = 12 | |
King = 13 | |
Ace = 14 | |
*/ | |
// Enumerate the face cards | |
let faceCardRange = Rank.Jack.rawValue...Rank.King.rawValue | |
let faceCards: AnySequence<Rank> = enumerate(faceCardRange) | |
for faceCard in faceCards { | |
print("Face card: \(faceCard.description) = \(faceCard.rawValue)\n") | |
} | |
/* Output | |
Face card: Jack = 11 | |
Face card: Queen = 12 | |
Face card: King = 13 | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
updated for swift 2