From 47b6d2e9d0e2d39bba0d91225999d8d4c86699aa Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Thu, 25 Jun 2026 10:16:13 -0700 Subject: [PATCH 1/2] Add `CasePathable.case` With the introduction of `CasePathReflectable` we could look up an enum's case statically: ```swift let enum = Foo.bar Enum.allCasePaths[enum] // \.bar ``` Let's make things a little more ergonomic by introducing a `case` property. As a keyword, `case` is unlikely to conflict with other properties, and it makes enums a little more usable where key path APIs are involved: ```swift .sheet(item: $enum, id: \.case) { enum in // ... } ``` --- Sources/CasePathsCore/CasePathable.swift | 7 +++++++ .../Documentation.docc/Extensions/CasePathable.md | 1 + Tests/CasePathsTests/CasePathsTests.swift | 2 ++ 3 files changed, 10 insertions(+) diff --git a/Sources/CasePathsCore/CasePathable.swift b/Sources/CasePathsCore/CasePathable.swift index a4565118..a890f3f3 100644 --- a/Sources/CasePathsCore/CasePathable.swift +++ b/Sources/CasePathsCore/CasePathable.swift @@ -493,6 +493,13 @@ extension CasePathable { } } +extension CasePathable where AllCasePaths: CasePathReflectable { + /// A case key path to this enum's case. + public var `case`: PartialCaseKeyPath { + Self.allCasePaths[self] + } +} + extension AnyCasePath { /// Creates a type-erased case path for given case key path. /// diff --git a/Sources/CasePathsCore/Documentation.docc/Extensions/CasePathable.md b/Sources/CasePathsCore/Documentation.docc/Extensions/CasePathable.md index cecb804e..bbe779f3 100644 --- a/Sources/CasePathsCore/Documentation.docc/Extensions/CasePathable.md +++ b/Sources/CasePathsCore/Documentation.docc/Extensions/CasePathable.md @@ -14,6 +14,7 @@ ### Case properties +- ``case`` - ``is(_:)`` - ``subscript(dynamicMember:)-emck`` - ``subscript(dynamicMember:)-dm5y`` diff --git a/Tests/CasePathsTests/CasePathsTests.swift b/Tests/CasePathsTests/CasePathsTests.swift index 4e1a7405..9f1fb715 100644 --- a/Tests/CasePathsTests/CasePathsTests.swift +++ b/Tests/CasePathsTests/CasePathsTests.swift @@ -60,6 +60,8 @@ final class CasePathsTests: XCTestCase { func testCaseKeyPaths() { var foo: Foo = .bar(.int(1)) + XCTAssertEqual(foo.case, \.bar) + XCTAssertEqual(foo.bar, .int(1)) // NB: Due to a Swift bug, this is only possible to do outside the library: // XCTAssertEqual(foo.bar?.int, 1) From e7374721b9de94da95507d4890182cca5c097e16 Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Thu, 25 Jun 2026 11:14:40 -0700 Subject: [PATCH 2/2] wip --- Sources/CasePathsCore/Optional+CasePathable.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/CasePathsCore/Optional+CasePathable.swift b/Sources/CasePathsCore/Optional+CasePathable.swift index 9b9ff213..6753e7cc 100644 --- a/Sources/CasePathsCore/Optional+CasePathable.swift +++ b/Sources/CasePathsCore/Optional+CasePathable.swift @@ -32,6 +32,7 @@ extension Optional: CasePathable, CasePathIterable { /// A case path to an optional-chained value. @_disfavoredOverload + @available(*, deprecated, message: "This subscript will be removed in CasePaths 2.0") public subscript( dynamicMember keyPath: KeyPath> ) -> AnyCasePath