Skip to content

stdlib: move non-legacy parts of Reflection.swift into separate files #4623

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 4, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion stdlib/public/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ set(SWIFTLIB_ESSENTIAL
CTypes.swift
DebuggerSupport.swift
DropWhile.swift.gyb
Dump.swift
EmptyCollection.swift
Equatable.swift
ErrorType.swift
Expand Down Expand Up @@ -84,6 +85,7 @@ set(SWIFTLIB_ESSENTIAL
MutableCollection.swift
NewtypeWrapper.swift.gyb
ObjCMirrors.swift
ObjectIdentifier.swift
Optional.swift
OptionSet.swift
OutputStream.swift
Expand All @@ -94,7 +96,7 @@ set(SWIFTLIB_ESSENTIAL
RandomAccessCollection.swift
Range.swift.gyb
RangeReplaceableCollection.swift.gyb
Reflection.swift
ReflectionLegacy.swift
Repeat.swift
REPL.swift
Reverse.swift
Expand Down
219 changes: 219 additions & 0 deletions stdlib/public/core/Dump.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 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
//
//===----------------------------------------------------------------------===//

/// Dumps an object's contents using its mirror to the specified output stream.
@discardableResult
public func dump<T, TargetStream : TextOutputStream>(
_ value: T,
to target: inout TargetStream,
name: String? = nil,
indent: Int = 0,
maxDepth: Int = .max,
maxItems: Int = .max
) -> T {
var maxItemCounter = maxItems
var visitedItems = [ObjectIdentifier : Int]()
target._lock()
defer { target._unlock() }
_dump_unlocked(
value,
to: &target,
name: name,
indent: indent,
maxDepth: maxDepth,
maxItemCounter: &maxItemCounter,
visitedItems: &visitedItems)
return value
}

/// Dumps an object's contents using its mirror to standard output.
@discardableResult
public func dump<T>(
_ value: T,
name: String? = nil,
indent: Int = 0,
maxDepth: Int = .max,
maxItems: Int = .max
) -> T {
var stdoutStream = _Stdout()
return dump(
value,
to: &stdoutStream,
name: name,
indent: indent,
maxDepth: maxDepth,
maxItems: maxItems)
}

/// Dump an object's contents. User code should use dump().
internal func _dump_unlocked<TargetStream : TextOutputStream>(
_ value: Any,
to target: inout TargetStream,
name: String?,
indent: Int,
maxDepth: Int,
maxItemCounter: inout Int,
visitedItems: inout [ObjectIdentifier : Int]
) {
guard maxItemCounter > 0 else { return }
maxItemCounter -= 1

for _ in 0..<indent { target.write(" ") }

let mirror = Mirror(reflecting: value)
let count = mirror.children.count
let bullet = count == 0 ? "-"
: maxDepth <= 0 ? "▹" : "▿"
target.write(bullet)
target.write(" ")

if let nam = name {
target.write(nam)
target.write(": ")
}
// This takes the place of the old mirror API's 'summary' property
_dumpPrint_unlocked(value, mirror, &target)

let id: ObjectIdentifier?
if type(of: value) is AnyObject.Type {
// Object is a class (but not an ObjC-bridged struct)
id = ObjectIdentifier(_unsafeDowncastToAnyObject(fromAny: value))
} else if let metatypeInstance = value as? Any.Type {
// Object is a metatype
id = ObjectIdentifier(metatypeInstance)
} else {
id = nil
}
if let theId = id {
if let previous = visitedItems[theId] {
target.write(" #")
_print_unlocked(previous, &target)
target.write("\n")
return
}
let identifier = visitedItems.count
visitedItems[theId] = identifier
target.write(" #")
_print_unlocked(identifier, &target)
}

target.write("\n")

guard maxDepth > 0 else { return }

if let superclassMirror = mirror.superclassMirror {
_dumpSuperclass_unlocked(
mirror: superclassMirror,
to: &target,
indent: indent + 2,
maxDepth: maxDepth - 1,
maxItemCounter: &maxItemCounter,
visitedItems: &visitedItems)
}

var currentIndex = mirror.children.startIndex
for i in 0..<count {
if maxItemCounter <= 0 {
for _ in 0..<(indent+4) {
_print_unlocked(" ", &target)
}
let remainder = count - i
target.write("(")
_print_unlocked(remainder, &target)
if i > 0 { target.write(" more") }
if remainder == 1 {
target.write(" child)\n")
} else {
target.write(" children)\n")
}
return
}

let (name, child) = mirror.children[currentIndex]
mirror.children.formIndex(after: &currentIndex)
_dump_unlocked(
child,
to: &target,
name: name,
indent: indent + 2,
maxDepth: maxDepth - 1,
maxItemCounter: &maxItemCounter,
visitedItems: &visitedItems)
}
}

/// Dump information about an object's superclass, given a mirror reflecting
/// that superclass.
internal func _dumpSuperclass_unlocked<TargetStream : TextOutputStream>(
mirror: Mirror,
to target: inout TargetStream,
indent: Int,
maxDepth: Int,
maxItemCounter: inout Int,
visitedItems: inout [ObjectIdentifier : Int]
) {
guard maxItemCounter > 0 else { return }
maxItemCounter -= 1

for _ in 0..<indent { target.write(" ") }

let count = mirror.children.count
let bullet = count == 0 ? "-"
: maxDepth <= 0 ? "▹" : "▿"
target.write(bullet)
target.write(" super: ")
_debugPrint_unlocked(mirror.subjectType, &target)
target.write("\n")

guard maxDepth > 0 else { return }

if let superclassMirror = mirror.superclassMirror {
_dumpSuperclass_unlocked(
mirror: superclassMirror,
to: &target,
indent: indent + 2,
maxDepth: maxDepth - 1,
maxItemCounter: &maxItemCounter,
visitedItems: &visitedItems)
}

var currentIndex = mirror.children.startIndex
for i in 0..<count {
if maxItemCounter <= 0 {
for _ in 0..<(indent+4) {
target.write(" ")
}
let remainder = count - i
target.write("(")
_print_unlocked(remainder, &target)
if i > 0 { target.write(" more") }
if remainder == 1 {
target.write(" child)\n")
} else {
target.write(" children)\n")
}
return
}

let (name, child) = mirror.children[currentIndex]
mirror.children.formIndex(after: &currentIndex)
_dump_unlocked(
child,
to: &target,
name: name,
indent: indent + 2,
maxDepth: maxDepth - 1,
maxItemCounter: &maxItemCounter,
visitedItems: &visitedItems)
}
}

8 changes: 5 additions & 3 deletions stdlib/public/core/GroupInfo.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,12 @@
"MemoryLayout.swift"
],
"Reflection": [
"Mirrors.swift",
"Dump.swift",
"Mirror.swift",
"Reflection.swift",
"ObjCMirrors.swift"
"Mirrors.swift",
"ObjCMirrors.swift",
"ObjectIdentifier.swift",
"ReflectionLegacy.swift"
],
"Math": [
"SetAlgebra.swift",
Expand Down
125 changes: 125 additions & 0 deletions stdlib/public/core/ObjectIdentifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 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
//
//===----------------------------------------------------------------------===//

/// A unique identifier for a class instance or metatype.
///
/// In Swift, only class instances and metatypes have unique identities. There
/// is no notion of identity for structs, enums, functions, or tuples.
public struct ObjectIdentifier : Hashable {
internal let _value: Builtin.RawPointer

// FIXME: Better hashing algorithm
/// The identifier's hash value.
///
/// 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.
///
/// - SeeAlso: `Hashable`
public var hashValue: Int {
return Int(Builtin.ptrtoint_Word(_value))
}

/// Creates an instance that uniquely identifies the given class instance.
///
/// The following example creates an example class `A` and compares instances
/// of the class using their object identifiers and the identical-to
/// operator (`===`):
///
/// class IntegerRef {
/// let value: Int
/// init(_ value: Int) {
/// self.value = value
/// }
/// }
///
/// let x = IntegerRef(10)
/// let y = x
///
/// print(ObjectIdentifier(x) == ObjectIdentifier(y))
/// // Prints "true"
/// print(x === y)
/// // Prints "true"
///
/// let z = IntegerRef(10)
/// print(ObjectIdentifier(x) == ObjectIdentifier(z))
/// // Prints "false"
/// print(x === z)
/// // Prints "false"
///
/// - Parameter x: An instance of a class.
public init(_ x: AnyObject) {
self._value = Builtin.bridgeToRawPointer(x)
}

/// Creates an instance that uniquely identifies the given metatype.
///
/// - Parameter: A metatype.
public init(_ x: Any.Type) {
self._value = unsafeBitCast(x, to: Builtin.RawPointer.self)
}
}

extension ObjectIdentifier : CustomDebugStringConvertible {
/// A textual representation of the identifier, suitable for debugging.
public var debugDescription: String {
return "ObjectIdentifier(\(_rawPointerToString(_value)))"
}
}

extension ObjectIdentifier : Comparable {
public static func < (lhs: ObjectIdentifier, rhs: ObjectIdentifier) -> Bool {
return UInt(bitPattern: lhs) < UInt(bitPattern: rhs)
}

public static func == (x: ObjectIdentifier, y: ObjectIdentifier) -> Bool {
return Bool(Builtin.cmp_eq_RawPointer(x._value, y._value))
}
}

extension UInt {
/// Creates an integer that captures the full value of the given object
/// identifier.
public init(bitPattern objectID: ObjectIdentifier) {
self.init(Builtin.ptrtoint_Word(objectID._value))
}
}

extension Int {
/// Creates an integer that captures the full value of the given object
/// identifier.
public init(bitPattern objectID: ObjectIdentifier) {
self.init(bitPattern: UInt(bitPattern: objectID))
}
}

extension ObjectIdentifier {
@available(*, unavailable, message: "use the 'UInt(_:)' initializer")
public var uintValue: UInt {
Builtin.unreachable()
}
}

extension UInt {
@available(*, unavailable, renamed: "init(bitPattern:)")
public init(_ objectID: ObjectIdentifier) {
Builtin.unreachable()
}
}

extension Int {
@available(*, unavailable, renamed: "init(bitPattern:)")
public init(_ objectID: ObjectIdentifier) {
Builtin.unreachable()
}
}

Loading