//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// #if SWIFT_ENABLE_REFLECTION /// Dumps the given object's contents using its mirror to the specified output /// stream. /// /// - Parameters: /// - value: The value to output to the `target` stream. /// - target: The stream to use for writing the contents of `value`. /// - name: A label to use when writing the contents of `value`. When `nil` /// is passed, the label is omitted. The default is `nil`. /// - indent: The number of spaces to use as an indent for each line of the /// output. The default is `0`. /// - maxDepth: The maximum depth to descend when writing the contents of a /// value that has nested components. The default is `Int.max`. /// - maxItems: The maximum number of elements for which to write the full /// contents. The default is `Int.max`. /// - Returns: The instance passed as `value`. @discardableResult @_semantics("optimize.sil.specialize.generic.never") public func dump( _ 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 the given object's contents using its mirror to standard output. /// /// - Parameters: /// - value: The value to output to the `target` stream. /// - name: A label to use when writing the contents of `value`. When `nil` /// is passed, the label is omitted. The default is `nil`. /// - indent: The number of spaces to use as an indent for each line of the /// output. The default is `0`. /// - maxDepth: The maximum depth to descend when writing the contents of a /// value that has nested components. The default is `Int.max`. /// - maxItems: The maximum number of elements for which to write the full /// contents. The default is `Int.max`. /// - Returns: The instance passed as `value`. @discardableResult @_semantics("optimize.sil.specialize.generic.never") public func dump( _ 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(). @_semantics("optimize.sil.specialize.generic.never") internal func _dump_unlocked( _ 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.. 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.. 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: ¤tIndex) _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. @_semantics("optimize.sil.specialize.generic.never") internal func _dumpSuperclass_unlocked( 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.. 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.. 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: ¤tIndex) _dump_unlocked( child, to: &target, name: name, indent: indent + 2, maxDepth: maxDepth - 1, maxItemCounter: &maxItemCounter, visitedItems: &visitedItems) } } #endif // SWIFT_ENABLE_REFLECTION