|
10 | 10 | // |
11 | 11 | //===----------------------------------------------------------------------===// |
12 | 12 |
|
13 | | -#if _runtime(_ObjC) |
14 | 13 | /// A Swift Array or Dictionary of types conforming to |
15 | 14 | /// `_ObjectiveCBridgeable` can be passed to Objective-C as an NSArray or |
16 | 15 | /// NSDictionary, respectively. The elements of the resulting NSArray |
@@ -83,6 +82,8 @@ public protocol _ObjectiveCBridgeable { |
83 | 82 | -> Self |
84 | 83 | } |
85 | 84 |
|
| 85 | +#if _runtime(_ObjC) |
| 86 | + |
86 | 87 | //===--- Bridging for metatypes -------------------------------------------===// |
87 | 88 |
|
88 | 89 | /// A stand-in for a value of metatype type. |
@@ -640,3 +641,200 @@ public func _getObjCTypeEncoding<T>(_ type: T.Type) -> UnsafePointer<Int8> { |
640 | 641 | } |
641 | 642 |
|
642 | 643 | #endif |
| 644 | + |
| 645 | +//===--- Bridging without the ObjC runtime --------------------------------===// |
| 646 | + |
| 647 | +#if !_runtime(_ObjC) |
| 648 | + |
| 649 | +/// Convert `x` from its Objective-C representation to its Swift |
| 650 | +/// representation. |
| 651 | +/// COMPILER_INTRINSIC |
| 652 | +@_inlineable // FIXME(sil-serialize-all) |
| 653 | +public func _forceBridgeFromObjectiveC_bridgeable<T:_ObjectiveCBridgeable> ( |
| 654 | + _ x: T._ObjectiveCType, |
| 655 | + _: T.Type |
| 656 | +) -> T { |
| 657 | + var result: T? |
| 658 | + T._forceBridgeFromObjectiveC(x, result: &result) |
| 659 | + return result! |
| 660 | +} |
| 661 | + |
| 662 | +/// Attempt to convert `x` from its Objective-C representation to its Swift |
| 663 | +/// representation. |
| 664 | +/// COMPILER_INTRINSIC |
| 665 | +@_inlineable // FIXME(sil-serialize-all) |
| 666 | +public func _conditionallyBridgeFromObjectiveC_bridgeable<T:_ObjectiveCBridgeable>( |
| 667 | + _ x: T._ObjectiveCType, |
| 668 | + _: T.Type |
| 669 | +) -> T? { |
| 670 | + var result: T? |
| 671 | + T._conditionallyBridgeFromObjectiveC (x, result: &result) |
| 672 | + return result |
| 673 | +} |
| 674 | + |
| 675 | +public // SPI(Foundation) |
| 676 | +protocol _NSSwiftValue: class { |
| 677 | + init(_ value: Any) |
| 678 | + var value: Any { get } |
| 679 | + static var null: AnyObject { get } |
| 680 | +} |
| 681 | + |
| 682 | +@usableFromInline |
| 683 | +internal class _SwiftValue { |
| 684 | + @usableFromInline |
| 685 | + let value: Any |
| 686 | + |
| 687 | + @usableFromInline |
| 688 | + init(_ value: Any) { |
| 689 | + self.value = value |
| 690 | + } |
| 691 | + |
| 692 | + @usableFromInline |
| 693 | + static let null = _SwiftValue(Optional<Any>.none as Any) |
| 694 | +} |
| 695 | + |
| 696 | +/// COMPILER_INTRISIC |
| 697 | +@_silgen_name("swift_unboxFromSwiftValueWithType") |
| 698 | +public func swift_unboxFromSwiftValueWithType<T>( |
| 699 | + _ source: inout AnyObject, |
| 700 | + _ result: UnsafeMutablePointer<T> |
| 701 | + ) -> Bool { |
| 702 | + |
| 703 | + if source === _nullPlaceholder { |
| 704 | + if let unpacked = Optional<Any>.none as? T { |
| 705 | + result.initialize(to: unpacked) |
| 706 | + return true |
| 707 | + } |
| 708 | + } |
| 709 | + |
| 710 | + if let box = source as? _SwiftValue { |
| 711 | + if let value = box.value as? T { |
| 712 | + result.initialize(to: value) |
| 713 | + return true |
| 714 | + } |
| 715 | + } else if let box = source as? _NSSwiftValue { |
| 716 | + if let value = box.value as? T { |
| 717 | + result.initialize(to: value) |
| 718 | + return true |
| 719 | + } |
| 720 | + } |
| 721 | + |
| 722 | + return false |
| 723 | +} |
| 724 | + |
| 725 | +@_silgen_name("_swift_extractDynamicValue") |
| 726 | +public func _extractDynamicValue<T>(_ value: T) -> AnyObject? |
| 727 | + |
| 728 | +@_silgen_name("_swift_bridgeToObjectiveCUsingProtocolIfPossible") |
| 729 | +public func _bridgeToObjectiveCUsingProtocolIfPossible<T>(_ value: T) -> AnyObject? |
| 730 | + |
| 731 | +@usableFromInline |
| 732 | +protocol _Unwrappable { |
| 733 | + func unwrap() -> Any? |
| 734 | +} |
| 735 | + |
| 736 | +extension Optional: _Unwrappable { |
| 737 | + func unwrap() -> Any? { |
| 738 | + return self |
| 739 | + } |
| 740 | +} |
| 741 | + |
| 742 | +// This is a best-effort tripmine for detecting the situation |
| 743 | +// (which should never happen) of Swift._SwiftValue and |
| 744 | +// Foundation._SwiftValue/Foundation.NSNull being used |
| 745 | +// in the same process. |
| 746 | + |
| 747 | +@usableFromInline |
| 748 | +internal enum _SwiftValueFlavor: Equatable { |
| 749 | + case stdlib |
| 750 | + case foundation |
| 751 | +} |
| 752 | + |
| 753 | +@usableFromInline |
| 754 | +func _currentSwiftValueFlavor() -> _SwiftValueFlavor { |
| 755 | + if _typeByName("Foundation._SwiftValue") as? _NSSwiftValue.Type != nil { |
| 756 | + return .foundation |
| 757 | + } else { |
| 758 | + return .stdlib |
| 759 | + } |
| 760 | +} |
| 761 | + |
| 762 | +@usableFromInline |
| 763 | +internal var _selectedSwiftValueFlavor: _SwiftValueFlavor = _currentSwiftValueFlavor() |
| 764 | + |
| 765 | +@usableFromInline |
| 766 | +internal func _assertSwiftValueFlavorIsConsistent() { |
| 767 | + assert(_selectedSwiftValueFlavor == _currentSwiftValueFlavor()) |
| 768 | +} |
| 769 | + |
| 770 | +@usableFromInline |
| 771 | +internal var _nullPlaceholder: AnyObject { |
| 772 | + _assertSwiftValueFlavorIsConsistent() |
| 773 | + if let foundationType = _typeByName("Foundation._SwiftValue") as? _NSSwiftValue.Type { |
| 774 | + return foundationType.null |
| 775 | + } else { |
| 776 | + return _SwiftValue.null |
| 777 | + } |
| 778 | +} |
| 779 | + |
| 780 | +@usableFromInline |
| 781 | +func _makeSwiftValue(_ value: Any) -> AnyObject { |
| 782 | + _assertSwiftValueFlavorIsConsistent() |
| 783 | + if let foundationType = _typeByName("Foundation._SwiftValue") as? _NSSwiftValue.Type { |
| 784 | + return foundationType.init(value) |
| 785 | + } else { |
| 786 | + return _SwiftValue(value) |
| 787 | + } |
| 788 | +} |
| 789 | + |
| 790 | +/// Bridge an arbitrary value to an Objective-C object. |
| 791 | +/// |
| 792 | +/// - If `T` is a class type, it is always bridged verbatim, the function |
| 793 | +/// returns `x`; |
| 794 | +/// |
| 795 | +/// - otherwise, if `T` conforms to `_ObjectiveCBridgeable`, |
| 796 | +/// returns the result of `x._bridgeToObjectiveC()`; |
| 797 | +/// |
| 798 | +/// - otherwise, we use **boxing** to bring the value into Objective-C. |
| 799 | +/// The value is wrapped in an instance of a private Objective-C class |
| 800 | +/// that is `id`-compatible and dynamically castable back to the type of |
| 801 | +/// the boxed value, but is otherwise opaque. |
| 802 | +/// |
| 803 | +/// COMPILER_INTRINSIC |
| 804 | +@inlinable // FIXME(sil-serialize-all) |
| 805 | +public func _bridgeAnythingToObjectiveC<T>(_ x: T) -> AnyObject { |
| 806 | + var done = false |
| 807 | + var result: AnyObject! |
| 808 | + |
| 809 | + var source: Any = x |
| 810 | + |
| 811 | + if let dynamicSource = _extractDynamicValue(x) { |
| 812 | + result = dynamicSource as AnyObject |
| 813 | + done = true |
| 814 | + } |
| 815 | + |
| 816 | + if !done, let wrapper = source as? _Unwrappable { |
| 817 | + if let value = wrapper.unwrap() { |
| 818 | + result = value as AnyObject |
| 819 | + } else { |
| 820 | + result = _nullPlaceholder |
| 821 | + } |
| 822 | + |
| 823 | + done = true |
| 824 | + } |
| 825 | + |
| 826 | + if !done { |
| 827 | + if type(of: source) as? AnyClass != nil { |
| 828 | + result = unsafeBitCast(x, to: AnyObject.self) |
| 829 | + } else if let object = _bridgeToObjectiveCUsingProtocolIfPossible(source) { |
| 830 | + result = object |
| 831 | + } else { |
| 832 | + result = _makeSwiftValue(source) |
| 833 | + } |
| 834 | + } |
| 835 | + |
| 836 | + return result |
| 837 | +} |
| 838 | + |
| 839 | +#endif // !_runtime(_ObjC) |
| 840 | + |
0 commit comments