Files
swift-mirror/stdlib/internal/SwiftExperimental/Mirror.swift
Dave Abrahams 6af025bcaa [stdlib] NewMirrors: bring back our Schema enum
Swift SVN r26365
2015-03-20 22:34:46 +00:00

196 lines
5.6 KiB
Swift

//===--- Mirror.swift -----------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
public struct Mirror {
public typealias Child = (label: String?, value: Any)
public typealias Structure = AnyForwardCollection<Child>
public enum Schema {
case Struct, Class, Enum, Tuple, Optional, Collection, Dictionary, Set,
ObjectiveCObject
init?(legacy: MirrorDisposition) {
switch legacy {
case .Struct: self = .Struct
case .Class: self = .Class
case .Enum: self = .Enum
case .Tuple: self = .Tuple
case .Aggregate: return nil
case .IndexContainer: self = .Collection
case .KeyContainer: self = .Dictionary
case .MembershipContainer: self = .Set
case .Container: preconditionFailure("unused!")
case .Optional: self = .Optional
case .ObjCObject: self = .ObjectiveCObject
}
}
}
public init<
C: CollectionType where C.Generator.Element == Child
>(structure: C, schema: Schema? = nil) {
self.structure = Structure(structure)
self.schema = schema
}
public init<
C: CollectionType
>(_ unlabeledChildren: C, schema: Schema? = nil) {
self.structure = Structure(
lazy(unlabeledChildren).map { Child(label: nil, value: $0) }
)
self.schema = schema
}
public let structure: Structure
public let schema: Schema?
}
extension Mirror {
internal struct LegacyChildren : CollectionType {
init(_ oldMirror: MirrorType) {
self._oldMirror = oldMirror
}
var startIndex: Int { return 0 }
var endIndex: Int { return _oldMirror.count }
subscript(position: Int) -> Child {
let (label, childMirror) = _oldMirror[position]
return (label: label, value: childMirror.value)
}
func generate() -> IndexingGenerator<LegacyChildren> {
return IndexingGenerator(self)
}
internal let _oldMirror: MirrorType
}
public init(_ oldMirror: MirrorType) {
self.init(
structure: LegacyChildren(oldMirror),
schema: Schema(legacy: oldMirror.disposition))
}
}
public protocol CustomReflectable {
func reflect() -> Mirror
}
public func reflect(x: Any) -> Mirror {
if let customized? = x as? CustomReflectable {
return customized.reflect()
}
else {
return Mirror(Swift.reflect(x))
}
}
//===--- Addressing -------------------------------------------------------===//
public protocol MirrorPathType {}
extension IntMax : MirrorPathType {}
extension Int : MirrorPathType {}
extension String : MirrorPathType {}
/// Returns the first index `i` in `indices(domain)` such that
/// `predicate(domain[i])` is `true``, or `nil` if
/// `predicate(domain[i])` is `false` for all `i`.
///
/// Complexity: O(\ `count(domain)`\ )
public func find<
C: CollectionType
>(domain: C, predicate: (C.Generator.Element)->Bool) -> C.Index? {
for i in indices(domain) {
if predicate(domain[i]) {
return i
}
}
return nil
}
extension Mirror {
struct _Dummy : CustomReflectable {
var mirror: Mirror
func reflect() -> Mirror { return mirror }
}
public func descendant(
first: MirrorPathType, _ rest: MirrorPathType...
) -> Any? {
var result: Any = _Dummy(mirror: self)
for e in [first] + rest {
let structure = reflect(result).structure
let position: Structure.Index
if let label? = e as? String {
position = find(structure) { $0.label == label } ?? structure.endIndex
}
else if let offset? = (e as? Int).map({ IntMax($0) }) ?? (e as? IntMax) {
position = advance(structure.startIndex, offset, structure.endIndex)
}
else {
_preconditionFailure(
"Someone added a conformance to MirrorPathType; that privilege is reserved to the standard library")
}
if position == structure.endIndex { return nil }
result = structure[position].value
}
return result
}
}
//===--- Adapters ---------------------------------------------------------===//
//===----------------------------------------------------------------------===//
public struct LabeledStructure<Element>
: CollectionType, DictionaryLiteralConvertible {
public init(dictionaryLiteral elements: (String, Element)...) {
self.elements = elements
}
/// Construct a copy of `other`
///
/// exists primarily so a Dictionary literal can be passed as an argument
public init(_ other: LabeledStructure) {
self.elements = other.elements
}
public init(_ elements: [(String, Element)]) {
self.elements = elements
}
public var startIndex: Int { return 0 }
public var endIndex: Int { return elements.endIndex }
public subscript(position: Int) -> Mirror.Child {
return (label: elements[position].0, value: elements[position].1)
}
public func generate() -> IndexingGenerator<LabeledStructure> {
return IndexingGenerator(self)
}
internal let elements: [(String, Element)]
}
extension Mirror : DictionaryLiteralConvertible {
typealias Key = String
typealias Value = Any
public init(dictionaryLiteral elements: (String, Any)...) {
self.init(LabeledStructure(elements))
}
public init<Element>(
_ structure: LabeledStructure<Element>, schema: Schema? = nil
) {
self.structure = Structure(structure)
self.schema = schema
}
}