mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
324 lines
10 KiB
Plaintext
324 lines
10 KiB
Plaintext
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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`.
|
|
public required convenience init(integerLiteral value: Int) {
|
|
self.init(value: value)
|
|
}
|
|
|
|
/// Create an instance initialized to `value`.
|
|
public required convenience init(floatLiteral value: Double) {
|
|
self.init(value: value)
|
|
}
|
|
|
|
/// Create an instance initialized to `value`.
|
|
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)
|
|
}
|
|
}
|
|
}
|