1010//
1111//===----------------------------------------------------------------------===//
1212
13+ import SwiftShims
14+
1315@_silgen_name ( " swift_isClassType " )
1416internal func _isClassType( _: Any . Type ) -> Bool
1517
@@ -29,8 +31,7 @@ internal func _getRecursiveChildCount(_: Any.Type) -> Int
2931internal func _getChildMetadata(
3032 _: Any . Type ,
3133 index: Int ,
32- outName: UnsafeMutablePointer < UnsafePointer < CChar > ? > ,
33- outFreeFunc: UnsafeMutablePointer < NameFreeFunc ? >
34+ fieldMetadata: UnsafeMutablePointer < _FieldReflectionMetadata >
3435) -> Any . Type
3536
3637@_silgen_name ( " swift_reflectionMirror_recursiveChildOffset " )
@@ -281,14 +282,91 @@ public func _forEachField(
281282 for i in 0 ..< childCount {
282283 let offset = _getChildOffset ( type, index: i)
283284
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) }
285+ var field = _FieldReflectionMetadata ( )
286+ let childType = _getChildMetadata ( type, index: i, fieldMetadata: & field)
287+ defer { field. freeFunc ? ( field. name) }
288+ let kind = _MetadataKind ( childType)
289+
290+ if !body( field. name!, offset, childType, kind) {
291+ return false
292+ }
293+ }
294+
295+ return true
296+ }
297+
298+ /// Calls the given closure on every field of the specified type.
299+ ///
300+ /// If `body` returns `false` for any field, no additional fields are visited.
301+ ///
302+ /// - Parameters:
303+ /// - type: The type to inspect.
304+ /// - options: Options to use when reflecting over `type`.
305+ /// - body: A closure to call with information about each field in `type`.
306+ /// The parameters to `body` are a pointer to a C string holding the name
307+ /// of the field, the offset of the field in bytes, the type of the field,
308+ /// and the `_MetadataKind` of the field's type.
309+ /// - Returns: `true` if every invocation of `body` returns `true`; otherwise,
310+ /// `false`.
311+ @available ( macOS 9999 , iOS 9999 , tvOS 9999 , watchOS 9999 , * )
312+ @discardableResult
313+ @_spi ( Reflection)
314+ public func _forEachFieldWithKeyPath< Root> (
315+ of type: Root . Type ,
316+ options: _EachFieldOptions = [ ] ,
317+ body: ( UnsafePointer < CChar > , PartialKeyPath < Root > ) -> Bool
318+ ) -> Bool {
319+ // Class types not supported because the metadata does not have
320+ // enough information to construct computed properties.
321+ if _isClassType ( type) || options. contains ( . classType) {
322+ return false
323+ }
324+ let ignoreUnknown = options. contains ( . ignoreUnknown)
325+
326+ let childCount = _getRecursiveChildCount ( type)
327+ for i in 0 ..< childCount {
328+ let offset = _getChildOffset ( type, index: i)
329+
330+ var field = _FieldReflectionMetadata ( )
331+ let childType = _getChildMetadata ( type, index: i, fieldMetadata: & field)
332+ defer { field. freeFunc ? ( field. name) }
289333 let kind = _MetadataKind ( childType)
334+ let supportedType : Bool
335+ switch kind {
336+ case . struct, . class, . optional, . existential,
337+ . existentialMetatype, . tuple, . enum:
338+ supportedType = true
339+ default :
340+ supportedType = false
341+ }
342+ if !supportedType || !field. isStrong {
343+ if !ignoreUnknown { return false }
344+ continue ;
345+ }
346+ func keyPathType< Leaf> ( for: Leaf . Type ) -> PartialKeyPath < Root > . Type {
347+ if field. isVar { return WritableKeyPath < Root , Leaf > . self }
348+ return KeyPath < Root , Leaf > . self
349+ }
350+ let resultSize = MemoryLayout < Int32 > . size + MemoryLayout < Int > . size
351+ let partialKeyPath = _openExistential ( childType, do: keyPathType)
352+ . _create ( capacityInBytes: resultSize) {
353+ var destBuilder = KeyPathBuffer . Builder ( $0)
354+ destBuilder. pushHeader ( KeyPathBuffer . Header (
355+ size: resultSize - MemoryLayout< Int> . size,
356+ trivial: true ,
357+ hasReferencePrefix: false
358+ ) )
359+ let component = RawKeyPathComponent (
360+ header: RawKeyPathComponent . Header ( stored: . struct,
361+ mutable: field. isVar,
362+ inlineOffset: UInt32 ( offset) ) ,
363+ body: UnsafeRawBufferPointer ( start: nil , count: 0 ) )
364+ component. clone (
365+ into: & destBuilder. buffer,
366+ endOfReferencePrefix: false )
367+ }
290368
291- if !body( nameC !, offset , childType , kind ) {
369+ if !body( field . name !, partialKeyPath ) {
292370 return false
293371 }
294372 }
0 commit comments