Skip to content

Commit

Permalink
Added CaseKeyPath support
Browse files Browse the repository at this point in the history
  • Loading branch information
Obbut committed Jan 26, 2024
1 parent 8214bbe commit 4319e31
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 10 deletions.
6 changes: 3 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
72 changes: 65 additions & 7 deletions Sources/Sync/Sync.swift
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
import CasePaths

@attached(accessor)
@attached(peer, names: prefixed(_))
public macro Sync<Parent, Child, each Value>(
_ sync: repeat (_: WritableKeyPath<Child, each Value>, to: WritableKeyPath<Parent, each Value>)
_ sync: repeat (_: KeyPath<Child, each Value>, to: KeyPath<Parent, each Value>)
) = #externalMacro(module: "SyncMacros", type: "SyncMacro")

@attached(accessor)
@attached(peer, names: prefixed(_))
public macro Sync<Parent, Child, each ChildState, each Value>(
_ sync: repeat (
_: CaseKeyPath<Child, each ChildState>, _: KeyPath<each ChildState, each Value>, to: KeyPath<Parent, each Value>
)
) = #externalMacro(module: "SyncMacros", type: "SyncMacro")

// MARK: Support functions - non-optional

public func _syncToChild<Parent, Child, each Value>(
parent: Parent,
child: Child,
_ keyPaths: repeat (
_: WritableKeyPath<Child, each Value>, to: WritableKeyPath<Parent, each Value>
_: KeyPath<Child, each Value>, to: KeyPath<Parent, each Value>
)
) -> Child {
var child = child

func sync<V>(_ keyPath: (_: WritableKeyPath<Child, V>, to: WritableKeyPath<Parent, V>)) {
child[keyPath: keyPath.0] = parent[keyPath: keyPath.to]
func sync<V>(_ keyPath: (_: KeyPath<Child, V>, to: KeyPath<Parent, V>)) {
guard let childKeyPath = keyPath.0 as? WritableKeyPath<Child, V> else { return }
child[keyPath: childKeyPath] = parent[keyPath: keyPath.to]
}

repeat sync(each keyPaths)
Expand All @@ -26,14 +39,59 @@ public func _syncToParent<Parent, Child, each Value>(
parent: inout Parent,
child: Child,
_ keyPaths: repeat (
_: WritableKeyPath<Child, each Value>, to: WritableKeyPath<Parent, each Value>
_: KeyPath<Child, each Value>, to: KeyPath<Parent, each Value>
)
) -> Child {
func sync<V>(_ keyPath: (_: WritableKeyPath<Child, V>, to: WritableKeyPath<Parent, V>)) {
parent[keyPath: keyPath.to] = child[keyPath: keyPath.0]
func sync<V>(_ keyPath: (_: KeyPath<Child, V>, to: KeyPath<Parent, V>)) {
guard let to = keyPath.to as? WritableKeyPath<Parent, V> else { return }
parent[keyPath: to] = child[keyPath: keyPath.0]
}

repeat sync(each keyPaths)

return child
}

// MARK: CaseKeyPath support

public func _syncToChild<Parent, Child, each ChildState, each Value>(
parent: Parent,
child: Child,
_ keyPaths: repeat (
_: CaseKeyPath<Child, each ChildState>, _: KeyPath<each ChildState, each Value>, to: KeyPath<Parent, each Value>
)
) -> Child where Child: CasePathable {
var child = child

func sync<CS, V>(_ keyPath: (_: CaseKeyPath<Child, CS>, _: KeyPath<CS, V>, to: KeyPath<Parent, V>)) {
guard
let valueCaseStateKeyPath = keyPath.1 as? WritableKeyPath<CS, V>,
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, Child, each ChildState, each Value>(
parent: inout Parent,
child: Child,
_ keyPaths: repeat (
_: CaseKeyPath<Child, each ChildState>, _: KeyPath<each ChildState, each Value>, to: KeyPath<Parent, each Value>
)
) -> Child where Child: CasePathable {
func sync<CS, V>(_ keyPath: (_: CaseKeyPath<Child, CS>, _: KeyPath<CS, V>, to: KeyPath<Parent, V>)) {
guard let to = keyPath.to as? WritableKeyPath<Parent, V> else { return }
if let value = child[case: keyPath.0] {
parent[keyPath: to] = value[keyPath: keyPath.1]
}
}

repeat sync(each keyPaths)

return child
}

0 comments on commit 4319e31

Please sign in to comment.