Skip to content

Commit bda1f5f

Browse files
committed
Setup task after first call to next
1 parent c88249a commit bda1f5f

File tree

3 files changed

+225
-235
lines changed

3 files changed

+225
-235
lines changed

Sources/AsyncAlgorithms/Debounce/AsyncDebounceSequence.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ extension AsyncDebounceSequence {
7575

7676
fileprivate init(storage: DebounceStorage<Base, C>) {
7777
self.storage = storage
78-
self.storage.iteratorInitialized()
7978
}
8079

8180
deinit {

Sources/AsyncAlgorithms/Debounce/DebounceStateMachine.swift

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ struct DebounceStateMachine<Base: AsyncSequence, C: Clock> {
1414
typealias Element = Base.Element
1515

1616
private enum State {
17-
/// The initial state before a call to `makeAsyncIterator` happened.
17+
/// The initial state before a call to `next` happened.
1818
case initial(base: Base)
1919

2020
/// The state while we are waiting for downstream demand.
@@ -64,24 +64,6 @@ struct DebounceStateMachine<Base: AsyncSequence, C: Clock> {
6464
self.interval = interval
6565
}
6666

67-
/// Actions returned by `iteratorInitialized()`.
68-
enum IteratorInitializedAction {
69-
/// Indicates that a new `Task` should be created that consumes the sequence.
70-
case startTask(Base)
71-
}
72-
73-
mutating func iteratorInitialized() -> IteratorInitializedAction {
74-
switch self.state {
75-
case .initial(let base):
76-
// This is the first iterator being created and we need to create our `Task`
77-
// that is consuming the upstream sequences.
78-
return .startTask(base)
79-
80-
case .waitingForDemand, .demandSignalled, .debouncing, .upstreamFailure, .finished:
81-
fatalError("debounce allows only a single AsyncIterator to be created")
82-
}
83-
}
84-
8567
/// Actions returned by `iteratorDeinitialized()`.
8668
enum IteratorDeinitializedAction {
8769
/// Indicates that the `Task` needs to be cancelled and
@@ -96,8 +78,8 @@ struct DebounceStateMachine<Base: AsyncSequence, C: Clock> {
9678
mutating func iteratorDeinitialized() -> IteratorDeinitializedAction? {
9779
switch self.state {
9880
case .initial:
99-
// An iterator needs to be initialized before it can be deinitialized.
100-
preconditionFailure("Internal inconsistency current state \(self.state) and received iteratorDeinitialized()")
81+
// Nothing to do here. No demand was signalled until now
82+
return .none
10183

10284
case .debouncing, .demandSignalled:
10385
// An iterator was deinitialized while we have a suspended continuation.
@@ -129,16 +111,15 @@ struct DebounceStateMachine<Base: AsyncSequence, C: Clock> {
129111
}
130112
}
131113

132-
mutating func taskStarted(_ task: Task<Void, Never>) {
114+
mutating func taskStarted(_ task: Task<Void, Never>, downstreamContinuation: UnsafeContinuation<Result<Element?, Error>, Never>) {
133115
switch self.state {
134116
case .initial:
135-
// The user called `makeAsyncIterator` and we are starting the `Task`
117+
// The user called `next` and we are starting the `Task`
136118
// to consume the upstream sequence
137-
self.state = .waitingForDemand(
119+
self.state = .demandSignalled(
138120
task: task,
139-
upstreamContinuation: nil,
140121
clockContinuation: nil,
141-
bufferedElement: nil
122+
downstreamContinuation: downstreamContinuation
142123
)
143124

144125
case .debouncing, .demandSignalled, .waitingForDemand, .upstreamFailure, .finished:
@@ -652,6 +633,8 @@ struct DebounceStateMachine<Base: AsyncSequence, C: Clock> {
652633

653634
/// Actions returned by `next()`.
654635
enum NextAction {
636+
/// Indicates that a new `Task` should be created that consumes the sequence.
637+
case startTask(Base)
655638
case resumeUpstreamContinuation(
656639
upstreamContinuation: UnsafeContinuation<Void, Error>?
657640
)
@@ -671,8 +654,10 @@ struct DebounceStateMachine<Base: AsyncSequence, C: Clock> {
671654

672655
mutating func next(for continuation: UnsafeContinuation<Result<Element?, Error>, Never>) -> NextAction {
673656
switch self.state {
674-
case .initial:
675-
preconditionFailure("Internal inconsistency current state \(self.state) and received next()")
657+
case .initial(let base):
658+
// This is the first time we get demand singalled so we have to start the task
659+
// The transition to the next state is done in the taskStarted method
660+
return .startTask(base)
676661

677662
case .demandSignalled, .debouncing:
678663
// We already got demand signalled and have suspended the downstream task

0 commit comments

Comments
 (0)