|
12 | 12 |
|
13 | 13 | import CoreFoundation
|
14 | 14 |
|
| 15 | +#if canImport(ObjectiveC) |
| 16 | +import ObjectiveC |
| 17 | +#endif |
| 18 | + |
15 | 19 | public protocol _StructBridgeable {
|
16 | 20 | func _bridgeToAny() -> Any
|
17 | 21 | }
|
@@ -85,7 +89,71 @@ internal final class _SwiftValue : NSObject, NSCopying {
|
85 | 89 | return nil
|
86 | 90 | }
|
87 | 91 |
|
| 92 | + #if canImport(ObjectiveC) |
| 93 | + private static var _objCNSNullClassStorage: Any.Type? |
| 94 | + private static var objCNSNullClass: Any.Type? { |
| 95 | + if let type = _objCNSNullClassStorage { |
| 96 | + return type |
| 97 | + } |
| 98 | + |
| 99 | + let name = "NSNull" |
| 100 | + let maybeType = name.withCString { cString in |
| 101 | + return objc_getClass(cString) |
| 102 | + } |
| 103 | + |
| 104 | + if let type = maybeType as? Any.Type { |
| 105 | + _objCNSNullClassStorage = type |
| 106 | + return type |
| 107 | + } else { |
| 108 | + return nil |
| 109 | + } |
| 110 | + } |
| 111 | + |
| 112 | + private static var _swiftStdlibSwiftValueClassStorage: Any.Type? |
| 113 | + private static var swiftStdlibSwiftValueClass: Any.Type? { |
| 114 | + if let type = _swiftStdlibSwiftValueClassStorage { |
| 115 | + return type |
| 116 | + } |
| 117 | + |
| 118 | + let name = "_SwiftValue" |
| 119 | + let maybeType = name.withCString { cString in |
| 120 | + return objc_getClass(cString) |
| 121 | + } |
| 122 | + |
| 123 | + if let type = maybeType as? Any.Type { |
| 124 | + _swiftStdlibSwiftValueClassStorage = type |
| 125 | + return type |
| 126 | + } else { |
| 127 | + return nil |
| 128 | + } |
| 129 | + } |
| 130 | + |
| 131 | + #endif |
| 132 | + |
88 | 133 | static func fetch(nonOptional object: AnyObject) -> Any {
|
| 134 | + #if canImport(ObjectiveC) |
| 135 | + // You can pass the result of a `as AnyObject` expression to this method. This can have one of three results on Darwin: |
| 136 | + // - It's a SwiftFoundation type. Bridging will take care of it below. |
| 137 | + // - It's nil. The compiler is hardcoded to return [NSNull null] for nils. |
| 138 | + // - It's some other Swift type. The compiler will box it in a native _SwiftValue. |
| 139 | + // Case 1 is handled below. |
| 140 | + // Case 2 is handled here: |
| 141 | + if type(of: object as Any) == objCNSNullClass { |
| 142 | + return Optional<Any>.none as Any |
| 143 | + } |
| 144 | + // Case 3 is handled here: |
| 145 | + if type(of: object as Any) == swiftStdlibSwiftValueClass { |
| 146 | + return object |
| 147 | + // Since this returns Any, the object is casted almost immediately — e.g.: |
| 148 | + // _SwiftValue.fetch(x) as SomeStruct |
| 149 | + // which will immediately unbox the native box. For callers, it will be exactly |
| 150 | + // as if we returned the unboxed value directly. |
| 151 | + } |
| 152 | + |
| 153 | + // On Linux, case 2 is handled below, and case 3 can't happen — |
| 154 | + // the compiler will produce SwiftFoundation._SwiftValue boxes rather than ObjC ones. |
| 155 | + #endif |
| 156 | + |
89 | 157 | if object === kCFBooleanTrue {
|
90 | 158 | return true
|
91 | 159 | } else if object === kCFBooleanFalse {
|
|
0 commit comments