/
Attribute.swift
113 lines (97 loc) · 2.84 KB
/
Attribute.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2023 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
//
//===----------------------------------------------------------------------===//
import Swift
import _Runtime
/// A namespace used for working with runtime attributes.
@available(SwiftStdlib 5.9, *)
@frozen
public enum Attribute {
/// Get all the instances of a runtime attribute wherever it's attached to.
///
/// Example:
///
/// @runtimeMetadata
/// struct Field {
/// let name: String
///
/// init<T, U>(attachedTo: KeyPath<T, U>, _ name: String) {
/// self.name = name
/// }
/// }
///
/// struct Dog {
/// @Field("dog_breed")
/// let breed: String
/// }
///
/// let fields = Attribute.allInstances(of: Field.self)
///
/// for field in fields {
/// print(field.name) // "dog_breed"
/// }
///
/// - Parameters:
/// - type: The type of the attribute that is attached to various sources.
/// - Returns: A sequence of attribute instances of `type` in no particular
/// order.
@available(SwiftStdlib 5.9, *)
public static func allInstances<T>(of type: T.Type) -> AttributeInstances<T> {
let meta = Metadata(T.self)
guard meta.kind == .struct ||
meta.kind == .enum ||
meta.kind == .class else {
return AttributeInstances([])
}
return ImageInspection.withAttributeCache {
let attrDescriptor = meta.type.descriptor.base
guard let fnPtrs = $0[attrDescriptor] else {
return AttributeInstances([])
}
return AttributeInstances(fnPtrs)
}
}
}
/// A sequence wrapper over some runtime attribute instances.
///
/// Instances of `AttributeInstances` are created with the
/// `Attribute.allInstances(of:)` function.
@available(SwiftStdlib 5.9, *)
@frozen
public struct AttributeInstances<T> {
@usableFromInline
let fnPtrs: [UnsafeRawPointer]
@usableFromInline
var index = 0
@available(SwiftStdlib 5.9, *)
init(_ fnPtrs: [UnsafeRawPointer]) {
self.fnPtrs = fnPtrs
}
}
@available(SwiftStdlib 5.9, *)
extension AttributeInstances: IteratorProtocol {
@available(SwiftStdlib 5.9, *)
@inlinable
public mutating func next() -> T? {
while index < fnPtrs.endIndex {
let fnPtr = fnPtrs[index]
index += 1
typealias AttributeFn = @convention(thin) () -> T?
let fn = unsafeBitCast(fnPtr, to: AttributeFn.self)
guard let attribute = fn() else {
continue
}
return attribute
}
return nil
}
}
@available(SwiftStdlib 5.9, *)
extension AttributeInstances: Sequence {}