//===--- BridgeStorage.swift.gyb ------------------------------*- swift -*-===// // // 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 // //===----------------------------------------------------------------------===// // // Bridged types are notionally single-word beasts that either store // an objc class or a native Swift class. We'd like to be able to // distinguish these cases efficiently. // //===----------------------------------------------------------------------===// // RUN: rm -rf %t && mkdir -p %t && %S/../../utils/gyb %s -o %t/out.swift // RUN: %S/../../utils/line-directive %t/out.swift -- %target-build-swift -parse-stdlib %t/out.swift -o %t/a.out // RUN: %S/../../utils/line-directive %t/out.swift -- %target-run %t/a.out // REQUIRES: executable_test // REQUIRES: objc_interop import Swift //===--- Code mimics the stdlib without using spare pointer bits ----------===// import SwiftShims protocol BridgeStorage { typealias Native : AnyObject typealias ObjC : AnyObject init(native: Native, bits: Int) init(native: Native) init(objC: ObjC) mutating func isUniquelyReferencedNative() -> Bool mutating func isUniquelyReferenced_native_noSpareBits() -> Bool var isNative: Bool {get} var isObjC: Bool {get} var nativeInstance: Native {get} var nativeInstance_noSpareBits: Native {get} var objCInstance: ObjC {get} var spareBits: Int {get} } extension _BridgeStorage : BridgeStorage {} //===----------------------------------------------------------------------===// //===--- Testing code -----------------------------------------------------===// //===----------------------------------------------------------------------===// import StdlibUnittest var allTests = TestSuite("DiscriminatedBridgeObject") class C { deinit { print("bye C!") } } import Foundation func isOSAtLeast(major: Int, _ minor: Int, patch: Int = 0) -> Bool { // isOperatingSystemAtLeastVersion() is unavailable on some OS versions. if #available(iOS 8.0, OSX 10.10, *) { let procInfo: AnyObject = NSProcessInfo.processInfo() return procInfo.isOperatingSystem(atLeastVersion: NSOperatingSystemVersion(majorVersion: major, minorVersion: minor, patchVersion: patch)) } return false } func expectTagged(s: NSString, _ expected: Bool) -> NSString { #if arch(x86_64) let mask: UInt = 0x8000000000000001 #elseif arch(arm64) let mask: UInt = 0x8000000000000000 #else let mask: UInt = 0 #endif var osSupportsTaggedStrings: Bool #if os(iOS) // NSTaggedPointerString is enabled starting in iOS 9.0. osSupportsTaggedStrings = isOSAtLeast(9,0) #elseif os(tvOS) || os(watchOS) // NSTaggedPointerString is supported in all versions of TVOS and watchOS. osSupportsTaggedStrings = true #elseif os(OSX) // NSTaggedPointerString is enabled starting in OS X 10.10. osSupportsTaggedStrings = isOSAtLeast(10,10) #endif let taggedStringsSupported = osSupportsTaggedStrings && mask != 0 let tagged = unsafeBitCast(s, to: UInt.self) & mask != 0 if taggedStringsSupported && expected == tagged { // okay } else if !taggedStringsSupported && !tagged { // okay } else { let un = !tagged ? "un" : "" fatalError("Unexpectedly \(un)tagged pointer for string \"\(s)\"") } return s } var taggedNSString : NSString { return expectTagged(NSString(format: "foo"), true) } var unTaggedNSString : NSString { return expectTagged("fûtbōl" as NSString, false) } % for Self in ['_BridgeStorage']: allTests.test("${Self}") { typealias B = ${Self} let oy: NSString = "oy" expectTrue(B(objC: oy).objCInstance == oy) for i in 0..<2 { if true { var b = B(native: C(), bits: i) expectFalse(b.isObjC) expectTrue(b.isNative) expectTrue(b.isUniquelyReferencedNative()) if i == 0 { expectTrue(b.isUniquelyReferenced_native_noSpareBits()) } expectEqual(i, b.spareBits) } if true { let c = C() var b = B(native: c, bits: i) expectFalse(b.isObjC) expectTrue(b.isNative) expectFalse(b.isUniquelyReferencedNative()) expectEqual(i, b.spareBits) expectTrue(b.nativeInstance === c) if i == 0 { expectTrue(b.nativeInstance_noSpareBits === c) expectFalse(b.isUniquelyReferenced_native_noSpareBits()) } } } var b = B(native: C(), bits: 0) expectTrue(b.isUniquelyReferencedNative()) // Add a reference and verify that it's still native but no longer unique var c = b expectFalse(b.isUniquelyReferencedNative()) _fixLifetime(c) // make sure c is not killed early let n = C() var bb = B(native: n) expectEqual(0, bb.spareBits) expectTrue(bb.nativeInstance === n) expectTrue(bb.isNative) expectFalse(bb.isObjC) var d = B(objC: taggedNSString) expectFalse(d.isUniquelyReferencedNative()) expectFalse(d.isNative) expectTrue(d.isObjC) d = B(objC: unTaggedNSString) expectFalse(d.isUniquelyReferencedNative()) expectFalse(d.isNative) expectTrue(d.isObjC) } % end runAllTests()