Skip to content
Open
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
14 changes: 14 additions & 0 deletions Sources/AsyncAlgorithms/AsyncAdjacentPairsSequence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,20 @@ public struct AsyncAdjacentPairsSequence<Base: AsyncSequence>: AsyncSequence {
self.base = base
}

@available(AsyncAlgorithms 1.1, *)
mutating public func next(isolation actor: isolated (any Actor)?) async throws(Base.Failure) -> (Base.Element, Base.Element)? {
if previousElement == nil {
previousElement = try await base.next(isolation: actor)
}

guard let previous = previousElement, let next = try await base.next(isolation: actor) else {
return nil
}

previousElement = next
return (previous, next)
}

@inlinable
public mutating func next() async rethrows -> (Base.Element, Base.Element)? {
if previousElement == nil {
Expand Down
26 changes: 26 additions & 0 deletions Tests/AsyncAlgorithmsTests/TestAdjacentPairs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import XCTest
import AsyncAlgorithms
import Observation
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the test does not really need Observations to work - we have other things that dont have this added dependency.


final class TestAdjacentPairs: XCTestCase {
func test_adjacentPairs_produces_tuples_of_adjacent_values_of_original_element() async {
Expand Down Expand Up @@ -95,4 +96,29 @@ final class TestAdjacentPairs: XCTestCase {
task.cancel()
await fulfillment(of: [finished], timeout: 1.0)
}

@available(macOS 26.0, iOS 26.0, tvOS 26.0, watchOS 26.0, visionOS 26.0, *)
@MainActor func test_adjacentPairs_respects_immediate() async {
let testObservable = TestObservable()
let observations = Observations { testObservable.prop }

let iterated = expectation(description: "iterates once")

// with `Task.immediate`, the first element in the adjacent pair should be populated immediately
let t = Task.immediate {
for await (previous, current) in observations.adjacentPairs() {
XCTAssertEqual(previous, 1)
XCTAssertEqual(current, 2)
iterated.fulfill()
}
}
testObservable.prop = 2
await fulfillment(of: [iterated], timeout: 1.0)
t.cancel()
}
}

@available(macOS 26.0, iOS 26.0, tvOS 26.0, watchOS 26.0, visionOS 26.0, *)
@MainActor @Observable private final class TestObservable {
var prop = 1
}
Loading