11
11
12
12
@_implementationOnly import DequeModule
13
13
14
- struct SuspendingBufferStateMachine < Element> {
14
+ struct BufferStateMachine < Base: AsyncSequence > {
15
+ typealias Element = Base . Element
15
16
typealias SuspendedProducer = ( continuation: UnsafeContinuation < Void , Never > , element: Result < Element ? , Error > )
16
17
typealias SuspendedConsumer = UnsafeContinuation < Element ? , Error >
17
18
@@ -22,12 +23,12 @@ struct SuspendingBufferStateMachine<Element> {
22
23
}
23
24
24
25
private var state : State
25
- private let limit : Int
26
+ private let policy : AsyncBufferSequence < Base > . Policy
26
27
27
- init ( limit : Int ) {
28
- assert ( limit > 0 , " The limit should be positive for the buffer operator to be efficient. " )
28
+ init ( policy : AsyncBufferSequence < Base > . Policy ) {
29
+ assert ( policy . isPositiveLimit , " The limit should be positive for the buffer operator to be efficient. " )
29
30
self . state = . buffering( buffer: [ ] , suspendedProducer: nil , suspendedConsumer: nil )
30
- self . limit = limit
31
+ self . policy = policy
31
32
}
32
33
33
34
enum ElementIsProducedAction {
@@ -43,15 +44,37 @@ struct SuspendingBufferStateMachine<Element> {
43
44
case . buffering( var buffer, . none, . none) :
44
45
// we are either idle or the buffer is already in use (no awaiting consumer)
45
46
// we have to stack the new element or suspend the producer if the buffer is full
46
- if buffer. count < limit {
47
- self . state = . modifying
48
- // we can stack
49
- buffer. append ( . success( element) )
50
- self . state = . buffering( buffer: buffer, suspendedProducer: nil , suspendedConsumer: nil )
51
- return . exit
52
- } else {
53
- // we have to suspend the producer
54
- return . suspend
47
+ switch self . policy {
48
+ case . bounded( let limit) :
49
+ if buffer. count < limit {
50
+ self . state = . modifying
51
+ // we can stack
52
+ buffer. append ( . success( element) )
53
+ self . state = . buffering( buffer: buffer, suspendedProducer: nil , suspendedConsumer: nil )
54
+ return . exit
55
+ }
56
+ // we have to suspend the producer
57
+ return . suspend
58
+ case . unbounded:
59
+ self . state = . modifying
60
+ buffer. append ( . success( element) )
61
+ self . state = . buffering( buffer: buffer, suspendedProducer: nil , suspendedConsumer: nil )
62
+ return . exit
63
+ case . bufferingNewest( let limit) :
64
+ self . state = . modifying
65
+ if buffer. count >= limit {
66
+ _ = buffer. popFirst ( )
67
+ }
68
+ buffer. append ( . success( element) )
69
+ self . state = . buffering( buffer: buffer, suspendedProducer: nil , suspendedConsumer: nil )
70
+ return . exit
71
+ case . bufferingOldest( let limit) :
72
+ self . state = . modifying
73
+ if buffer. count < limit {
74
+ buffer. append ( . success( element) )
75
+ }
76
+ self . state = . buffering( buffer: buffer, suspendedProducer: nil , suspendedConsumer: nil )
77
+ return . exit
55
78
}
56
79
57
80
case . buffering( let buffer, . none, . some( let suspendedConsumer) ) :
@@ -85,20 +108,29 @@ struct SuspendingBufferStateMachine<Element> {
85
108
case . buffering( var buffer, . none, . none) :
86
109
// we are either idle or the buffer is already in use (no awaiting consumer)
87
110
// we have to stack the new element or confirm the suspension if the buffer is full
88
- if buffer. count < limit {
89
- self . state = . modifying
90
- // we can stack and resume the producer
91
- buffer. append ( . success( element) )
92
- self . state = . buffering( buffer: buffer, suspendedProducer: nil , suspendedConsumer: nil )
93
- return . resumeProducer
94
- } else {
95
- // we confirm the suspension
96
- self . state = . buffering(
97
- buffer: buffer,
98
- suspendedProducer: SuspendedProducer ( continuation: continuation, element: . success( element) ) ,
99
- suspendedConsumer: nil
100
- )
101
- return . none
111
+ switch self . policy {
112
+ case . bounded( let limit) :
113
+ if buffer. count < limit {
114
+ self . state = . modifying
115
+ // we can stack and resume the producer
116
+ buffer. append ( . success( element) )
117
+ self . state = . buffering( buffer: buffer, suspendedProducer: nil , suspendedConsumer: nil )
118
+ return . resumeProducer
119
+ } else {
120
+ // we confirm the suspension
121
+ self . state = . buffering(
122
+ buffer: buffer,
123
+ suspendedProducer: SuspendedProducer ( continuation: continuation, element: . success( element) ) ,
124
+ suspendedConsumer: nil
125
+ )
126
+ return . none
127
+ }
128
+ case . unbounded:
129
+ preconditionFailure ( " Invalid state. A suspension cannot happen with this policy. " )
130
+ case . bufferingNewest:
131
+ preconditionFailure ( " Invalid state. A suspension cannot happen with this policy. " )
132
+ case . bufferingOldest:
133
+ preconditionFailure ( " Invalid state. A suspension cannot happen with this policy. " )
102
134
}
103
135
104
136
case . buffering( let buffer, . none, . some( let suspendedConsumer) ) :
0 commit comments