// Dynamic cast without bridging func dynamicCast(_ 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(_ 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) }