blob: 1354430fdb2abc2f1e151172e79d8f01388c632f [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
@_exported import Foundation // Clang module
import CoreGraphics
//===----------------------------------------------------------------------===//
// Numbers
//===----------------------------------------------------------------------===//
@_silgen_name("_swift_Foundation_TypePreservingNSNumberGetKind")
internal func _swift_Foundation_TypePreservingNSNumberGetKind(
_ value: NSNumber
) -> UInt8
// This enum has a matching counterpart in TypePreservingNSNumber.mm. Please
// update both copies when changing it.
internal enum _SwiftTypePreservingNSNumberTag : UInt8 {
case SwiftInt = 0
case SwiftInt64 = 1
case SwiftInt32 = 2
case SwiftInt16 = 3
case SwiftInt8 = 4
case SwiftUInt = 5
case SwiftUInt64 = 6
case SwiftUInt32 = 7
case SwiftUInt16 = 8
case SwiftUInt8 = 9
case SwiftFloat = 10
case SwiftDouble = 11
case SwiftCGFloat = 12
case SwiftBool = 13
}
// Conversions between NSNumber and various numeric types. The
// conversion to NSNumber is automatic (auto-boxing), while conversion
// back to a specific numeric type requires a cast.
%{
# The set of types we bridge to NSNumber using a Swift-type-preserving
# subclass. Note that this doesn't include Bool or CGFloat, which require
# special handling.
bridgedNumberTypes = [
('Int', 'int'),
('Int64', 'int64'),
('Int32', 'int32'),
('Int16', 'int16'),
('Int8', 'int8'),
('UInt', 'uint'),
('UInt64', 'uint64'),
('UInt32', 'uint32'),
('UInt16', 'uint16'),
('UInt8', 'uint8'),
('Float', 'float'),
('Double', 'double'),
]
}%
% for NumberType, accessorName in bridgedNumberTypes:
@_silgen_name("_swift_Foundation_TypePreservingNSNumberWith${NumberType}")
internal func _swift_Foundation_TypePreservingNSNumberWith${NumberType}(
_ value: ${NumberType}
) -> NSNumber
@_silgen_name("_swift_Foundation_TypePreservingNSNumberGetAs${NumberType}")
internal func _swift_Foundation_TypePreservingNSNumberGetAs${NumberType}(
_ value: NSNumber
) -> ${NumberType}
extension ${NumberType} : _ObjectiveCBridgeable {
public init(_ number: NSNumber) {
self = number.${accessorName}Value
}
@_semantics("convertToObjectiveC")
public func _bridgeToObjectiveC() -> NSNumber {
return _swift_Foundation_TypePreservingNSNumberWith${NumberType}(self)
}
public static func _forceBridgeFromObjectiveC(
_ x: NSNumber,
result: inout ${NumberType}?
) {
// If the NSNumber instance preserved its Swift type, we only want to allow
// the cast if the type matches.
if let tag = _SwiftTypePreservingNSNumberTag(rawValue:
_swift_Foundation_TypePreservingNSNumberGetKind(x)) {
precondition(tag == .Swift${NumberType},
"NSNumber does not contain right type to be cast to ${NumberType}")
}
result = x.${accessorName}Value
}
public static func _conditionallyBridgeFromObjectiveC(
_ x: NSNumber,
result: inout ${NumberType}?
) -> Bool {
// If the NSNumber instance preserved its Swift type, we only want to allow
// the cast if the type matches.
if let tag = _SwiftTypePreservingNSNumberTag(rawValue:
_swift_Foundation_TypePreservingNSNumberGetKind(x)),
tag != .Swift${NumberType} {
result = nil
return false
}
result = x.${accessorName}Value
return true
}
public static func _unconditionallyBridgeFromObjectiveC(
_ source: NSNumber?
) -> ${NumberType} {
let unwrappedSource = source!
// If the NSNumber instance preserved its Swift type, we only want to allow
// the cast if the type matches.
if let tag = _SwiftTypePreservingNSNumberTag(rawValue:
_swift_Foundation_TypePreservingNSNumberGetKind(unwrappedSource)) {
precondition(tag == .Swift${NumberType},
"NSNumber does not contain right type to be cast to ${NumberType}")
}
return unwrappedSource.${accessorName}Value
}
}
% end
// Cocoa's implementation of NSNumber already preserves the type of Bool
// values by producing a CFBoolean instance instead of a CFNumber instance
// under the hood. Property list and JSON serialization in Foundation rely
// on -[NSNumber numberWithBool:] producing the correct implementation-
// internal subclass to know when to serialize as a boolean instead of a
// number, so implement Bool's bridging in terms of the standard NSNumber
// interfaces.
extension Bool: _ObjectiveCBridgeable {
public init(_ number: NSNumber) {
self = number.boolValue
}
@_semantics("convertToObjectiveC")
public func _bridgeToObjectiveC() -> NSNumber {
return NSNumber(value: self)
}
public static func _forceBridgeFromObjectiveC(
_ x: NSNumber,
result: inout Bool?
) {
// If the NSNumber instance preserved its Swift type, we only want to allow
// the cast if the type matches.
if let tag = _SwiftTypePreservingNSNumberTag(rawValue:
_swift_Foundation_TypePreservingNSNumberGetKind(x)) {
precondition(tag == .SwiftBool,
"NSNumber does not contain right type to be cast to Bool")
}
result = x.boolValue
}
public static func _conditionallyBridgeFromObjectiveC(
_ x: NSNumber,
result: inout Bool?
) -> Bool {
// If the NSNumber instance preserved its Swift type, we only want to allow
// the cast if the type matches.
if let tag = _SwiftTypePreservingNSNumberTag(rawValue:
_swift_Foundation_TypePreservingNSNumberGetKind(x)),
tag != .SwiftBool {
result = nil
return false
}
result = x.boolValue
return true
}
public static func _unconditionallyBridgeFromObjectiveC(
_ source: NSNumber?
) -> Bool {
let unwrappedSource = source!
// If the NSNumber instance preserved its Swift type, we only want to allow
// the cast if the type matches.
if let tag = _SwiftTypePreservingNSNumberTag(rawValue:
_swift_Foundation_TypePreservingNSNumberGetKind(unwrappedSource)) {
precondition(tag == .SwiftBool,
"NSNumber does not contain right type to be cast to Bool")
}
return unwrappedSource.boolValue
}
}
// CGFloat bridging.
@_silgen_name("_swift_Foundation_TypePreservingNSNumberWithCGFloat")
internal func _swift_Foundation_TypePreservingNSNumberWithCGFloat(
_ value: CGFloat
) -> NSNumber
@_silgen_name("_swift_Foundation_TypePreservingNSNumberGetAsCGFloat")
internal func _swift_Foundation_TypePreservingNSNumberGetAsCGFloat(
_ value: NSNumber
) -> CGFloat
extension CGFloat : _ObjectiveCBridgeable {
public init(_ number: NSNumber) {
self.native = CGFloat.NativeType(number)
}
@_semantics("convertToObjectiveC")
public func _bridgeToObjectiveC() -> NSNumber {
return _swift_Foundation_TypePreservingNSNumberWithCGFloat(self)
}
public static func _forceBridgeFromObjectiveC(
_ x: NSNumber,
result: inout CGFloat?
) {
// If the NSNumber instance preserved its Swift type, we only want to allow
// the cast if the type matches.
if let tag = _SwiftTypePreservingNSNumberTag(rawValue:
_swift_Foundation_TypePreservingNSNumberGetKind(x)) {
precondition(tag == .SwiftCGFloat,
"NSNumber does not contain right type to be cast to CGFloat")
}
result = CGFloat(x)
}
public static func _conditionallyBridgeFromObjectiveC(
_ x: NSNumber,
result: inout CGFloat?
) -> Bool {
// If the NSNumber instance preserved its Swift type, we only want to allow
// the cast if the type matches.
if let tag = _SwiftTypePreservingNSNumberTag(rawValue:
_swift_Foundation_TypePreservingNSNumberGetKind(x)),
tag != .SwiftCGFloat {
result = nil
return false
}
result = CGFloat(x)
return true
}
public static func _unconditionallyBridgeFromObjectiveC(
_ source: NSNumber?
) -> CGFloat {
let unwrappedSource = source!
// If the NSNumber instance preserved its Swift type, we only want to allow
// the cast if the type matches.
if let tag = _SwiftTypePreservingNSNumberTag(rawValue:
_swift_Foundation_TypePreservingNSNumberGetKind(unwrappedSource)) {
precondition(tag == .SwiftCGFloat,
"NSNumber does not contain right type to be cast to CGFloat")
}
return CGFloat(unwrappedSource)
}
}
// Literal support for NSNumber
extension NSNumber
: ExpressibleByFloatLiteral,
ExpressibleByIntegerLiteral,
ExpressibleByBooleanLiteral
{
/// Create an instance initialized to `value`.
@nonobjc
public required convenience init(integerLiteral value: Int) {
self.init(value: value)
}
/// Create an instance initialized to `value`.
@nonobjc
public required convenience init(floatLiteral value: Double) {
self.init(value: value)
}
/// Create an instance initialized to `value`.
@nonobjc
public required convenience init(booleanLiteral value: Bool) {
self.init(value: value)
}
}
extension NSNumber : _HasCustomAnyHashableRepresentation {
// Must be @nonobjc to prevent infinite recursion trying to bridge
// AnyHashable to NSObject.
@nonobjc
public func _toCustomAnyHashable() -> AnyHashable? {
guard let kind = _SwiftTypePreservingNSNumberTag(
rawValue: _swift_Foundation_TypePreservingNSNumberGetKind(self)
) else {
if let nsDecimalNumber: NSDecimalNumber = self as? NSDecimalNumber {
return AnyHashable(nsDecimalNumber as Decimal)
}
return nil
}
switch kind {
% for NumberType, _ in bridgedNumberTypes:
case .Swift${NumberType}:
return AnyHashable(_swift_Foundation_TypePreservingNSNumberGetAs${NumberType}(self))
% end
case .SwiftCGFloat:
return AnyHashable(_swift_Foundation_TypePreservingNSNumberGetAsCGFloat(self))
case .SwiftBool:
return AnyHashable(self.boolValue)
}
}
}