From 4319e31afcb277d067bcdf45057bb0d8d368f0e9 Mon Sep 17 00:00:00 2001 From: Robbert Brandsma Date: Fri, 26 Jan 2024 20:07:04 +0100 Subject: [PATCH] Added CaseKeyPath support --- Package.swift | 6 ++-- Sources/Sync/Sync.swift | 72 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/Package.swift b/Package.swift index f79788e..d32edb1 100644 --- a/Package.swift +++ b/Package.swift @@ -24,9 +24,9 @@ let package = Package( /// 🪄 Magical testing tools for Swift macros. .package(url: "https://github.com/pointfreeco/swift-macro-testing.git", from: "0.2.2"), - - /// Macro helpers - .package(url: "https://github.com/stackotter/swift-macro-toolkit.git", from: "0.3.1"), + + /// For enum support + .package(url: "https://github.com/pointfreeco/swift-case-paths.git", from: "1.2.1") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. diff --git a/Sources/Sync/Sync.swift b/Sources/Sync/Sync.swift index d19fa99..53010a1 100644 --- a/Sources/Sync/Sync.swift +++ b/Sources/Sync/Sync.swift @@ -1,20 +1,33 @@ +import CasePaths + @attached(accessor) @attached(peer, names: prefixed(_)) public macro Sync( - _ sync: repeat (_: WritableKeyPath, to: WritableKeyPath) + _ sync: repeat (_: KeyPath, to: KeyPath) ) = #externalMacro(module: "SyncMacros", type: "SyncMacro") +@attached(accessor) +@attached(peer, names: prefixed(_)) +public macro Sync( + _ sync: repeat ( + _: CaseKeyPath, _: KeyPath, to: KeyPath + ) +) = #externalMacro(module: "SyncMacros", type: "SyncMacro") + +// MARK: Support functions - non-optional + public func _syncToChild( parent: Parent, child: Child, _ keyPaths: repeat ( - _: WritableKeyPath, to: WritableKeyPath + _: KeyPath, to: KeyPath ) ) -> Child { var child = child - func sync(_ keyPath: (_: WritableKeyPath, to: WritableKeyPath)) { - child[keyPath: keyPath.0] = parent[keyPath: keyPath.to] + func sync(_ keyPath: (_: KeyPath, to: KeyPath)) { + guard let childKeyPath = keyPath.0 as? WritableKeyPath else { return } + child[keyPath: childKeyPath] = parent[keyPath: keyPath.to] } repeat sync(each keyPaths) @@ -26,14 +39,59 @@ public func _syncToParent( parent: inout Parent, child: Child, _ keyPaths: repeat ( - _: WritableKeyPath, to: WritableKeyPath + _: KeyPath, to: KeyPath ) ) -> Child { - func sync(_ keyPath: (_: WritableKeyPath, to: WritableKeyPath)) { - parent[keyPath: keyPath.to] = child[keyPath: keyPath.0] + func sync(_ keyPath: (_: KeyPath, to: KeyPath)) { + guard let to = keyPath.to as? WritableKeyPath else { return } + parent[keyPath: to] = child[keyPath: keyPath.0] } repeat sync(each keyPaths) return child } + +// MARK: CaseKeyPath support + +public func _syncToChild( + parent: Parent, + child: Child, + _ keyPaths: repeat ( + _: CaseKeyPath, _: KeyPath, to: KeyPath + ) +) -> Child where Child: CasePathable { + var child = child + + func sync(_ keyPath: (_: CaseKeyPath, _: KeyPath, to: KeyPath)) { + guard + let valueCaseStateKeyPath = keyPath.1 as? WritableKeyPath, + var value = child[case: keyPath.0] else { return } + value[keyPath: valueCaseStateKeyPath] = parent[keyPath: keyPath.to] + child = keyPath.0(value) + } + + repeat sync(each keyPaths) + + return child +} + +public func _syncToParent( + parent: inout Parent, + child: Child, + _ keyPaths: repeat ( + _: CaseKeyPath, _: KeyPath, to: KeyPath + ) +) -> Child where Child: CasePathable { + func sync(_ keyPath: (_: CaseKeyPath, _: KeyPath, to: KeyPath)) { + guard let to = keyPath.to as? WritableKeyPath else { return } + if let value = child[case: keyPath.0] { + parent[keyPath: to] = value[keyPath: keyPath.1] + } + } + + repeat sync(each keyPaths) + + return child +} +