blob: a22f3751d275a72c7759a23f8b16d5b0cb091acc [file] [log] [blame]
//===--- BridgeStorage.swift - Discriminated storage for bridged types ----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Types that are bridged to Objective-C need to manage an object
// that may be either some native class or the @objc Cocoa
// equivalent. _BridgeStorage discriminates between these two
// possibilities and stores a few extra bits when the stored type is
// native. It is assumed that the @objc class instance may in fact
// be a tagged pointer, and thus no extra bits may be available.
//
//===----------------------------------------------------------------------===//
import SwiftShims
@_fixed_layout
public // @testable
struct _BridgeStorage<
NativeClass: AnyObject, ObjCClass: AnyObject
> {
public // @testable
typealias Native = NativeClass
public // @testable
typealias ObjC = ObjCClass
@inlinable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
init(native: Native, bits: Int) {
_sanityCheck(_usesNativeSwiftReferenceCounting(NativeClass.self))
// More bits are available on some platforms, but it's not portable
_sanityCheck(0...1 ~= bits,
"BridgeStorage can't store bits outside the range 0...1")
rawValue = _makeNativeBridgeObject(
native, UInt(bits) << _objectPointerLowSpareBitShift)
}
@inlinable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
init(objC: ObjC) {
_sanityCheck(_usesNativeSwiftReferenceCounting(NativeClass.self))
rawValue = _makeObjCBridgeObject(objC)
}
@inlinable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
init(native: Native) {
_sanityCheck(_usesNativeSwiftReferenceCounting(NativeClass.self))
rawValue = Builtin.reinterpretCast(native)
}
@inlinable // FIXME(sil-serialize-all)
public // @testable
var spareBits: Int {
@inline(__always) get {
_sanityCheck(isNative)
return Int(
_nonPointerBits(rawValue) >> _objectPointerLowSpareBitShift)
}
}
@inlinable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
mutating func isUniquelyReferencedNative() -> Bool {
return _isUnique(&rawValue)
}
@inlinable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
mutating func isUniquelyReferencedOrPinnedNative() -> Bool {
return _isUniqueOrPinned(&rawValue)
}
@inlinable // FIXME(sil-serialize-all)
public // @testable
var isNative: Bool {
@inline(__always) get {
let result = Builtin.classifyBridgeObject(rawValue)
return !Bool(Builtin.or_Int1(result.isObjCObject,
result.isObjCTaggedPointer))
}
}
@inlinable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
func isNativeWithClearedSpareBits(_ bits: Int) -> Bool {
return (_bitPattern(rawValue) &
(_objCTaggedPointerBits | _objectPointerIsObjCBit |
(UInt(bits)) << _objectPointerLowSpareBitShift)) == 0
}
@inlinable // FIXME(sil-serialize-all)
public // @testable
var isObjC: Bool {
@inline(__always) get {
return !isNative
}
}
@inlinable // FIXME(sil-serialize-all)
public // @testable
var nativeInstance: Native {
@inline(__always) get {
_sanityCheck(isNative)
return Builtin.castReferenceFromBridgeObject(rawValue)
}
}
@inlinable // FIXME(sil-serialize-all)
public // @testable
var nativeInstance_noSpareBits: Native {
@inline(__always) get {
_sanityCheck(isNative)
_sanityCheck(_nonPointerBits(rawValue) == 0)
return Builtin.reinterpretCast(rawValue)
}
}
@inlinable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
mutating func isUniquelyReferenced_native_noSpareBits() -> Bool {
_sanityCheck(isNative)
return _isUnique_native(&rawValue)
}
@inlinable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
mutating func isUniquelyReferencedOrPinned_native_noSpareBits() -> Bool {
_sanityCheck(isNative)
return _isUniqueOrPinned_native(&rawValue)
}
@inlinable // FIXME(sil-serialize-all)
public // @testable
var objCInstance: ObjC {
@inline(__always) get {
_sanityCheck(isObjC)
return Builtin.castReferenceFromBridgeObject(rawValue)
}
}
//===--- private --------------------------------------------------------===//
@inlinable // FIXME(sil-serialize-all)
@usableFromInline // FIXME(sil-serialize-all)
internal var _isTagged: Bool {
@inline(__always) get {
return Bool(Builtin.classifyBridgeObject(rawValue).isObjCTaggedPointer)
}
}
// rawValue is passed inout to _isUnique. Although its value
// is unchanged, it must appear mutable to the optimizer.
@usableFromInline
internal var rawValue: Builtin.BridgeObject
}