Skip to content

Commit

Permalink
Add _modify to @perceptible (#91)
Browse files Browse the repository at this point in the history
* Add _modify to @perceptible

* Modernize syntax.

* Added CoW test
  • Loading branch information
mbrandonw authored Jun 26, 2024
1 parent 0fb2e78 commit 3bd7e50
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Sources/Perception/Macros.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
public macro Perceptible() =
#externalMacro(module: "PerceptionMacros", type: "PerceptibleMacro")

@attached(accessor, names: named(init), named(get), named(set))
@attached(accessor, names: named(init), named(get), named(set), named(_modify))
@attached(peer, names: prefixed(_))
public macro PerceptionTracked() =
#externalMacro(module: "PerceptionMacros", type: "PerceptionTrackedMacro")
Expand Down
5 changes: 1 addition & 4 deletions Sources/PerceptionMacros/Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,7 @@ extension VariableDeclSyntax {
}

func accessorsMatching(_ predicate: (TokenKind) -> Bool) -> [AccessorDeclSyntax] {
let patternBindings = bindings.compactMap { binding in
binding
}
let accessors: [AccessorDeclListSyntax.Element] = patternBindings.compactMap { patternBinding in
let accessors: [AccessorDeclListSyntax.Element] = bindings.compactMap { patternBinding in
switch patternBinding.accessorBlock?.accessors {
case .accessors(let accessors):
return accessors
Expand Down
12 changes: 11 additions & 1 deletion Sources/PerceptionMacros/PerceptibleMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,17 @@ public struct PerceptionTrackedMacro: AccessorMacro {
}
"""

return [initAccessor, getAccessor, setAccessor]
let modifyAccessor: AccessorDeclSyntax =
"""
_modify {
access(keyPath: \\.\(identifier))
\(raw: PerceptibleMacro.registrarVariableName).willSet(self, keyPath: \\.\(identifier))
defer { \(raw: PerceptibleMacro.registrarVariableName).didSet(self, keyPath: \\.\(identifier)) }
yield &_\(identifier)
}
"""

return [initAccessor, getAccessor, setAccessor, modifyAccessor]
}
}

Expand Down
8 changes: 8 additions & 0 deletions Tests/PerceptionMacrosTests/PerceptionMacrosTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@
_count = newValue
}
}
_modify {
access(keyPath: \.count)
_$perceptionRegistrar.willSet(self, keyPath: \.count)
defer {
_$perceptionRegistrar.didSet(self, keyPath: \.count)
}
yield &_count
}
}
private let _$perceptionRegistrar = Perception.PerceptionRegistrar()
Expand Down
30 changes: 30 additions & 0 deletions Tests/PerceptionTests/ModifyTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Perception
import XCTest

final class ModifyTests: XCTestCase {
func testCOW() {
let subject = CowTest()
let startId = subject.container.id
XCTAssertEqual(subject.container.id, startId)
subject.container.mutate()
XCTAssertEqual(subject.container.id, startId)
}
}

struct CowContainer {
final class Contents { }
var contents = Contents()
mutating func mutate() {
if !isKnownUniquelyReferenced(&contents) {
contents = Contents()
}
}
var id: ObjectIdentifier {
ObjectIdentifier(contents)
}
}

@Perceptible
final class CowTest {
var container = CowContainer()
}

0 comments on commit 3bd7e50

Please sign in to comment.