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
13 changes: 13 additions & 0 deletions Sources/OneWay/AsyncSequences/AsyncViewStateSequence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ where State: Sendable & Equatable {
///
/// - Parameter dynamicMember: a key path for the original state.
/// - Returns: A new stream that has a part of the original state.
#if swift(>=6)
public subscript<Property>(
dynamicMember keyPath: KeyPath<State, Property> & Sendable
) -> AsyncMapSequence<AsyncStream<State>, Property> {
let (stream, continuation) = AsyncStream<Element>.makeStream()
continuations.append(continuation)
if let last {
continuation.yield(last)
}
return stream.map { $0[keyPath: keyPath] }
}
#else
public subscript<Property>(
dynamicMember keyPath: KeyPath<State, Property>
) -> AsyncMapSequence<AsyncStream<State>, Property> {
Expand All @@ -73,6 +85,7 @@ where State: Sendable & Equatable {
}
return stream.map { $0[keyPath: keyPath] }
}
#endif
}

extension AsyncViewStateSequence: Sendable where State: Sendable { }
2 changes: 1 addition & 1 deletion Tests/OneWayTests/TestHelper/Publisher+Async.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#if canImport(Combine)
@preconcurrency import Combine

extension Publisher where Failure == Never {
extension Publisher where Failure == Never, Output: Sendable {
public var stream: AsyncStream<Output> {
AsyncStream { continuation in
let cancellable = self.sink { completion in
Expand Down
26 changes: 10 additions & 16 deletions Tests/OneWayTests/ViewStoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,15 @@ final class ViewStoreTests: XCTestCase {
private var sut: ViewStore<TestReducer>!

@MainActor
override func setUp() {
super.setUp()
override func setUp() async throws {
sut = ViewStore(
reducer: TestReducer(),
state: TestReducer.State(count: 0)
)
}

@MainActor
override func tearDown() {
super.tearDown()
override func tearDown() async throws {
sut = nil
}

Expand All @@ -40,17 +38,15 @@ final class ViewStoreTests: XCTestCase {
}
}

#if swift(>=5.10)
@MainActor
func test_sendSeveralActions() async {
sut.send(.increment)
sut.send(.increment)
sut.send(.twice)

nonisolated(unsafe) let sut = sut!
let sut = sut!
await sendableExpectWithMainActor { await sut.state.count == 4 }
}
#endif

@MainActor
func test_triggeredState() async {
Expand Down Expand Up @@ -132,27 +128,26 @@ final class ViewStoreTests: XCTestCase {
XCTAssertEqual(result, [0, 1, 2, 3, 4])
}

#if swift(>=5.10)
@MainActor
func test_asyncViewStateSequenceForMultipleConsumers() async {
let expectation = expectation(description: #function)

nonisolated(unsafe) let sut = sut!
let sut = sut!
let result = TestResult(expectation, expectedCount: 15)
Task { @MainActor in
await withTaskGroup(of: Void.self) { group in
group.addTask { @MainActor in
for await state in sut.states {
group.addTask {
for await state in await sut.states {
await result.insert(state.count)
}
}
group.addTask { @MainActor in
for await count in sut.states.count {
group.addTask {
for await count in await sut.states.count {
await result.insert(count)
}
}
group.addTask { @MainActor in
for await count in sut.states.count {
group.addTask {
for await count in await sut.states.count {
await result.insert(count)
}
}
Expand All @@ -176,7 +171,6 @@ final class ViewStoreTests: XCTestCase {
]
)
}
#endif
}

private struct TestReducer: Reducer {
Expand Down