Created
May 26, 2016 19:36
-
-
Save callionica/fd7f4c4ef095f81aea538227d5e9effb to your computer and use it in GitHub Desktop.
This file contains 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
// Dynamic cast without bridging | |
func dynamicCast<T>(_ type: T.Type, _ v: Any)->T? { | |
guard let result = v as? T where v.dynamicType is T.Type else { | |
return nil; | |
} | |
return result | |
} | |
// Return a 2uple if both objects are convertible to type T, otherwise nil | |
func matchCast<T>(_ type: T.Type, _ l: Any, _ r: Any)->(T, T)? { | |
guard let l = dynamicCast(type, l) else { | |
return nil; | |
} | |
guard let r = dynamicCast(type, r) else { | |
return nil; | |
} | |
return (l, r) | |
} | |
// False for different dynamic types | |
// Reference equality for objects | |
// Operator == for known primitive types (Bool, String, Int*, UInt*, Float*, Double) | |
// Tuples, structs, sets, collections, and dictionaries get memberwise comparison | |
// Enums get a string comparison on their dump output | |
// False for everything else | |
func equal(_ l: Any, _ r: Any)->Bool { | |
// Check if types are the same | |
if (l.dynamicType != r.dynamicType) { | |
return false | |
} | |
// Include this if you import Foundation | |
// if let m = matchCast(NSNumber.self, l, r) { | |
// return m.0 == m.1 | |
// } | |
// if let m = matchCast(NSString.self, l, r) { | |
// return m.0 == m.1 | |
// } | |
// Must come after primitive tests | |
if let m = matchCast(AnyObject.self, l, r) { | |
return m.0 === m.1 // Reference equality | |
} | |
if let m = matchCast(String.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(Bool.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(Int.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(Int8.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(Int16.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(Int32.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(Int64.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(UInt.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(UInt8.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(UInt16.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(UInt32.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(UInt64.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(Float.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(Float80.self, l, r) { | |
return m.0 == m.1 | |
} | |
if let m = matchCast(Double.self, l, r) { | |
return m.0 == m.1 | |
} | |
func equalCompound(_ l: Any, _ r : Any)->Bool { | |
func isEnum(mirror: Mirror)->Bool { | |
guard let ds = mirror.displayStyle else { | |
return false; | |
} | |
return ds == .Enum | |
} | |
func equalDump(_ l: Any, _ r: Any)->Bool { | |
var o1 = "" | |
dump(l, &o1) | |
var o2 = "" | |
dump(r, &o2) | |
return o1 == o2 | |
} | |
func isWorkingDisplayStyle(ds: Mirror.DisplayStyle?)->Bool { | |
guard let ds = ds else { | |
return false; | |
} | |
switch (ds) { | |
case .Class: | |
return false // Don't expect to use because we use ref equality | |
case .Enum: | |
return false // Can't use because case doesn't show up in mirror (but associated data does) | |
case .Collection: | |
return true // Looks OK | |
case .Dictionary: | |
return true // Looks OK | |
case .Optional: | |
return true // Looks OK - works because the cases have different number of children | |
case .Set: | |
return true // Looks OK | |
case .Tuple: | |
return true // Looks OK | |
case .Struct: | |
return true // Looks OK | |
} | |
} | |
let m1 = Mirror(reflecting: l) | |
let m2 = Mirror(reflecting: r) | |
if (isEnum(m1) && isEnum(m2)) { | |
// We can't get the case from the Mirror object or dynamicType | |
// so we resort to using dump and comparing the strings | |
return equalDump(l, r) | |
} | |
guard (isWorkingDisplayStyle(m1.displayStyle)) && | |
(m1.displayStyle == m2.displayStyle) && | |
(m1.children.count == m2.children.count) else { | |
return false; | |
} | |
for (p1, p2) in zip(m1.children, m2.children) { | |
if (!equal(p1.1, p2.1)) { | |
return false; | |
} | |
} | |
return true | |
} | |
return equalCompound(l, r) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Code from http://www.callionica.com/developer/#any-equals