@@ -162,4 +162,59 @@ extension MemoryLayout {
162
162
public static func alignment( ofValue value: T ) -> Int {
163
163
return MemoryLayout . alignment
164
164
}
165
+
166
+ /// Returns the offset of an inline stored property of `T` within the
167
+ /// in-memory representation of `T`.
168
+ ///
169
+ /// If the given `key` refers to inline, directly addressable storage within
170
+ /// the in-memory representation of `T`, then the return value is a distance
171
+ /// in bytes that can be added to a pointer of type `T` to get a pointer to
172
+ /// the storage accessed by `key`. If the return value is non-nil, then these
173
+ /// formulations are equivalent:
174
+ ///
175
+ /// var root: T, value: U
176
+ /// var key: WritableKeyPath<T, U>
177
+ /// // Mutation through the key path...
178
+ /// root[keyPath: key] = value
179
+ /// // ...is exactly equivalent to mutation through the offset pointer...
180
+ /// withUnsafeMutablePointer(to: &root) {
181
+ /// (UnsafeMutableRawPointer($0) + MemoryLayout<T>.offset(of: key))
182
+ /// // ...which can be assumed to be bound to the target type
183
+ /// .assumingMemoryBound(to: U.self).pointee = value
184
+ /// }
185
+ ///
186
+ /// - Parameter key: A key path referring to storage that can be accessed
187
+ /// through a value of type `T`.
188
+ /// - Returns: The offset in bytes from a pointer to a value of type `T`
189
+ /// to a pointer to the storage referenced by `key`, or `nil` if no
190
+ /// such offset is available for the storage referenced by `key`, such as
191
+ /// because `key` is computed, has observers, requires reabstraction, or
192
+ /// overlaps storage with other properties.
193
+ ///
194
+ /// A property has inline, directly addressable storage when it is a stored
195
+ /// property for which no additional work is required to extract or set the
196
+ /// value. For example:
197
+ ///
198
+ /// struct ProductCategory {
199
+ /// var name: String // inline, directly-addressable
200
+ /// var updateCounter: Int // inline, directly-addressable
201
+ /// var productCount: Int { // computed properties are not directly addressable
202
+ /// return products.count
203
+ /// }
204
+ /// var products: [Product] { // didSet/willSet properties are not directly addressable
205
+ /// didSet { updateCounter += 1 }
206
+ /// }
207
+ /// }
208
+ ///
209
+ /// When using `offset(of:)` with a type imported from a library, don't assume
210
+ /// that future versions of the library will have the same behavior. If a
211
+ /// property is converted from a stored property to a computed property, the
212
+ /// result of `offset(of:)` changes to `nil`. That kind of conversion is
213
+ /// non-breaking in other contexts, but would trigger a runtime error if the
214
+ /// result of `offset(of:)` is force-unwrapped.
215
+ @_inlineable // FIXME(sil-serialize-all)
216
+ @_transparent
217
+ public static func offset( of key: PartialKeyPath < T > ) -> Int ? {
218
+ return key. _storedInlineOffset
219
+ }
165
220
}
0 commit comments