Skip to content

Commit 3522a33

Browse files
committed
Create function to create an offset based keypath at runtime
1 parent 316dfaf commit 3522a33

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

stdlib/public/core/KeyPath.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3893,6 +3893,51 @@ internal func _instantiateKeyPathBuffer(
38933893
return offset
38943894
}
38953895

3896+
@available(SwiftStdlib 5.9, *)
3897+
public func _createOffsetBasedKeyPath(
3898+
root: Any.Type,
3899+
value: Any.Type,
3900+
offset: Int,
3901+
isClass: Bool = false
3902+
) -> AnyKeyPath {
3903+
func openRoot<Root>(_: Root.Type) -> AnyKeyPath.Type {
3904+
func openValue<Value>(_: Value.Type) -> AnyKeyPath.Type {
3905+
KeyPath<Root, Value>.self
3906+
}
3907+
3908+
return _openExistential(value, do: openValue(_:))
3909+
}
3910+
3911+
let kpTy = _openExistential(root, do: openRoot(_:))
3912+
3913+
// The buffer header is 32 bits, but components must start on a word
3914+
// boundary.
3915+
let kpBufferSize = MemoryLayout<Int>.size + MemoryLayout<Int32>.size
3916+
return kpTy._create(capacityInBytes: kpBufferSize) {
3917+
var builder = KeyPathBuffer.Builder($0)
3918+
let header = KeyPathBuffer.Header(
3919+
size: kpBufferSize - MemoryLayout<Int>.size,
3920+
trivial: true,
3921+
hasReferencePrefix: false
3922+
)
3923+
3924+
builder.pushHeader(header)
3925+
3926+
let componentHeader = RawKeyPathComponent.Header(
3927+
stored: isClass ? .class : .struct,
3928+
mutable: false,
3929+
inlineOffset: UInt32(offset)
3930+
)
3931+
3932+
let component = RawKeyPathComponent(
3933+
header: componentHeader,
3934+
body: UnsafeRawBufferPointer(start: nil, count: 0)
3935+
)
3936+
3937+
component.clone(into: &builder.buffer, endOfReferencePrefix: false)
3938+
}
3939+
}
3940+
38963941
#if SWIFT_ENABLE_REFLECTION
38973942

38983943
@_silgen_name("swift_keyPath_copySymbolName")

test/stdlib/KeyPath.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,5 +1065,26 @@ keyPath.test("ReferenceWritableKeyPath statically typed as WritableKeyPath") {
10651065
expectEqual(outer[keyPath: upcastKeyPath], 46)
10661066
}
10671067

1068+
struct Dog {
1069+
var name: String
1070+
var age: Int
1071+
}
1072+
1073+
if #available(SwiftStdlib 5.9, *) {
1074+
keyPath.test("_createOffsetBasedKeyPath") {
1075+
let dogAgeKp = _createOffsetBasedKeyPath(
1076+
root: Dog.self,
1077+
value: Int.self,
1078+
offset: 16
1079+
) as? KeyPath<Dog, Int>
1080+
1081+
expectNotNil(dogAgeKp)
1082+
1083+
let sparky = Dog(name: "Sparky", age: 7)
1084+
1085+
expectEqual(sparky[keyPath: dogAgeKp!], 7)
1086+
}
1087+
}
1088+
10681089
runAllTests()
10691090

0 commit comments

Comments
 (0)