Skip to content

Commit

Permalink
Improve dynamic "case" lookup performance (#137)
Browse files Browse the repository at this point in the history
When writing algorithms against dynamic "case" lookup it's more
performant to work directly with the case-pathable type rather than use
case key paths, which resolve lazily and have a higher cost.
  • Loading branch information
stephencelis authored Jan 3, 2024
1 parent 8059322 commit a7592b6
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 139 deletions.
8 changes: 4 additions & 4 deletions Examples/CaseStudies/08-Routing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ private let readMe = """
This case study demonstrates how to power multiple forms of navigation from a single destination \
enum that describes all of the possible destinations one can travel to from this screen.
The screen has four navigation destinations: an alert, a confirmation dialog, a navigation link to a count stepper, \
and a modal sheet to a count stepper. The state for each of these destinations is held as \
associated data of an enum, and bindings to the cases of that enum are derived using the tools \
in this library.
The screen has four navigation destinations: an alert, a confirmation dialog, a navigation link \
to a count stepper, and a modal sheet to a count stepper. The state for each of these \
destinations is held as associated data of an enum, and bindings to the cases of that enum are \
derived using the tools in this library.
"""

@CasePathable
Expand Down
17 changes: 13 additions & 4 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@
"repositoryURL": "https://github.com/pointfreeco/swift-case-paths",
"state": {
"branch": null,
"revision": "40773cbaf8d71ed5357f297b1ba4073f5b24faaa",
"version": "1.1.0"
"revision": "bba1111185863c9288c5f047770f421c3b7793a4",
"version": "1.1.3"
}
},
{
"package": "swift-custom-dump",
"repositoryURL": "https://github.com/pointfreeco/swift-custom-dump",
"state": {
"branch": null,
"revision": "edd66cace818e1b1c6f1b3349bb1d8e00d6f8b01",
"version": "1.0.0"
"revision": "aedcf6f4cd486ccef5b312ccac85d4b3f6e58605",
"version": "1.1.2"
}
},
{
Expand All @@ -37,6 +37,15 @@
"version": "1.0.0"
}
},
{
"package": "swift-syntax",
"repositoryURL": "https://github.com/apple/swift-syntax.git",
"state": {
"branch": null,
"revision": "6ad4ea24b01559dde0773e3d091f1b9e36175036",
"version": "509.0.2"
}
},
{
"package": "xctest-dynamic-overlay",
"repositoryURL": "https://github.com/pointfreeco/xctest-dynamic-overlay",
Expand Down
27 changes: 15 additions & 12 deletions Sources/SwiftUINavigation/Binding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
/// - Parameter keyPath: A case key path to a specific associated value.
/// - Returns: A new binding.
public subscript<Member>(
dynamicMember keyPath: CaseKeyPath<Value, Member>
dynamicMember keyPath: KeyPath<Value.AllCasePaths, AnyCasePath<Value, Member>>
) -> Binding<Member>?
where Value: CasePathable {
Binding<Member>(
let casePath = Value.allCasePaths[keyPath: keyPath]
return Binding<Member>(
unwrapping: Binding<Member?>(
get: { self.wrappedValue[case: keyPath] },
get: { casePath.extract(from: self.wrappedValue) },
set: { newValue, transaction in
guard let newValue else { return }
self.transaction(transaction).wrappedValue[case: keyPath] = newValue
self.transaction(transaction).wrappedValue = casePath.embed(newValue)
}
)
)
Expand All @@ -31,20 +32,22 @@
///
/// - Parameter keyPath: A case key path to a specific associated value.
/// - Returns: A new binding.
public subscript<Enum, AssociatedValue>(
dynamicMember keyPath: CaseKeyPath<Enum, AssociatedValue>
) -> Binding<AssociatedValue?>
public subscript<Enum: CasePathable, Member>(
dynamicMember keyPath: KeyPath<Enum.AllCasePaths, AnyCasePath<Enum, Member>>
) -> Binding<Member?>
where Value == Enum? {
return Binding<AssociatedValue?>(
get: { self.wrappedValue[case: (\Enum?.Cases.some).appending(path: keyPath)] },
let casePath = Enum.allCasePaths[keyPath: keyPath]
return Binding<Member?>(
get: {
guard let wrappedValue = self.wrappedValue else { return nil }
return casePath.extract(from: wrappedValue)
},
set: { newValue, transaction in
guard let newValue else {
self.transaction(transaction).wrappedValue = nil
return
}
self.transaction(transaction).wrappedValue[
case: (\Enum?.Cases.some).appending(path: keyPath)
] = newValue
self.transaction(transaction).wrappedValue = casePath.embed(newValue)
}
)
}
Expand Down
240 changes: 121 additions & 119 deletions SwiftUINavigation.xcworkspace/xcshareddata/swiftpm/Package.resolved
Original file line number Diff line number Diff line change
@@ -1,122 +1,124 @@
{
"pins" : [
{
"identity" : "combine-schedulers",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/combine-schedulers",
"state" : {
"revision" : "9dc9cbe4bc45c65164fa653a563d8d8db61b09bb",
"version" : "1.0.0"
"object": {
"pins": [
{
"package": "combine-schedulers",
"repositoryURL": "https://github.com/pointfreeco/combine-schedulers",
"state": {
"branch": null,
"revision": "9dc9cbe4bc45c65164fa653a563d8d8db61b09bb",
"version": "1.0.0"
}
},
{
"package": "swift-case-paths",
"repositoryURL": "https://github.com/pointfreeco/swift-case-paths",
"state": {
"branch": null,
"revision": "bba1111185863c9288c5f047770f421c3b7793a4",
"version": "1.1.3"
}
},
{
"package": "swift-clocks",
"repositoryURL": "https://github.com/pointfreeco/swift-clocks",
"state": {
"branch": null,
"revision": "a8421d68068d8f45fbceb418fbf22c5dad4afd33",
"version": "1.0.2"
}
},
{
"package": "swift-collections",
"repositoryURL": "https://github.com/apple/swift-collections",
"state": {
"branch": null,
"revision": "d029d9d39c87bed85b1c50adee7c41795261a192",
"version": "1.0.6"
}
},
{
"package": "swift-concurrency-extras",
"repositoryURL": "https://github.com/pointfreeco/swift-concurrency-extras",
"state": {
"branch": null,
"revision": "bb5059bde9022d69ac516803f4f227d8ac967f71",
"version": "1.1.0"
}
},
{
"package": "swift-custom-dump",
"repositoryURL": "https://github.com/pointfreeco/swift-custom-dump",
"state": {
"branch": null,
"revision": "aedcf6f4cd486ccef5b312ccac85d4b3f6e58605",
"version": "1.1.2"
}
},
{
"package": "swift-dependencies",
"repositoryURL": "http://github.com/pointfreeco/swift-dependencies",
"state": {
"branch": null,
"revision": "c31b1445c4fae49e6fdb75496b895a3653f6aefc",
"version": "1.1.5"
}
},
{
"package": "SwiftDocCPlugin",
"repositoryURL": "https://github.com/apple/swift-docc-plugin",
"state": {
"branch": null,
"revision": "26ac5758409154cc448d7ab82389c520fa8a8247",
"version": "1.3.0"
}
},
{
"package": "SymbolKit",
"repositoryURL": "https://github.com/apple/swift-docc-symbolkit",
"state": {
"branch": null,
"revision": "b45d1f2ed151d057b54504d653e0da5552844e34",
"version": "1.0.0"
}
},
{
"package": "swift-identified-collections",
"repositoryURL": "https://github.com/pointfreeco/swift-identified-collections.git",
"state": {
"branch": null,
"revision": "d1e45f3e1eee2c9193f5369fa9d70a6ddad635e8",
"version": "1.0.0"
}
},
{
"package": "swift-syntax",
"repositoryURL": "https://github.com/apple/swift-syntax.git",
"state": {
"branch": null,
"revision": "6ad4ea24b01559dde0773e3d091f1b9e36175036",
"version": "509.0.2"
}
},
{
"package": "swift-tagged",
"repositoryURL": "https://github.com/pointfreeco/swift-tagged.git",
"state": {
"branch": null,
"revision": "3907a9438f5b57d317001dc99f3f11b46882272b",
"version": "0.10.0"
}
},
{
"package": "xctest-dynamic-overlay",
"repositoryURL": "https://github.com/pointfreeco/xctest-dynamic-overlay",
"state": {
"branch": null,
"revision": "23cbf2294e350076ea4dbd7d5d047c1e76b03631",
"version": "1.0.2"
}
}
},
{
"identity" : "swift-case-paths",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-case-paths",
"state" : {
"revision" : "40773cbaf8d71ed5357f297b1ba4073f5b24faaa",
"version" : "1.1.0"
}
},
{
"identity" : "swift-clocks",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-clocks",
"state" : {
"revision" : "d1fd837326aa719bee979bdde1f53cd5797443eb",
"version" : "1.0.0"
}
},
{
"identity" : "swift-collections",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections",
"state" : {
"revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2",
"version" : "1.0.4"
}
},
{
"identity" : "swift-concurrency-extras",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-concurrency-extras",
"state" : {
"revision" : "ea631ce892687f5432a833312292b80db238186a",
"version" : "1.0.0"
}
},
{
"identity" : "swift-custom-dump",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-custom-dump",
"state" : {
"revision" : "edd66cace818e1b1c6f1b3349bb1d8e00d6f8b01",
"version" : "1.0.0"
}
},
{
"identity" : "swift-dependencies",
"kind" : "remoteSourceControl",
"location" : "http://github.com/pointfreeco/swift-dependencies",
"state" : {
"revision" : "4e1eb6e28afe723286d8cc60611237ffbddba7c5",
"version" : "1.0.0"
}
},
{
"identity" : "swift-docc-plugin",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-docc-plugin",
"state" : {
"revision" : "26ac5758409154cc448d7ab82389c520fa8a8247",
"version" : "1.3.0"
}
},
{
"identity" : "swift-docc-symbolkit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-docc-symbolkit",
"state" : {
"revision" : "b45d1f2ed151d057b54504d653e0da5552844e34",
"version" : "1.0.0"
}
},
{
"identity" : "swift-identified-collections",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-identified-collections.git",
"state" : {
"revision" : "d1e45f3e1eee2c9193f5369fa9d70a6ddad635e8",
"version" : "1.0.0"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "74203046135342e4a4a627476dd6caf8b28fe11b",
"version" : "509.0.0"
}
},
{
"identity" : "swift-tagged",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-tagged.git",
"state" : {
"revision" : "3907a9438f5b57d317001dc99f3f11b46882272b",
"version" : "0.10.0"
}
},
{
"identity" : "xctest-dynamic-overlay",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/xctest-dynamic-overlay",
"state" : {
"revision" : "23cbf2294e350076ea4dbd7d5d047c1e76b03631",
"version" : "1.0.2"
}
}
],
"version" : 2
]
},
"version": 1
}

0 comments on commit a7592b6

Please sign in to comment.