Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
// Retrieves and recasts the body of an enum
func body<T, U>(of value: inout T) -> U {
return withUnsafePointer(to: &value) {
$0.withMemoryRebound(to: U.self, capacity: 1) {
$0.pointee
}
}
}
// For enums with associated values, the case flag is stored in the last byte
func flag<T>(of value: inout T) -> UInt8 {
let size = MemoryLayout<T>.size
return withUnsafePointer(to: &value) {
$0.withMemoryRebound(to: UInt8.self, capacity: size) { $0[size - 1] }
}
}
func ~=<T, U>(lhs: T, rhs: (U) -> T) -> Bool {
var lhs = lhs
var result = rhs(body(of: &lhs))
return flag(of: &lhs) == flag(of: &result)
}
enum Enum {
case foo(Int)
case bar(String)
case qux(Int)
}
let items: [Enum] = [.foo(1), .bar("hi"), .foo(2)]
let filtered = items.filter { $0 ~= Enum.bar }
@kvaughan-ct

This comment has been minimized.

Copy link

kvaughan-ct commented Feb 10, 2017

I was excited for this solution, but it crashes in a couple of scenarios :( First, extend the enum out to have a non-associated type, and an associative type with a more complex tuple. Extend the test items list to include instances of these.

enum Enum {
    case foo(Int)
    case bar(String)
    case qux(Int)
    case thud
    case xyzzy(Int, String)
}

let items: [Enum] = [.foo(1), .bar("hi"), .foo(2), .thud, .xyzzy(3, "bye")]

The following breaks because of expected argument types, but could be overcome with an alternate definition for ~=:

let filtered = items.filter { $0 ~= Enum.thud }

Testing for .bar crashes:

let filtered = items.filter { $0 ~= Enum.bar }

Though interestingly, testing for .foo still works, I think because the first parameter is still an Int type (if you reverse xyzzy to be (String, Int), then it's .bar that works and .foo that crashes):

let filtered = items.filter { $0 ~= Enum.foo }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.