//===----------------------------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// /// Customizes the result of `reflect(x)`, where `x` is a conforming /// type. public protocol Reflectable { // The runtime has inappropriate knowledge of this protocol and how its // witness tables are laid out. Changing this protocol requires a // corresponding change to Reflection.cpp. /// Returns a mirror that reflects `self`. func getMirror() -> MirrorType } /// A unique identifier for a class instance. This can be used by reflection /// clients to recognize cycles in the object graph. /// /// In Swift, only class instances have unique identities. There is no notion /// of identity for structs, enums, or tuples. public struct ObjectIdentifier : Hashable { let value: Builtin.RawPointer /// Convert to a `UInt` that captures the full value of `self`. /// /// Axiom: `a.uintValue() == b.uintValue()` iff `a == b` public func uintValue() -> UInt { return UInt(Builtin.ptrtoint_Word(value)) } // FIXME: Better hashing algorithm /// The hash value. /// /// **Axiom:** `x == y` implies `x.hashValue == y.hashValue` /// /// **Note:** the hash value is not guaranteed to be stable across /// different invocations of the same program. Do not persist the /// hash value across program runs. public var hashValue: Int { return Int(Builtin.ptrtoint_Word(value)) } /// Construct an instance that uniquely identifies `x`. public init(_ x: AnyObject) { self.value = unsafeBitCast(x, Builtin.RawPointer.self) } } public func ==(x: ObjectIdentifier, y: ObjectIdentifier) -> Bool { return Bool(Builtin.cmp_eq_RawPointer(x.value, y.value)) } /// The sum of types that can be used as a quick look representation. /// /// This type must be binary-compatible with the 'QuickLookObject' struct in /// stdlib/Runtime/Reflection.mm, and 'QuickLookObject?' must be binary /// compatible with 'OptionalQuickLookObject' from the same. /// /// NB: This type is somewhat carefully laid out to *suppress* enum layout /// optimization so that it is easier to manufacture in the C++ runtime /// implementation. public enum QuickLookObject { /// Plain text. case Text(String) /// An integer numeric value. case Int(Int64) /// An unsigned integer numeric value. case UInt(UInt64) /// A floating-point numeric value. case Float(Double) /// An image. /// FIXME: Uses an Any to avoid coupling a particular Cocoa type. case Image(Any) /// A sound. /// FIXME: Uses an Any to avoid coupling a particular Cocoa type. case Sound(Any) /// A color. /// FIXME: Uses an Any to avoid coupling a particular Cocoa type. case Color(Any) /// A bezier path. /// FIXME: Uses an Any to avoid coupling a particular Cocoa type. case BezierPath(Any) /// An attributed string. /// FIXME: Uses an Any to avoid coupling a particular Cocoa type. case AttributedString(Any) /// A rectangle /// Uses explicit coordinates to avoid coupling a particular Cocoa type. case Rectangle(Double,Double,Double,Double) /// A point /// Uses explicit coordinates to avoid coupling a particular Cocoa type. case Point(Double,Double) /// A size /// Uses explicit coordinates to avoid coupling a particular Cocoa type. case Size(Double,Double) /// A logical value case Logical(Bool) /// A range /// Uses explicit values to avoid coupling a particular Cocoa type. case Range(UInt64, UInt64) /// A GUI view /// Uses an Any to avoid coupling a particular Cocoa type. case View(Any) /// A graphical sprite /// Uses an Any to avoid coupling a particular Cocoa type. case Sprite(Any) /// A Uniform Resource Locator case URL(String) /// Raw data that has already been encoded in a format the IDE understands. case _Raw([UInt8], String) } /// How children of this value should be presented in the IDE. public enum MirrorDisposition { /// As a struct. case Struct /// As a class. case Class /// As an enum. case Enum /// As a tuple. case Tuple /// As a miscellaneous aggregate with a fixed set of children. case Aggregate /// As a container that is accessed by index. case IndexContainer /// As a container that is accessed by key. case KeyContainer /// As a container that represents membership of its values. case MembershipContainer /// As a miscellaneous container with a variable number of children. case Container /// An Optional which can have either zero or one children. case Optional /// An Objective-C object imported in Swift case ObjCObject } /// The type returned by `reflect(x)`; supplies an API for runtime /// reflection on `x` public protocol MirrorType { /// The instance being reflected var value: Any { get } /// Identical to `value.dynamicType` var valueType: Any.Type { get } /// A unique identifier for `value` if it is a class instance; `nil` /// otherwise. var objectIdentifier: ObjectIdentifier? { get } /// The count of `value`\ 's logical children var count: Int { get } /// Get a name and mirror for the `i`\ th logical child. subscript(i: Int) -> (String, MirrorType) { get } /// A string description of `value`. var summary: String { get } /// A rich representation of `value` for an IDE, or `nil` if none is supplied. var quickLookObject: QuickLookObject? { get } /// How `value` should be presented in an IDE. var disposition: MirrorDisposition { get } } /// An entry point that can be called from C++ code to get the summary string /// for an arbitrary object. The memory pointed to by "out" is initialized with /// the summary string. @asmname("swift_getSummary") public // COMPILER_INTRINSIC func _getSummary(out: UnsafeMutablePointer, x: T) { out.initialize(reflect(x).summary) } /// Produce a mirror for any value. If the value's type conforms to Reflectable, /// invoke its getMirror() method; otherwise, fall back to an implementation /// in the runtime that structurally reflects values of any type. @asmname("swift_reflectAny")public func reflect(x: T) -> MirrorType /// Unsafely produce a mirror for a value in memory whose lifetime is /// guaranteed by holding a strong reference to a heap object. /// This lets containers with heap storage vend mirrors for their elements /// without unnecessary copying of the underlying value. @asmname("swift_unsafeReflectAny")func unsafeReflect( owner: Builtin.NativeObject, ptr: UnsafeMutablePointer ) -> MirrorType /// Dump an object's contents using its mirror to the specified output stream. public func dump( x: T, inout targetStream: TargetStream, name: String? = nil, indent: Int = 0, maxDepth: Int = .max, maxItems: Int = .max ) -> T { var maxItemCounter = maxItems var visitedItems = [ObjectIdentifier : Int]() _dumpWithMirror( reflect(x), name, indent, maxDepth, &maxItemCounter, &visitedItems, &targetStream) return x } /// Dump an object's contents using its mirror to standard output. public func dump(x: T, name: String? = nil, indent: Int = 0, maxDepth: Int = .max, maxItems: Int = .max) -> T { var stdoutStream = _Stdout() return dump( x, &stdoutStream, name: name, indent: indent, maxDepth: maxDepth, maxItems: maxItems) } /// Dump an object's contents using a mirror. User code should use dump(). func _dumpWithMirror( mirror: MirrorType, name: String?, indent: Int, maxDepth: Int, inout maxItemCounter: Int, inout visitedItems: [ObjectIdentifier : Int], inout targetStream: TargetStream ) { if maxItemCounter <= 0 { return } --maxItemCounter for _ in 0.. 0 { print(" more", &targetStream) } if remainder == 1 { println(" child)", &targetStream) } else { println(" children)", &targetStream) } return } let (name, child) = mirror[i] _dumpWithMirror(child, name, indent + 2, maxDepth - 1, &maxItemCounter, &visitedItems, &targetStream) } } // -- MirrorType implementations for basic data types /// A mirror for a value that is represented as a simple value with no /// children. internal struct _LeafMirror: MirrorType { let _value: T let summaryFunction: T -> String let quickLookFunction: T -> QuickLookObject? init(_ value: T, _ summaryFunction: T -> String, _ quickLookFunction: T -> QuickLookObject?) { self._value = value self.summaryFunction = summaryFunction self.quickLookFunction = quickLookFunction } var value: Any { return _value } var valueType: Any.Type { return value.dynamicType } var objectIdentifier: ObjectIdentifier? { return nil } var count: Int { return 0 } subscript(i: Int) -> (String, MirrorType) { _preconditionFailure("no children") } var summary: String { return summaryFunction(_value) } var quickLookObject: QuickLookObject? { return quickLookFunction(_value) } var disposition: MirrorDisposition { return .Aggregate } } // -- Implementation details for the runtime's MirrorType implementation @asmname("swift_MagicMirrorData_summary") func _swift_MagicMirrorData_summaryImpl( metadata: Any.Type, result: UnsafeMutablePointer ) public struct _MagicMirrorData { let owner: Builtin.NativeObject let ptr: Builtin.RawPointer let metadata: Any.Type var value: Any { @asmname("swift_MagicMirrorData_value")get } var valueType: Any.Type { @asmname("swift_MagicMirrorData_valueType")get } public var objcValue: Any { @asmname("swift_MagicMirrorData_objcValue")get } public var objcValueType: Any.Type { @asmname("swift_MagicMirrorData_objcValueType")get } var summary: String { var (_, result) = _withUninitializedString { _swift_MagicMirrorData_summaryImpl(self.metadata, $0) } return result } public func _loadValue() -> T { return Builtin.load(ptr) as T } } struct _OpaqueMirror: MirrorType { let data: _MagicMirrorData var value: Any { return data.value } var valueType: Any.Type { return data.valueType } var objectIdentifier: ObjectIdentifier? { return nil } var count: Int { return 0 } subscript(i: Int) -> (String, MirrorType) { _preconditionFailure("no children") } var summary: String { return data.summary } var quickLookObject: QuickLookObject? { return nil } var disposition: MirrorDisposition { return .Aggregate } } internal struct _TupleMirror: MirrorType { let data: _MagicMirrorData var value: Any { return data.value } var valueType: Any.Type { return data.valueType } var objectIdentifier: ObjectIdentifier? { return nil } var count: Int { @asmname("swift_TupleMirror_count")get } subscript(i: Int) -> (String, MirrorType) { @asmname("swift_TupleMirror_subscript")get } var summary: String { return "(\(count) elements)" } var quickLookObject: QuickLookObject? { return nil } var disposition: MirrorDisposition { return .Tuple } } struct _StructMirror: MirrorType { let data: _MagicMirrorData var value: Any { return data.value } var valueType: Any.Type { return data.valueType } var objectIdentifier: ObjectIdentifier? { return nil } var count: Int { @asmname("swift_StructMirror_count")get } subscript(i: Int) -> (String, MirrorType) { @asmname("swift_StructMirror_subscript")get } var summary: String { return _stdlib_getDemangledTypeName(value) } var quickLookObject: QuickLookObject? { return nil } var disposition: MirrorDisposition { return .Struct } } @asmname("swift_ClassMirror_count") func _getClassCount(_MagicMirrorData) -> Int @asmname("swift_ClassMirror_subscript") func _getClassChild(Int, _MagicMirrorData) -> (String, MirrorType) @asmname("swift_ClassMirror_quickLookObject")public func _getClassQuickLookObject(data: _MagicMirrorData) -> QuickLookObject? struct _ClassMirror: MirrorType { let data: _MagicMirrorData var value: Any { return data.value } var valueType: Any.Type { return data.valueType } var objectIdentifier: ObjectIdentifier? { return data._loadValue() as ObjectIdentifier } var count: Int { return _getClassCount(data) } subscript(i: Int) -> (String, MirrorType) { return _getClassChild(i, data) } var summary: String { return _stdlib_getDemangledTypeName(value) } var quickLookObject: QuickLookObject? { return _getClassQuickLookObject(data) } var disposition: MirrorDisposition { return .Class } } struct _ClassSuperMirror: MirrorType { let data: _MagicMirrorData var value: Any { return data.value } var valueType: Any.Type { return data.valueType } // Suppress the value identifier for super mirrors. var objectIdentifier: ObjectIdentifier? { return nil } var count: Int { return _getClassCount(data) } subscript(i: Int) -> (String, MirrorType) { return _getClassChild(i, data) } var summary: String { return _stdlib_getDemangledTypeName(value) } var quickLookObject: QuickLookObject? { return nil } var disposition: MirrorDisposition { return .Class } }