|
2 | 2 | //
|
3 | 3 | // This source file is part of the Swift.org open source project
|
4 | 4 | //
|
5 |
| -// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors |
| 5 | +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors |
6 | 6 | // Licensed under Apache License v2.0 with Runtime Library Exception
|
7 | 7 | //
|
8 | 8 | // See https://swift.org/LICENSE.txt for license information
|
9 | 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
10 | 10 | //
|
11 | 11 | //===----------------------------------------------------------------------===//
|
12 | 12 |
|
| 13 | +@_silgen_name("swift_isClassType") |
| 14 | +internal func _isClassType(_: Any.Type) -> Bool |
| 15 | + |
| 16 | +@_silgen_name("swift_getMetadataKind") |
| 17 | +internal func _metadataKind(_: Any.Type) -> UInt |
| 18 | + |
13 | 19 | @_silgen_name("swift_reflectionMirror_normalizedType")
|
14 | 20 | internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
|
15 | 21 |
|
16 | 22 | @_silgen_name("swift_reflectionMirror_count")
|
17 | 23 | internal func _getChildCount<T>(_: T, type: Any.Type) -> Int
|
18 | 24 |
|
| 25 | +@_silgen_name("swift_reflectionMirror_recursiveCount") |
| 26 | +internal func _getRecursiveChildCount(_: Any.Type) -> Int |
| 27 | + |
| 28 | +@_silgen_name("swift_reflectionMirror_recursiveChildMetadata") |
| 29 | +internal func _getChildMetadata( |
| 30 | + _: Any.Type, |
| 31 | + index: Int, |
| 32 | + outName: UnsafeMutablePointer<UnsafePointer<CChar>?>, |
| 33 | + outFreeFunc: UnsafeMutablePointer<NameFreeFunc?> |
| 34 | +) -> Any.Type |
| 35 | + |
| 36 | +@_silgen_name("swift_reflectionMirror_recursiveChildOffset") |
| 37 | +internal func _getChildOffset( |
| 38 | + _: Any.Type, |
| 39 | + index: Int |
| 40 | +) -> Int |
| 41 | + |
19 | 42 | internal typealias NameFreeFunc = @convention(c) (UnsafePointer<CChar>?) -> Void
|
20 | 43 |
|
21 | 44 | @_silgen_name("swift_reflectionMirror_subscript")
|
@@ -168,3 +191,107 @@ extension Mirror {
|
168 | 191 | #endif
|
169 | 192 | }
|
170 | 193 | }
|
| 194 | + |
| 195 | +/// Options for calling `_forEachField(of:options:body:)`. |
| 196 | +@available(macOS 10.15.4, iOS 13.4, tvOS 13.4, watchOS 6.2, *) |
| 197 | +@_spi(Reflection) |
| 198 | +public struct _EachFieldOptions: OptionSet { |
| 199 | + public var rawValue: UInt32 |
| 200 | + |
| 201 | + public init(rawValue: UInt32) { |
| 202 | + self.rawValue = rawValue |
| 203 | + } |
| 204 | + |
| 205 | + /// Require the top-level type to be a class. |
| 206 | + /// |
| 207 | + /// If this is not set, the top-level type is required to be a struct or |
| 208 | + /// tuple. |
| 209 | + public static var classType = _EachFieldOptions(rawValue: 1 << 0) |
| 210 | + |
| 211 | + /// Ignore fields that can't be introspected. |
| 212 | + /// |
| 213 | + /// If not set, the presence of things that can't be introspected causes |
| 214 | + /// the function to immediately return `false`. |
| 215 | + public static var ignoreUnknown = _EachFieldOptions(rawValue: 1 << 1) |
| 216 | +} |
| 217 | + |
| 218 | +/// The metadata "kind" for a type. |
| 219 | +@available(macOS 10.15.4, iOS 13.4, tvOS 13.4, watchOS 6.2, *) |
| 220 | +@_spi(Reflection) |
| 221 | +public enum _MetadataKind: UInt { |
| 222 | + // With "flags": |
| 223 | + // runtimePrivate = 0x100 |
| 224 | + // nonHeap = 0x200 |
| 225 | + // nonType = 0x400 |
| 226 | + |
| 227 | + case `class` = 0 |
| 228 | + case `struct` = 0x200 // 0 | nonHeap |
| 229 | + case `enum` = 0x201 // 1 | nonHeap |
| 230 | + case optional = 0x202 // 2 | nonHeap |
| 231 | + case foreignClass = 0x203 // 3 | nonHeap |
| 232 | + case opaque = 0x300 // 0 | runtimePrivate | nonHeap |
| 233 | + case tuple = 0x301 // 1 | runtimePrivate | nonHeap |
| 234 | + case function = 0x302 // 2 | runtimePrivate | nonHeap |
| 235 | + case existential = 0x303 // 3 | runtimePrivate | nonHeap |
| 236 | + case metatype = 0x304 // 4 | runtimePrivate | nonHeap |
| 237 | + case objcClassWrapper = 0x305 // 5 | runtimePrivate | nonHeap |
| 238 | + case existentialMetatype = 0x306 // 6 | runtimePrivate | nonHeap |
| 239 | + case heapLocalVariable = 0x400 // 0 | nonType |
| 240 | + case heapGenericLocalVariable = 0x500 // 0 | nonType | runtimePrivate |
| 241 | + case errorObject = 0x501 // 1 | nonType | runtimePrivate |
| 242 | + case unknown = 0xffff |
| 243 | + |
| 244 | + init(_ type: Any.Type) { |
| 245 | + let v = _metadataKind(type) |
| 246 | + if let result = _MetadataKind(rawValue: v) { |
| 247 | + self = result |
| 248 | + } else { |
| 249 | + self = .unknown |
| 250 | + } |
| 251 | + } |
| 252 | +} |
| 253 | + |
| 254 | +/// Calls the given closure on every field of the specified type. |
| 255 | +/// |
| 256 | +/// If `body` returns `false` for any field, no additional fields are visited. |
| 257 | +/// |
| 258 | +/// - Parameters: |
| 259 | +/// - type: The type to inspect. |
| 260 | +/// - options: Options to use when reflecting over `type`. |
| 261 | +/// - body: A closure to call with information about each field in `type`. |
| 262 | +/// The parameters to `body` are a pointer to a C string holding the name |
| 263 | +/// of the field, the offset of the field in bytes, the type of the field, |
| 264 | +/// and the `_MetadataKind` of the field's type. |
| 265 | +/// - Returns: `true` if every invocation of `body` returns `true`; otherwise, |
| 266 | +/// `false`. |
| 267 | +@available(macOS 10.15.4, iOS 13.4, tvOS 13.4, watchOS 6.2, *) |
| 268 | +@discardableResult |
| 269 | +@_spi(Reflection) |
| 270 | +public func _forEachField( |
| 271 | + of type: Any.Type, |
| 272 | + options: _EachFieldOptions = [], |
| 273 | + body: (UnsafePointer<CChar>, Int, Any.Type, _MetadataKind) -> Bool |
| 274 | +) -> Bool { |
| 275 | + // Require class type iff `.classType` is included as an option |
| 276 | + if _isClassType(type) != options.contains(.classType) { |
| 277 | + return false |
| 278 | + } |
| 279 | + |
| 280 | + let childCount = _getRecursiveChildCount(type) |
| 281 | + for i in 0..<childCount { |
| 282 | + let offset = _getChildOffset(type, index: i) |
| 283 | + |
| 284 | + var nameC: UnsafePointer<CChar>? = nil |
| 285 | + var freeFunc: NameFreeFunc? = nil |
| 286 | + let childType = _getChildMetadata( |
| 287 | + type, index: i, outName: &nameC, outFreeFunc: &freeFunc) |
| 288 | + defer { freeFunc?(nameC) } |
| 289 | + let kind = _MetadataKind(childType) |
| 290 | + |
| 291 | + if !body(nameC!, offset, childType, kind) { |
| 292 | + return false |
| 293 | + } |
| 294 | + } |
| 295 | + |
| 296 | + return true |
| 297 | +} |
0 commit comments