forked from SwiftyLab/MetaCodable
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAnyPropertyVariable.swift
More file actions
200 lines (184 loc) · 7.19 KB
/
Copy pathAnyPropertyVariable.swift
File metadata and controls
200 lines (184 loc) · 7.19 KB
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
import SwiftSyntax
import SwiftSyntaxMacros
/// A type-erased variable value only containing initialization type data.
///
/// The `AnyPropertyVariable` type forwards `Variable` implementations
/// to an underlying variable value, hiding the type of the wrapped value.
struct AnyPropertyVariable<Initialization>: PropertyVariable
where Initialization: VariableInitialization {
/// The value wrapped by this instance.
///
/// The base property can be cast back
/// to its original type using type casting
/// operators (`as?`, `as!`, or `as`).
let base: any PropertyVariable
/// The initialization type handler for this variable.
///
/// By default, set as the underlying variable initialization
/// type is provided by this handler unless changed in initializer.
let initialization: (MacroExpansionContext) -> Initialization
/// The name of the variable.
///
/// Provides name of the underlying variable value.
var name: TokenSyntax { base.name }
/// The type of the variable.
///
/// Provides type of the underlying variable value.
var type: TypeSyntax { base.type }
/// The value of the variable.
///
/// Provides value of the underlying variable value.
var value: ExprSyntax? { base.value }
/// The prefix token to use along with `name` when decoding.
///
/// Provides underlying variable value decode prefix.
var decodePrefix: TokenSyntax { base.decodePrefix }
/// The prefix token to use along with `name` when encoding.
///
/// Provides underlying variable value encode prefix.
var encodePrefix: TokenSyntax { base.encodePrefix }
/// Whether the variable is to be decoded.
///
/// Provides whether underlying variable value
/// is to be decoded.
var decode: Bool? { base.decode }
/// Whether the variable is to be encoded.
///
/// Provides whether underlying variable value
/// is to be encoded.
var encode: Bool? { base.encode }
/// Whether the variable type requires `Decodable` conformance.
///
/// Provides whether underlying variable type requires
/// `Decodable` conformance.
var requireDecodable: Bool? { base.requireDecodable }
/// Whether the variable type requires `Encodable` conformance.
///
/// Provides whether underlying variable type requires
/// `Encodable` conformance.
var requireEncodable: Bool? { base.requireEncodable }
/// The fallback behavior when decoding fails.
///
/// In the event this decoding this variable is failed,
/// appropriate fallback would be applied.
///
/// Provides fallback for the underlying variable value.
var decodingFallback: DecodingFallback { base.decodingFallback }
/// Wraps the provided variable erasing its type and
/// initialization type.
///
/// The implementation is kept unchanged while
/// erasing this type and initialization type.
///
/// - Parameter base: The underlying variable value.
/// - Returns: Newly created variable.
init(base: some PropertyVariable<Initialization>) {
self.base = base
self.initialization = { base.initializing(in: $0) }
}
/// Wraps the provided variable erasing its type.
///
/// The implementation is kept unchanged while
/// erasing this type, initialization type is not erased.
/// - Parameter base: The underlying variable value.
/// - Returns: Newly created variable.
init<Var: PropertyVariable>(base: Var)
where
Var.Initialization: RequiredVariableInitialization,
Initialization == AnyRequiredVariableInitialization
{
self.base = base
self.initialization = { .init(base: base.initializing(in: $0)) }
}
/// Indicates the initialization type for this variable.
///
/// Provides initialization type of the underlying variable value.
///
/// - Parameter context: The context in which to perform
/// the macro expansion.
/// - Returns: The type of initialization for variable.
func initializing(
in context: some MacroExpansionContext
) -> Initialization {
initialization(context)
}
/// Provides the code syntax for decoding this variable
/// at the provided location.
///
/// Provides code syntax for decoding of the underlying
/// variable value.
///
/// - Parameters:
/// - context: The context in which to perform the macro expansion.
/// - location: The decoding location for the variable.
///
/// - Returns: The generated variable decoding code.
func decoding(
in context: some MacroExpansionContext,
from location: PropertyCodingLocation
) -> CodeBlockItemListSyntax {
base.decoding(in: context, from: location)
}
/// Provides the code syntax for encoding this variable
/// at the provided location.
///
/// Provides code syntax for encoding of the underlying
/// variable value.
///
/// - Parameters:
/// - context: The context in which to perform the macro expansion.
/// - location: The encoding location for the variable.
///
/// - Returns: The generated variable encoding code.
func encoding(
in context: some MacroExpansionContext,
to location: PropertyCodingLocation
) -> CodeBlockItemListSyntax {
base.encoding(in: context, to: location)
}
/// The number of variables this variable depends on.
///
/// Provides the number of variables underlying variable depends on.
var dependenciesCount: UInt { base.dependenciesCount }
/// Checks whether this variable is dependent on the provided variable.
///
/// Provides whether provided variable needs to be decoded first,
/// before decoding underlying variable value.
///
/// - Parameter variable: The variable to check for.
/// - Returns: Whether this variable is dependent on the provided variable.
func depends<Variable: PropertyVariable>(on variable: Variable) -> Bool {
base.depends(on: variable)
}
}
extension AnyPropertyVariable: AssociatedVariable
where Initialization: RequiredVariableInitialization {
/// The label of the variable.
///
/// Provides label of the underlying associated variable value,
/// `nil` if underlying variable not associated variable.
var label: TokenSyntax? {
guard let base = base as? any AssociatedVariable else { return nil }
return base.label
}
}
extension PropertyVariable where Initialization: VariableInitialization {
/// Erase type of this variable.
///
/// Wraps this variable in an `AnyPropertyVariable` instance.
/// The implementation stays unchanged while type is erased.
var any: AnyPropertyVariable<Self.Initialization> {
.init(base: self)
}
}
extension PropertyVariable
where Initialization: RequiredVariableInitialization {
/// Erase type of this variable and initialization type.
///
/// Wraps this variable in an `AnyPropertyVariable` instance and the initialization
/// type in `AnyRequiredVariableInitialization`. The implementation
/// stays unchanged while type is erased.
var any: AnyPropertyVariable<AnyRequiredVariableInitialization> {
.init(base: self)
}
}