diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index 942f14939c439..496c5602395a4 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -60,6 +60,7 @@ set(SWIFTLIB_ESSENTIAL DictionaryVariant.swift DropWhile.swift Dump.swift + EitherSequence.swift EmptyCollection.swift Equatable.swift ErrorType.swift diff --git a/stdlib/public/core/DebuggerSupport.swift b/stdlib/public/core/DebuggerSupport.swift index 9890a82bda4ca..0e7095aebd783 100644 --- a/stdlib/public/core/DebuggerSupport.swift +++ b/stdlib/public/core/DebuggerSupport.swift @@ -110,7 +110,7 @@ public enum _DebuggerSupport { private static func ivarCount(mirror: Mirror) -> Int { let ivars = mirror.superclassMirror.map(ivarCount) ?? 0 - return ivars + mirror.children.count + return ivars + mirror._children.count } private static func shouldExpand( @@ -119,7 +119,7 @@ public enum _DebuggerSupport { isRoot: Bool ) -> Bool { if isRoot || collectionStatus.isCollection { return true } - if !mirror.children.isEmpty { return true } + if !mirror._children.isEmpty { return true } if mirror.displayStyle == .`class` { return true } if let sc = mirror.superclassMirror { return ivarCount(mirror: sc) > 0 } return true @@ -154,7 +154,7 @@ public enum _DebuggerSupport { // anyway, so there's that... let willExpand = mirror.displayStyle != .`class` || value is CustomReflectable? - let count = mirror.children.count + let count = mirror._children.count let bullet = isRoot && (count == 0 || !willExpand) ? "" : count == 0 ? "- " : maxDepth <= 0 ? "▹ " : "▿ " @@ -202,7 +202,7 @@ public enum _DebuggerSupport { target: &target) } - for (optionalName,child) in mirror.children { + for (optionalName,child) in mirror._children { let childName = optionalName ?? "\(printedElements)" if maxItemCounter <= 0 { print(String(repeating: " ", count: indent+4), terminator: "", to: &target) diff --git a/stdlib/public/core/Dump.swift b/stdlib/public/core/Dump.swift index 24651aad32936..917ac696cf555 100644 --- a/stdlib/public/core/Dump.swift +++ b/stdlib/public/core/Dump.swift @@ -99,7 +99,7 @@ internal func _dump_unlocked( for _ in 0..( visitedItems: &visitedItems) } - var currentIndex = mirror.children.startIndex + var currentIndex = mirror._children.startIndex for i in 0..( return } - let (name, child) = mirror.children[currentIndex] - mirror.children.formIndex(after: ¤tIndex) + let (name, child) = mirror._children[currentIndex] + mirror._children.formIndex(after: ¤tIndex) _dump_unlocked( child, to: &target, @@ -196,7 +196,7 @@ internal func _dumpSuperclass_unlocked( for _ in 0..( visitedItems: &visitedItems) } - var currentIndex = mirror.children.startIndex + var currentIndex = mirror._children.startIndex for i in 0..( return } - let (name, child) = mirror.children[currentIndex] - mirror.children.formIndex(after: ¤tIndex) + let (name, child) = mirror._children[currentIndex] + mirror._children.formIndex(after: ¤tIndex) _dump_unlocked( child, to: &target, diff --git a/stdlib/public/core/EitherSequence.swift b/stdlib/public/core/EitherSequence.swift new file mode 100644 index 0000000000000..36dc7b2744564 --- /dev/null +++ b/stdlib/public/core/EitherSequence.swift @@ -0,0 +1,197 @@ +////===--- _EitherSequence.swift - A sequence type-erasing two sequences -----===// +//// +//// 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 +//// +////===----------------------------------------------------------------------===// + +// Not public stdlib API, currently used in Mirror.children implementation. + +internal enum _Either { + case left(Left), right(Right) +} + +extension _Either { + internal init(_ left: Left, or other: Right.Type) { self = .left(left) } + internal init(_ left: Left) { self = .left(left) } + internal init(_ right: Right) { self = .right(right) } +} + +extension _Either: Equatable where Left: Equatable, Right: Equatable { + internal static func == (lhs: Self, rhs: Self) -> Bool { + switch (lhs, rhs) { + case let (.left(l), .left(r)): return l == r + case let (.right(l), .right(r)): return l == r + case (.left, .right), (.right, .left): return false + } + } +} + +extension _Either: Comparable where Left: Comparable, Right: Comparable { + internal static func < (lhs: Self, rhs: Self) -> Bool { + switch (lhs, rhs) { + case let (.left(l), .left(r)): return l < r + case let (.right(l), .right(r)): return l < r + case (.left, .right): return true + case (.right, .left): return false + } + } +} + +/// A sequence that type erases two sequences. A lighter-weight alternative to +/// AnySequence when more can be statically known, and which is more easily +/// specialized. +/// +/// If you only know about one of the types, the second one can be +/// AnySequence, giving you a fast path for the known one. +/// +/// If you have 3+ types to erase, you can nest them. +typealias _EitherSequence = + _Either where L.Element == R.Element + +extension _EitherSequence { + internal struct Iterator { + var left: Left.Iterator? + var right: Right.Iterator? + } +} + +extension _Either.Iterator: IteratorProtocol { + internal typealias Element = Left.Element + + internal mutating func next() -> Element? { + left?.next() ?? right?.next() + } +} + +extension _EitherSequence: Sequence { + internal typealias Element = Left.Element + + internal func makeIterator() -> Iterator { + switch self { + case let .left(l): + return Iterator(left: l.makeIterator(), right: nil) + case let .right(r): + return Iterator(left: nil, right: r.makeIterator()) + } + } +} + +internal typealias _EitherCollection< + T: Collection, U: Collection +> = _EitherSequence where T.Element == U.Element + +extension _EitherCollection: Collection { + internal typealias Index = _Either + + internal var startIndex: Index { + switch self { + case let .left(s): return .left(s.startIndex) + case let .right(s): return .right(s.startIndex) + } + } + + internal var endIndex: Index { + switch self { + case let .left(s): return .left(s.endIndex) + case let .right(s): return .right(s.endIndex) + } + } + + internal subscript(position: Index) -> Element { + switch (self,position) { + case let (.left(s),.left(i)): return s[i] + case let (.right(s),.right(i)): return s[i] + default: fatalError("_EitherCollecton: Sequence used with other index type") + } + } + + internal func index(after i: Index) -> Index { + switch (self,i) { + case let (.left(s),.left(i)): return .left(s.index(after: i)) + case let (.right(s),.right(i)): return .right(s.index(after: i)) + default: fatalError("_EitherCollecton: wrong type of index used") + } + } + + internal func index( + _ i: Index, + offsetBy distance: Int, + limitedBy limit: Index + ) -> Index? { + switch (self,i,limit) { + case let (.left(s),.left(i),.left(limit)): + return s.index(i, offsetBy: distance, limitedBy: limit).map { .left($0) } + case let (.right(s),.right(i),.right(limit)): + return s.index(i, offsetBy: distance, limitedBy: limit).map { .right($0) } + default: fatalError("_EitherCollecton: wrong type of index used") + } + } + + internal func index(_ i: Index, offsetBy distance: Int) -> Index { + switch (self,i) { + case let (.left(s),.left(i)): return .left(s.index(i, offsetBy: distance)) + case let (.right(s),.right(i)): return .right(s.index(i, offsetBy: distance)) + default: fatalError("_EitherCollecton: wrong type of index used") + } + } + + internal func distance(from start: Index, to end: Index) -> Int { + switch (self,start,end) { + case let (.left(s),.left(i),.left(j)): + return s.distance(from: i, to: j) + case let (.right(s),.right(i),.right(j)): + return s.distance(from: i, to: j) + default: fatalError("_EitherCollecton: wrong type of index used") + } + } +} + +internal typealias _EitherBidirectionalCollection< + L: BidirectionalCollection, R: BidirectionalCollection +> = _Either where L.Element == R.Element + +extension _EitherBidirectionalCollection: BidirectionalCollection { + internal func index(before i: Index) -> Index { + switch (self,i) { + case let (.left(s),.left(i)): return .left(s.index(before: i)) + case let (.right(s),.right(i)): return .right(s.index(before: i)) + default: fatalError("_EitherCollecton: wrong type of index used") + } + } +} + +internal typealias _EitherRandomAccessCollection< + L: RandomAccessCollection, R: RandomAccessCollection +> = _Either where L.Element == R.Element + +extension _EitherRandomAccessCollection: RandomAccessCollection { } + +extension _Either { + init( + _ collection: C + ) where Right == AnyCollection, C.Element == T { + self = .right(AnyCollection(collection)) + } +} + +extension AnyCollection { + init( + _ other: _Either + ) where L.Element == Element, R.Element == Element { + // Strip away the Either and put the actual collection into the existential, + // trying to use the custom initializer from another AnyCollection. + switch other { + case let .left(l as Self): self = .init(l) + case let .right(r as Self): self = .init(r) + case let .left(l): self = .init(l) + case let .right(r): self = .init(r) + } + } +} + diff --git a/stdlib/public/core/GroupInfo.json b/stdlib/public/core/GroupInfo.json index e08fa92d9fd03..594e8094af872 100644 --- a/stdlib/public/core/GroupInfo.json +++ b/stdlib/public/core/GroupInfo.json @@ -64,6 +64,7 @@ "RandomAccessCollection.swift", "MutableCollection.swift", "CollectionAlgorithms.swift", + "EitherSequence.swift", "EmptyCollection.swift", "Stride.swift", "Repeat.swift", diff --git a/stdlib/public/core/Mirror.swift b/stdlib/public/core/Mirror.swift index 46b198bbded30..6e4faec37b049 100644 --- a/stdlib/public/core/Mirror.swift +++ b/stdlib/public/core/Mirror.swift @@ -100,25 +100,13 @@ public struct Mirror { /// `superclassMirror` property is `nil`. case suppressed } + - /// Creates a mirror that reflects on the given instance. - /// - /// If the dynamic type of `subject` conforms to `CustomReflectable`, the - /// resulting mirror is determined by its `customMirror` property. - /// Otherwise, the result is generated by the language. - /// - /// If the dynamic type of `subject` has value semantics, subsequent - /// mutations of `subject` will not observable in `Mirror`. In general, - /// though, the observability of mutations is unspecified. + /// The static type of the subject being reflected. /// - /// - Parameter subject: The instance for which to create a mirror. - public init(reflecting subject: Any) { - if case let customized as CustomReflectable = subject { - self = customized.customMirror - } else { - self = Mirror(internalReflecting: subject) - } - } + /// This type may differ from the subject's dynamic type when this mirror + /// is the `superclassMirror` of another mirror. + public let subjectType: Any.Type /// An element of the reflected instance's structure. /// @@ -142,6 +130,26 @@ public struct Mirror { /// } public typealias Children = AnyCollection + internal typealias _Children + = _EitherCollection> + + internal var _children: _Children + + /// A collection of `Child` elements describing the structure of the + /// reflected subject. + public var children: Children { AnyCollection(_children) } + + /// A suggested display style for the reflected subject. + public let displayStyle: DisplayStyle? + + /// A mirror of the subject's superclass, if one exists. + public var superclassMirror: Mirror? { + return _makeSuperclassMirror() + } + + internal let _makeSuperclassMirror: () -> Mirror? + internal let _defaultDescendantRepresentation: _DefaultDescendantRepresentation + /// A suggestion of how a mirror's subject is to be interpreted. /// /// Playgrounds and the debugger will show a representation similar @@ -152,6 +160,25 @@ public struct Mirror { case dictionary, `set` } + /// Creates a mirror that reflects on the given instance. + /// + /// If the dynamic type of `subject` conforms to `CustomReflectable`, the + /// resulting mirror is determined by its `customMirror` property. + /// Otherwise, the result is generated by the language. + /// + /// If the dynamic type of `subject` has value semantics, subsequent + /// mutations of `subject` will not observable in `Mirror`. In general, + /// though, the observability of mutations is unspecified. + /// + /// - Parameter subject: The instance for which to create a mirror. + public init(reflecting subject: Any) { + if case let customized as CustomReflectable = subject { + self = customized.customMirror + } else { + self = Mirror(internalReflecting: subject) + } + } + internal static func _noSuperclassMirror() -> Mirror? { return nil } @_semantics("optimize.sil.specialize.generic.never") @@ -223,7 +250,7 @@ public struct Mirror { self._makeSuperclassMirror = Mirror._superclassIterator( subject, ancestorRepresentation) - self.children = Children(children) + self._children = _Children(children) self.displayStyle = displayStyle self._defaultDescendantRepresentation = subject is CustomLeafReflectable ? .suppressed : .generated @@ -268,7 +295,7 @@ public struct Mirror { let lazyChildren = unlabeledChildren.lazy.map { Child(label: nil, value: $0) } - self.children = Children(lazyChildren) + self._children = _Children(lazyChildren) self.displayStyle = displayStyle self._defaultDescendantRepresentation @@ -315,33 +342,12 @@ public struct Mirror { subject, ancestorRepresentation) let lazyChildren = children.lazy.map { Child(label: $0.0, value: $0.1) } - self.children = Children(lazyChildren) + self._children = _Children(lazyChildren) self.displayStyle = displayStyle self._defaultDescendantRepresentation = subject is CustomLeafReflectable ? .suppressed : .generated } - - /// The static type of the subject being reflected. - /// - /// This type may differ from the subject's dynamic type when this mirror - /// is the `superclassMirror` of another mirror. - public let subjectType: Any.Type - - /// A collection of `Child` elements describing the structure of the - /// reflected subject. - public let children: Children - - /// A suggested display style for the reflected subject. - public let displayStyle: DisplayStyle? - - /// A mirror of the subject's superclass, if one exists. - public var superclassMirror: Mirror? { - return _makeSuperclassMirror() - } - - internal let _makeSuperclassMirror: () -> Mirror? - internal let _defaultDescendantRepresentation: _DefaultDescendantRepresentation } /// A type that explicitly supplies its own mirror. @@ -378,14 +384,6 @@ extension Int: MirrorPath {} extension String: MirrorPath {} extension Mirror { - internal struct _Dummy: CustomReflectable { - internal init(mirror: Mirror) { - self.mirror = mirror - } - internal var mirror: Mirror - internal var customMirror: Mirror { return mirror } - } - /// Returns a specific descendant of the reflected subject, or `nil` if no /// such descendant exists. /// @@ -433,24 +431,28 @@ extension Mirror { public func descendant( _ first: MirrorPath, _ rest: MirrorPath... ) -> Any? { - var result: Any = _Dummy(mirror: self) - for e in [first] + rest { - let children = Mirror(reflecting: result).children - let position: Children.Index - if case let label as String = e { - position = children.firstIndex { $0.label == label } ?? children.endIndex - } - else if let offset = e as? Int { + + func fetch(_ path: MirrorPath, in children: _Children) -> Any? { + let position: _Children.Index? + switch path { + case let label as String: + position = children.firstIndex { $0.label == label } + case let offset as Int: position = children.index(children.startIndex, offsetBy: offset, - limitedBy: children.endIndex) ?? children.endIndex - } - else { + limitedBy: children.endIndex) + default: _preconditionFailure( "Someone added a conformance to MirrorPath; that privilege is reserved to the standard library") } - if position == children.endIndex { return nil } - result = children[position].value + return position.map { children[$0].value } + } + + guard var result = fetch(first, in: _children) else { return nil } + for path in rest { + guard let next = fetch(path, in: Mirror(reflecting: result)._children) + else { return nil } + result = next } return result } diff --git a/stdlib/public/core/OutputStream.swift b/stdlib/public/core/OutputStream.swift index 972bdb9451d46..32727779defd8 100644 --- a/stdlib/public/core/OutputStream.swift +++ b/stdlib/public/core/OutputStream.swift @@ -293,7 +293,7 @@ internal func _adHocPrint_unlocked( if let displayStyle = mirror.displayStyle { switch displayStyle { case .optional: - if let child = mirror.children.first { + if let child = mirror._children.first { _debugPrint_unlocked(child.1, &target) } else { _debugPrint_unlocked("nil", &target) @@ -301,7 +301,7 @@ internal func _adHocPrint_unlocked( case .tuple: target.write("(") var first = true - for (label, value) in mirror.children { + for (label, value) in mirror._children { if first { first = false } else { @@ -322,7 +322,7 @@ internal func _adHocPrint_unlocked( printTypeName(mirror.subjectType) target.write("(") var first = true - for (label, value) in mirror.children { + for (label, value) in mirror._children { if let label = label { if first { first = false @@ -348,7 +348,7 @@ internal func _adHocPrint_unlocked( // If the case name is garbage, just print the type name. printTypeName(mirror.subjectType) } - if let (_, value) = mirror.children.first { + if let (_, value) = mirror._children.first { if Mirror(reflecting: value).displayStyle == .tuple { _debugPrint_unlocked(value, &target) } else { @@ -453,19 +453,19 @@ internal func _dumpPrint_unlocked( // count switch displayStyle { case .tuple: - let count = mirror.children.count + let count = mirror._children.count target.write(count == 1 ? "(1 element)" : "(\(count) elements)") return case .collection: - let count = mirror.children.count + let count = mirror._children.count target.write(count == 1 ? "1 element" : "\(count) elements") return case .dictionary: - let count = mirror.children.count + let count = mirror._children.count target.write(count == 1 ? "1 key/value pair" : "\(count) key/value pairs") return case .`set`: - let count = mirror.children.count + let count = mirror._children.count target.write(count == 1 ? "1 member" : "\(count) members") return default: diff --git a/stdlib/public/core/ReflectionMirror.swift b/stdlib/public/core/ReflectionMirror.swift index ead2c32caacbc..fd082e4b43602 100644 --- a/stdlib/public/core/ReflectionMirror.swift +++ b/stdlib/public/core/ReflectionMirror.swift @@ -104,17 +104,25 @@ internal func _getClassPlaygroundQuickLook( #endif extension Mirror { - internal init(internalReflecting subject: Any, - subjectType: Any.Type? = nil, - customAncestor: Mirror? = nil) - { + 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)) - let childCount = _getChildCount(subject, type: subjectType) - let children = (0 ..< childCount).lazy.map({ - getChild(of: subject, type: subjectType, index: $0) - }) - self.children = Children(children) + self._children = _Children( + ReflectedChildren(subject: subject, subjectType: subjectType)) self._makeSuperclassMirror = { guard let subjectClass = subjectType as? AnyClass,