Skip to content

Instantly share code, notes, and snippets.

@erica
Last active February 19, 2019 23:10
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save erica/dd1f6616b4124c588cf7 to your computer and use it in GitHub Desktop.
Save erica/dd1f6616b4124c588cf7 to your computer and use it in GitHub Desktop.
import Cocoa
// Note: use of enumeration var in generic is instadeath
// Note: use of static var in generic is not yet supported
public protocol EnumConvertible: Hashable {
init?(hashValue hash: Int)
static func countMembers() -> Int
static func members() -> [Self]
}
extension EnumConvertible where Self:Hashable {
internal static func fromHash(hashValue index: Int) -> Self {
let member = unsafeBitCast(UInt8(index), Self.self)
return member
}
static public func countMembers() -> Int {
// Cannot add storage to protocol at this time, so this gets computed each call
let byteCount = sizeof(self)
if byteCount == 0 {return 1}
if byteCount > 2 {fatalError("Unable to process enumeration")}
let singleByte = byteCount == 1
let minValue = singleByte ? 2 : 257
let maxValue = singleByte ? 2 << 8 : 2 << 16
for hashIndex in minValue..<maxValue {
switch singleByte {
case true:
if unsafeBitCast(UInt8(hashIndex), self).hashValue == 0 {
return hashIndex
}
case false:
if unsafeBitCast(UInt16(hashIndex), self).hashValue == 0 {
return hashIndex
}
}
}
return maxValue
}
static public func members() -> [Self] {
var enumerationMembers = [Self]()
let singleByte = sizeof(self) == 1
for index in 0..<Self.countMembers() {
switch singleByte {
case true:
let member = unsafeBitCast(UInt8(index), self)
enumerationMembers.append(member)
case false:
let member = unsafeBitCast(UInt16(index), self)
enumerationMembers.append(member)
}
}
return enumerationMembers
}
public init?(hashValue hash: Int) {
if hash >= Self.countMembers() {return nil}
self = Self.fromHash(hashValue: hash)
}
}
enum Planets : Int, EnumConvertible {case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Neptune, Uranus, Pluto}
enum Foo : Int, EnumConvertible {case i = 1, j = 5, k = 9}
enum Coin : EnumConvertible {case Heads, Tails}
enum Quark: String, EnumConvertible {case Up, Down, Top, Bottom, Strange, Charmed}
print(Planets.members())
print(Foo.members())
print(Coin.members())
print(Quark.members())
Quark(hashValue: 2)!.rawValue
Foo(hashValue: 0)!.rawValue
Foo(hashValue: 23)
Foo(hashValue: 0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment