| //===----------------------------------------------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| import CoreFoundation |
| |
| #if canImport(ObjectiveC) |
| import ObjectiveC |
| #endif |
| |
| public protocol _StructBridgeable { |
| func _bridgeToAny() -> Any |
| } |
| |
| fileprivate protocol Unwrappable { |
| func unwrap() -> Any? |
| } |
| |
| extension Optional: Unwrappable { |
| func unwrap() -> Any? { |
| return self |
| } |
| } |
| |
| /// - Note: This does not exist currently on Darwin but it is the inverse correlation to the bridge types such that a |
| /// reference type can be converted via a callout to a conversion method. |
| public protocol _StructTypeBridgeable : _StructBridgeable { |
| associatedtype _StructType |
| |
| func _bridgeToSwift() -> _StructType |
| } |
| |
| // Default adoption of the type specific variants to the Any variant |
| extension _ObjectiveCBridgeable { |
| public func _bridgeToAnyObject() -> AnyObject { |
| return _bridgeToObjectiveC() |
| } |
| } |
| |
| extension _StructTypeBridgeable { |
| public func _bridgeToAny() -> Any { |
| return _bridgeToSwift() |
| } |
| } |
| |
| // slated for removal, these are the swift-corelibs-only variant of the _ObjectiveCBridgeable |
| internal protocol _CFBridgeable { |
| associatedtype CFType |
| var _cfObject: CFType { get } |
| } |
| |
| internal protocol _SwiftBridgeable { |
| associatedtype SwiftType |
| var _swiftObject: SwiftType { get } |
| } |
| |
| internal protocol _NSBridgeable { |
| associatedtype NSType |
| var _nsObject: NSType { get } |
| } |
| |
| |
| #if !canImport(ObjectiveC) |
| // The _NSSwiftValue protocol is in the stdlib, and only available on platforms without ObjC. |
| extension __SwiftValue: _NSSwiftValue {} |
| #endif |
| |
| /// - Note: This is an internal boxing value for containing abstract structures |
| internal final class __SwiftValue : NSObject, NSCopying { |
| public private(set) var value: Any |
| |
| static func fetch(_ object: AnyObject?) -> Any? { |
| if let obj = object { |
| let value = fetch(nonOptional: obj) |
| if let wrapper = value as? Unwrappable, wrapper.unwrap() == nil { |
| return nil |
| } else { |
| return value |
| } |
| } |
| return nil |
| } |
| |
| #if canImport(ObjectiveC) |
| private static var _objCNSNullClassStorage: Any.Type? |
| private static var objCNSNullClass: Any.Type? { |
| if let type = _objCNSNullClassStorage { |
| return type |
| } |
| |
| let name = "NSNull" |
| let maybeType = name.withCString { cString in |
| return objc_getClass(cString) |
| } |
| |
| if let type = maybeType as? Any.Type { |
| _objCNSNullClassStorage = type |
| return type |
| } else { |
| return nil |
| } |
| } |
| |
| private static var _swiftStdlibSwiftValueClassStorage: Any.Type? |
| private static var swiftStdlibSwiftValueClass: Any.Type? { |
| if let type = _swiftStdlibSwiftValueClassStorage { |
| return type |
| } |
| |
| let name = "__SwiftValue" |
| let maybeType = name.withCString { cString in |
| return objc_getClass(cString) |
| } |
| |
| if let type = maybeType as? Any.Type { |
| _swiftStdlibSwiftValueClassStorage = type |
| return type |
| } else { |
| return nil |
| } |
| } |
| |
| #endif |
| |
| static func fetch(nonOptional object: AnyObject) -> Any { |
| #if canImport(ObjectiveC) |
| // You can pass the result of a `as AnyObject` expression to this method. This can have one of three results on Darwin: |
| // - It's a SwiftFoundation type. Bridging will take care of it below. |
| // - It's nil. The compiler is hardcoded to return [NSNull null] for nils. |
| // - It's some other Swift type. The compiler will box it in a native __SwiftValue. |
| // Case 1 is handled below. |
| // Case 2 is handled here: |
| if type(of: object as Any) == objCNSNullClass { |
| return Optional<Any>.none as Any |
| } |
| // Case 3 is handled here: |
| if type(of: object as Any) == swiftStdlibSwiftValueClass { |
| return object |
| // Since this returns Any, the object is casted almost immediately — e.g.: |
| // __SwiftValue.fetch(x) as SomeStruct |
| // which will immediately unbox the native box. For callers, it will be exactly |
| // as if we returned the unboxed value directly. |
| } |
| |
| // On Linux, case 2 is handled by the stdlib bridging machinery, and case 3 can't happen — |
| // the compiler will produce SwiftFoundation.__SwiftValue boxes rather than ObjC ones. |
| #endif |
| |
| if object === kCFBooleanTrue { |
| return true |
| } else if object === kCFBooleanFalse { |
| return false |
| } else if let container = object as? __SwiftValue { |
| return container.value |
| } else if let val = object as? _StructBridgeable { |
| return val._bridgeToAny() |
| } else { |
| return object |
| } |
| } |
| |
| static func store(optional value: Any?) -> NSObject? { |
| if let val = value { |
| return store(val) |
| } |
| return nil |
| } |
| |
| static func store(_ value: Any?) -> NSObject? { |
| if let val = value { |
| return store(val) |
| } |
| return nil |
| } |
| |
| static func store(_ value: Any) -> NSObject { |
| if let val = value as? NSObject { |
| return val |
| } else if let opt = value as? Unwrappable, opt.unwrap() == nil { |
| return NSNull() |
| } else { |
| #if canImport(ObjectiveC) |
| // On Darwin, this can be a native (ObjC) __SwiftValue. |
| let boxed = (value as AnyObject) |
| if !(boxed is NSObject) { |
| return __SwiftValue(value) // Do not emit native boxes — wrap them in Swift Foundation boxes instead. |
| } else { |
| return boxed as! NSObject |
| } |
| #else |
| return (value as AnyObject) as! NSObject |
| #endif |
| } |
| } |
| |
| init(_ value: Any) { |
| self.value = value |
| } |
| |
| override var hash: Int { |
| if let hashable = value as? AnyHashable { |
| return hashable.hashValue |
| } |
| return ObjectIdentifier(self).hashValue |
| } |
| |
| override func isEqual(_ value: Any?) -> Bool { |
| switch value { |
| case let other as __SwiftValue: |
| guard let left = other.value as? AnyHashable, |
| let right = self.value as? AnyHashable else { return self === other } |
| |
| return left == right |
| case let other as AnyHashable: |
| guard let hashable = self.value as? AnyHashable else { return false } |
| return other == hashable |
| default: |
| return false |
| } |
| } |
| |
| public func copy(with zone: NSZone?) -> Any { |
| return __SwiftValue(value) |
| } |
| |
| public static let null: AnyObject = NSNull() |
| } |