Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,11 @@ for await number in store.states.number {
// Prints "10", "20"
```

If you want to continue receiving the value even when the same value is assigned to the `State`, you can use `@Sensitive`. For explanations of other useful property wrappers(e.g. [@CopyOnWrite](https://swiftpackageindex.com/devyeom/oneway/main/documentation/oneway/copyonwrite), [@Insensitive](https://swiftpackageindex.com/devyeom/oneway/main/documentation/oneway/insensitive)), refer to [here](https://swiftpackageindex.com/devyeom/oneway/main/documentation/oneway/sensitive).
If you want to continue receiving the value even when the same value is assigned to the `State`, you can use `@Triggered`. For explanations of other useful property wrappers(e.g. [@CopyOnWrite](https://swiftpackageindex.com/devyeom/oneway/main/documentation/oneway/copyonwrite), [@Ignored](https://swiftpackageindex.com/devyeom/oneway/main/documentation/oneway/ignored)), refer to [here](https://swiftpackageindex.com/devyeom/oneway/main/documentation/oneway/triggered).

```swift
struct State: Sendable, Equatable {
@Sensitive var number: Int
@Triggered var number: Int
}

// number <- 10, 10, 20 ,20
Expand Down
4 changes: 2 additions & 2 deletions Sources/OneWay/OneWay.docc/OneWay.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ OneWay is released under the MIT license. See LICENSE for details.
### PropertyWrappers

- ``CopyOnWrite``
- ``Insensitive``
- ``Sensitive``
- ``Ignored``
- ``Triggered``

### Articles
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,31 @@
/// useful when the actual value of the `State` changes, but rendering of the `View` is not
/// required.
@propertyWrapper
public struct Insensitive<Value> {
public struct Ignored<Value> {
public var wrappedValue: Value

public init(wrappedValue: Value) {
self.wrappedValue = wrappedValue
}
}

extension Insensitive: CustomStringConvertible {
extension Ignored: CustomStringConvertible {
public var description: String {
String(describing: wrappedValue)
}
}

extension Insensitive: Sendable where Value: Sendable { }
extension Insensitive: Equatable {
public static func == (lhs: Insensitive, rhs: Insensitive) -> Bool {
extension Ignored: Sendable where Value: Sendable { }
extension Ignored: Equatable {
public static func == (lhs: Ignored, rhs: Ignored) -> Bool {
true
}
}
extension Insensitive: Hashable where Value: Hashable {
extension Ignored: Hashable where Value: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(wrappedValue)
}
}

@available(*, deprecated, renamed: "Ignored")
public typealias Insensitive = Ignored
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
/// It is useful in cases where the value hasn't actually changed, but the `View` needs to be
/// rendered again.
@propertyWrapper
public struct Sensitive<Value> where Value: Equatable {
public struct Triggered<Value> where Value: Equatable {
fileprivate struct Storage: Equatable {
var value: Value
var version: UInt8
Expand Down Expand Up @@ -44,24 +44,27 @@ public struct Sensitive<Value> where Value: Equatable {
}
}

extension Sensitive: CustomStringConvertible {
extension Triggered: CustomStringConvertible {
public var description: String {
String(describing: storage.value)
}
}

extension Sensitive: Sendable where Value: Sendable { }
extension Sensitive: Equatable { }
extension Sensitive: Hashable where Value: Hashable {
extension Triggered: Sendable where Value: Sendable { }
extension Triggered: Equatable { }
extension Triggered: Hashable where Value: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(storage)
}
}

extension Sensitive.Storage: Sendable where Value: Sendable { }
extension Sensitive.Storage: Hashable where Value: Hashable {
extension Triggered.Storage: Sendable where Value: Sendable { }
extension Triggered.Storage: Hashable where Value: Hashable {
fileprivate func hash(into hasher: inout Hasher) {
hasher.combine(value)
hasher.combine(version)
}
}

@available(*, deprecated, renamed: "Triggered")
public typealias Sensitive = Triggered
8 changes: 4 additions & 4 deletions Tests/OneWayTests/PropertyWrappersTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ final class PropertyWrappersTests: XCTestCase {
}
}

func test_sensitive() {
func test_triggered() {
struct Storage: Equatable {
@Sensitive var value: Int
@Triggered var value: Int
}

do {
Expand Down Expand Up @@ -83,9 +83,9 @@ final class PropertyWrappersTests: XCTestCase {
}
}

func test_insensitive() {
func test_ignored() {
struct Storage: Equatable {
@Insensitive var value: Int
@Ignored var value: Int
}

do {
Expand Down
56 changes: 28 additions & 28 deletions Tests/OneWayTests/ViewStoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ final class ViewStoreTests: XCTestCase {
await sendableExpect { await sut.state.count == 4 }
}

func test_sensitiveState() async {
func test_triggeredState() async {
actor Result {
var counts: [Int] = []
var sensitiveCounts: [Int] = []
var triggeredCounts: [Int] = []
func appendCount(_ count: Int) {
counts.append(count)
}
func appendSensitiveCount(_ count: Int) {
sensitiveCounts.append(count)
func appendTriggeredCount(_ count: Int) {
triggeredCounts.append(count)
}
}
let result = Result()
Expand All @@ -64,28 +64,28 @@ final class ViewStoreTests: XCTestCase {
}
}
Task { @MainActor in
for await sensitiveCount in sut.states.sensitiveCount {
await result.appendSensitiveCount(sensitiveCount)
for await triggeredCount in sut.states.triggeredCount {
await result.appendTriggeredCount(triggeredCount)
}
}

sut.send(.setSensitiveCount(10))
sut.send(.setSensitiveCount(10))
sut.send(.setSensitiveCount(10))
sut.send(.setTriggeredCount(10))
sut.send(.setTriggeredCount(10))
sut.send(.setTriggeredCount(10))

await sendableExpect { await result.counts == [0, 0, 0, 0] }
await sendableExpect { await result.sensitiveCounts == [0, 10, 10, 10] }
await sendableExpect { await result.triggeredCounts == [0, 10, 10, 10] }
}

func test_insensitiveState() async {
func test_ignoredState() async {
actor Result {
var counts: [Int] = []
var insensitiveCounts: [Int] = []
var ignoredCounts: [Int] = []
func appendCount(_ count: Int) {
counts.append(count)
}
func appendInsensitiveCount(_ count: Int) {
insensitiveCounts.append(count)
func appendIgnoredCount(_ count: Int) {
ignoredCounts.append(count)
}
}
let result = Result()
Expand All @@ -96,18 +96,18 @@ final class ViewStoreTests: XCTestCase {
}
}
Task { @MainActor in
for await insensitiveCount in sut.states.insensitiveCount {
await result.appendInsensitiveCount(insensitiveCount)
for await ignoredCount in sut.states.ignoredCount {
await result.appendIgnoredCount(ignoredCount)
}
}

sut.send(.setInsensitiveCount(10))
sut.send(.setInsensitiveCount(20))
sut.send(.setInsensitiveCount(30))
sut.send(.setIgnoredCount(10))
sut.send(.setIgnoredCount(20))
sut.send(.setIgnoredCount(30))

// only initial value
await sendableExpect { await result.counts == [0] }
await sendableExpect { await result.insensitiveCounts == [0] }
await sendableExpect { await result.ignoredCounts == [0] }
}

func test_asyncViewStateSequence() async {
Expand Down Expand Up @@ -179,14 +179,14 @@ private struct TestReducer: Reducer {
case twice
case concat
case setCount(Int)
case setSensitiveCount(Int)
case setInsensitiveCount(Int)
case setTriggeredCount(Int)
case setIgnoredCount(Int)
}

struct State: Equatable {
var count: Int
@Sensitive var sensitiveCount: Int = 0
@Insensitive var insensitiveCount: Int = 0
@Triggered var triggeredCount: Int = 0
@Ignored var ignoredCount: Int = 0
}

func reduce(state: inout State, action: Action) -> AnyEffect<Action> {
Expand All @@ -213,12 +213,12 @@ private struct TestReducer: Reducer {
state.count = count
return .none

case .setSensitiveCount(let count):
state.sensitiveCount = count
case .setTriggeredCount(let count):
state.triggeredCount = count
return .none

case .setInsensitiveCount(let count):
state.insensitiveCount = count
case .setIgnoredCount(let count):
state.ignoredCount = count
return .none
}
}
Expand Down