| //===----------------------------------------------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2020 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| import SwiftShims |
| |
| @_silgen_name("swift_isClassType") |
| internal func _isClassType(_: Any.Type) -> Bool |
| |
| @_silgen_name("swift_getMetadataKind") |
| internal func _metadataKind(_: Any.Type) -> UInt |
| |
| @_silgen_name("swift_reflectionMirror_normalizedType") |
| internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type |
| |
| @_silgen_name("swift_reflectionMirror_count") |
| internal func _getChildCount<T>(_: T, type: Any.Type) -> Int |
| |
| @_silgen_name("swift_reflectionMirror_recursiveCount") |
| internal func _getRecursiveChildCount(_: Any.Type) -> Int |
| |
| @_silgen_name("swift_reflectionMirror_recursiveChildMetadata") |
| internal func _getChildMetadata( |
| _: Any.Type, |
| index: Int, |
| fieldMetadata: UnsafeMutablePointer<_FieldReflectionMetadata> |
| ) -> Any.Type |
| |
| @_silgen_name("swift_reflectionMirror_recursiveChildOffset") |
| internal func _getChildOffset( |
| _: Any.Type, |
| index: Int |
| ) -> Int |
| |
| internal typealias NameFreeFunc = @convention(c) (UnsafePointer<CChar>?) -> Void |
| |
| @_silgen_name("swift_reflectionMirror_subscript") |
| internal func _getChild<T>( |
| of: T, |
| type: Any.Type, |
| index: Int, |
| outName: UnsafeMutablePointer<UnsafePointer<CChar>?>, |
| outFreeFunc: UnsafeMutablePointer<NameFreeFunc?> |
| ) -> Any |
| |
| // Returns 'c' (class), 'e' (enum), 's' (struct), 't' (tuple), or '\0' (none) |
| @_silgen_name("swift_reflectionMirror_displayStyle") |
| internal func _getDisplayStyle<T>(_: T) -> CChar |
| |
| internal func getChild<T>(of value: T, type: Any.Type, index: Int) -> (label: String?, value: Any) { |
| var nameC: UnsafePointer<CChar>? = nil |
| var freeFunc: NameFreeFunc? = nil |
| |
| let value = _getChild(of: value, type: type, index: index, outName: &nameC, outFreeFunc: &freeFunc) |
| |
| let name = nameC.flatMap({ String(validatingUTF8: $0) }) |
| freeFunc?(nameC) |
| return (name, value) |
| } |
| |
| #if _runtime(_ObjC) |
| @_silgen_name("swift_reflectionMirror_quickLookObject") |
| internal func _getQuickLookObject<T>(_: T) -> AnyObject? |
| |
| @_silgen_name("_swift_stdlib_NSObject_isKindOfClass") |
| internal func _isImpl(_ object: AnyObject, kindOf: UnsafePointer<CChar>) -> Bool |
| |
| internal func _is(_ object: AnyObject, kindOf `class`: String) -> Bool { |
| return `class`.withCString { |
| return _isImpl(object, kindOf: $0) |
| } |
| } |
| |
| internal func _getClassPlaygroundQuickLook( |
| _ object: AnyObject |
| ) -> _PlaygroundQuickLook? { |
| if _is(object, kindOf: "NSNumber") { |
| let number: _NSNumber = unsafeBitCast(object, to: _NSNumber.self) |
| switch UInt8(number.objCType[0]) { |
| case UInt8(ascii: "d"): |
| return .double(number.doubleValue) |
| case UInt8(ascii: "f"): |
| return .float(number.floatValue) |
| case UInt8(ascii: "Q"): |
| return .uInt(number.unsignedLongLongValue) |
| default: |
| return .int(number.longLongValue) |
| } |
| } |
| |
| if _is(object, kindOf: "NSAttributedString") { |
| return .attributedString(object) |
| } |
| |
| if _is(object, kindOf: "NSImage") || |
| _is(object, kindOf: "UIImage") || |
| _is(object, kindOf: "NSImageView") || |
| _is(object, kindOf: "UIImageView") || |
| _is(object, kindOf: "CIImage") || |
| _is(object, kindOf: "NSBitmapImageRep") { |
| return .image(object) |
| } |
| |
| if _is(object, kindOf: "NSColor") || |
| _is(object, kindOf: "UIColor") { |
| return .color(object) |
| } |
| |
| if _is(object, kindOf: "NSBezierPath") || |
| _is(object, kindOf: "UIBezierPath") { |
| return .bezierPath(object) |
| } |
| |
| if _is(object, kindOf: "NSString") { |
| return .text(_forceBridgeFromObjectiveC(object, String.self)) |
| } |
| |
| return .none |
| } |
| #endif |
| |
| extension Mirror { |
| internal struct ReflectedChildren: RandomAccessCollection { |
| let subject: Any |
| let subjectType: Any.Type |
| var startIndex: Int { 0 } |
| var endIndex: Int { _getChildCount(subject, type: subjectType) } |
| subscript(index: Int) -> Child { |
| getChild(of: subject, type: subjectType, index: index) |
| } |
| } |
| |
| internal init( |
| internalReflecting subject: Any, |
| subjectType: Any.Type? = nil, |
| customAncestor: Mirror? = nil |
| ) { |
| let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject)) |
| |
| self._children = _Children( |
| ReflectedChildren(subject: subject, subjectType: subjectType)) |
| |
| self._makeSuperclassMirror = { |
| guard let subjectClass = subjectType as? AnyClass, |
| let superclass = _getSuperclass(subjectClass) else { |
| return nil |
| } |
| |
| // Handle custom ancestors. If we've hit the custom ancestor's subject type, |
| // or descendants are suppressed, return it. Otherwise continue reflecting. |
| if let customAncestor = customAncestor { |
| if superclass == customAncestor.subjectType { |
| return customAncestor |
| } |
| if customAncestor._defaultDescendantRepresentation == .suppressed { |
| return customAncestor |
| } |
| } |
| return Mirror(internalReflecting: subject, |
| subjectType: superclass, |
| customAncestor: customAncestor) |
| } |
| |
| let rawDisplayStyle = _getDisplayStyle(subject) |
| switch UnicodeScalar(Int(rawDisplayStyle)) { |
| case "c": self.displayStyle = .class |
| case "e": self.displayStyle = .enum |
| case "s": self.displayStyle = .struct |
| case "t": self.displayStyle = .tuple |
| case "\0": self.displayStyle = nil |
| default: preconditionFailure("Unknown raw display style '\(rawDisplayStyle)'") |
| } |
| |
| self.subjectType = subjectType |
| self._defaultDescendantRepresentation = .generated |
| } |
| |
| internal static func quickLookObject(_ subject: Any) -> _PlaygroundQuickLook? { |
| #if _runtime(_ObjC) |
| let object = _getQuickLookObject(subject) |
| return object.flatMap(_getClassPlaygroundQuickLook) |
| #else |
| return nil |
| #endif |
| } |
| } |
| |
| /// Options for calling `_forEachField(of:options:body:)`. |
| @available(macOS 10.15.4, iOS 13.4, tvOS 13.4, watchOS 6.2, *) |
| @_spi(Reflection) |
| public struct _EachFieldOptions: OptionSet { |
| public var rawValue: UInt32 |
| |
| public init(rawValue: UInt32) { |
| self.rawValue = rawValue |
| } |
| |
| /// Require the top-level type to be a class. |
| /// |
| /// If this is not set, the top-level type is required to be a struct or |
| /// tuple. |
| public static var classType = _EachFieldOptions(rawValue: 1 << 0) |
| |
| /// Ignore fields that can't be introspected. |
| /// |
| /// If not set, the presence of things that can't be introspected causes |
| /// the function to immediately return `false`. |
| public static var ignoreUnknown = _EachFieldOptions(rawValue: 1 << 1) |
| } |
| |
| /// The metadata "kind" for a type. |
| @available(macOS 10.15.4, iOS 13.4, tvOS 13.4, watchOS 6.2, *) |
| @_spi(Reflection) |
| public enum _MetadataKind: UInt { |
| // With "flags": |
| // runtimePrivate = 0x100 |
| // nonHeap = 0x200 |
| // nonType = 0x400 |
| |
| case `class` = 0 |
| case `struct` = 0x200 // 0 | nonHeap |
| case `enum` = 0x201 // 1 | nonHeap |
| case optional = 0x202 // 2 | nonHeap |
| case foreignClass = 0x203 // 3 | nonHeap |
| case opaque = 0x300 // 0 | runtimePrivate | nonHeap |
| case tuple = 0x301 // 1 | runtimePrivate | nonHeap |
| case function = 0x302 // 2 | runtimePrivate | nonHeap |
| case existential = 0x303 // 3 | runtimePrivate | nonHeap |
| case metatype = 0x304 // 4 | runtimePrivate | nonHeap |
| case objcClassWrapper = 0x305 // 5 | runtimePrivate | nonHeap |
| case existentialMetatype = 0x306 // 6 | runtimePrivate | nonHeap |
| case heapLocalVariable = 0x400 // 0 | nonType |
| case heapGenericLocalVariable = 0x500 // 0 | nonType | runtimePrivate |
| case errorObject = 0x501 // 1 | nonType | runtimePrivate |
| case unknown = 0xffff |
| |
| init(_ type: Any.Type) { |
| let v = _metadataKind(type) |
| if let result = _MetadataKind(rawValue: v) { |
| self = result |
| } else { |
| self = .unknown |
| } |
| } |
| } |
| |
| /// Calls the given closure on every field of the specified type. |
| /// |
| /// If `body` returns `false` for any field, no additional fields are visited. |
| /// |
| /// - Parameters: |
| /// - type: The type to inspect. |
| /// - options: Options to use when reflecting over `type`. |
| /// - body: A closure to call with information about each field in `type`. |
| /// The parameters to `body` are a pointer to a C string holding the name |
| /// of the field, the offset of the field in bytes, the type of the field, |
| /// and the `_MetadataKind` of the field's type. |
| /// - Returns: `true` if every invocation of `body` returns `true`; otherwise, |
| /// `false`. |
| @available(macOS 10.15.4, iOS 13.4, tvOS 13.4, watchOS 6.2, *) |
| @discardableResult |
| @_spi(Reflection) |
| public func _forEachField( |
| of type: Any.Type, |
| options: _EachFieldOptions = [], |
| body: (UnsafePointer<CChar>, Int, Any.Type, _MetadataKind) -> Bool |
| ) -> Bool { |
| // Require class type iff `.classType` is included as an option |
| if _isClassType(type) != options.contains(.classType) { |
| return false |
| } |
| |
| let childCount = _getRecursiveChildCount(type) |
| for i in 0..<childCount { |
| let offset = _getChildOffset(type, index: i) |
| |
| var field = _FieldReflectionMetadata() |
| let childType = _getChildMetadata(type, index: i, fieldMetadata: &field) |
| defer { field.freeFunc?(field.name) } |
| let kind = _MetadataKind(childType) |
| |
| if !body(field.name!, offset, childType, kind) { |
| return false |
| } |
| } |
| |
| return true |
| } |
| |
| /// Calls the given closure on every field of the specified type. |
| /// |
| /// If `body` returns `false` for any field, no additional fields are visited. |
| /// |
| /// - Parameters: |
| /// - type: The type to inspect. |
| /// - options: Options to use when reflecting over `type`. |
| /// - body: A closure to call with information about each field in `type`. |
| /// The parameters to `body` are a pointer to a C string holding the name |
| /// of the field, the offset of the field in bytes, the type of the field, |
| /// and the `_MetadataKind` of the field's type. |
| /// - Returns: `true` if every invocation of `body` returns `true`; otherwise, |
| /// `false`. |
| @available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) |
| @discardableResult |
| @_spi(Reflection) |
| public func _forEachFieldWithKeyPath<Root>( |
| of type: Root.Type, |
| options: _EachFieldOptions = [], |
| body: (UnsafePointer<CChar>, PartialKeyPath<Root>) -> Bool |
| ) -> Bool { |
| // Class types not supported because the metadata does not have |
| // enough information to construct computed properties. |
| if _isClassType(type) || options.contains(.classType) { |
| return false |
| } |
| let ignoreUnknown = options.contains(.ignoreUnknown) |
| |
| let childCount = _getRecursiveChildCount(type) |
| for i in 0..<childCount { |
| let offset = _getChildOffset(type, index: i) |
| |
| var field = _FieldReflectionMetadata() |
| let childType = _getChildMetadata(type, index: i, fieldMetadata: &field) |
| defer { field.freeFunc?(field.name) } |
| let kind = _MetadataKind(childType) |
| let supportedType: Bool |
| switch kind { |
| case .struct, .class, .optional, .existential, |
| .existentialMetatype, .tuple, .enum: |
| supportedType = true |
| default: |
| supportedType = false |
| } |
| if !supportedType || !field.isStrong { |
| if !ignoreUnknown { return false } |
| continue; |
| } |
| func keyPathType<Leaf>(for: Leaf.Type) -> PartialKeyPath<Root>.Type { |
| if field.isVar { return WritableKeyPath<Root, Leaf>.self } |
| return KeyPath<Root, Leaf>.self |
| } |
| let resultSize = MemoryLayout<Int32>.size + MemoryLayout<Int>.size |
| let partialKeyPath = _openExistential(childType, do: keyPathType) |
| ._create(capacityInBytes: resultSize) { |
| var destBuilder = KeyPathBuffer.Builder($0) |
| destBuilder.pushHeader(KeyPathBuffer.Header( |
| size: resultSize - MemoryLayout<Int>.size, |
| trivial: true, |
| hasReferencePrefix: false |
| )) |
| let component = RawKeyPathComponent( |
| header: RawKeyPathComponent.Header(stored: .struct, |
| mutable: field.isVar, |
| inlineOffset: UInt32(offset)), |
| body: UnsafeRawBufferPointer(start: nil, count: 0)) |
| component.clone( |
| into: &destBuilder.buffer, |
| endOfReferencePrefix: false) |
| } |
| |
| if !body(field.name!, partialKeyPath) { |
| return false |
| } |
| } |
| |
| return true |
| } |