effect 3.4.9 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/RcMap/package.json +6 -0
- package/RcRef/package.json +6 -0
- package/dist/cjs/Cause.js +22 -1
- package/dist/cjs/Cause.js.map +1 -1
- package/dist/cjs/Channel.js.map +1 -1
- package/dist/cjs/Config.js.map +1 -1
- package/dist/cjs/Console.js.map +1 -1
- package/dist/cjs/Data.js +3 -1
- package/dist/cjs/Data.js.map +1 -1
- package/dist/cjs/Duration.js +23 -2
- package/dist/cjs/Duration.js.map +1 -1
- package/dist/cjs/Logger.js +11 -1
- package/dist/cjs/Logger.js.map +1 -1
- package/dist/cjs/PubSub.js.map +1 -1
- package/dist/cjs/Random.js +9 -1
- package/dist/cjs/Random.js.map +1 -1
- package/dist/cjs/RcMap.js +52 -0
- package/dist/cjs/RcMap.js.map +1 -0
- package/dist/cjs/RcRef.js +51 -0
- package/dist/cjs/RcRef.js.map +1 -0
- package/dist/cjs/Stream.js +29 -2
- package/dist/cjs/Stream.js.map +1 -1
- package/dist/cjs/index.js +6 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/internal/cause.js +21 -5
- package/dist/cjs/internal/cause.js.map +1 -1
- package/dist/cjs/internal/channel/channelExecutor.js.map +1 -1
- package/dist/cjs/internal/channel.js.map +1 -1
- package/dist/cjs/internal/core-effect.js +0 -5
- package/dist/cjs/internal/core-effect.js.map +1 -1
- package/dist/cjs/internal/core.js +15 -10
- package/dist/cjs/internal/core.js.map +1 -1
- package/dist/cjs/internal/defaultServices.js +1 -1
- package/dist/cjs/internal/defaultServices.js.map +1 -1
- package/dist/cjs/internal/fiberRuntime.js +3 -1
- package/dist/cjs/internal/fiberRuntime.js.map +1 -1
- package/dist/cjs/internal/logger.js +128 -27
- package/dist/cjs/internal/logger.js.map +1 -1
- package/dist/cjs/internal/pubsub.js +216 -36
- package/dist/cjs/internal/pubsub.js.map +1 -1
- package/dist/cjs/internal/random.js +2 -1
- package/dist/cjs/internal/random.js.map +1 -1
- package/dist/cjs/internal/rcMap.js +129 -0
- package/dist/cjs/internal/rcMap.js.map +1 -0
- package/dist/cjs/internal/rcRef.js +122 -0
- package/dist/cjs/internal/rcRef.js.map +1 -0
- package/dist/cjs/internal/stream.js +57 -11
- package/dist/cjs/internal/stream.js.map +1 -1
- package/dist/cjs/internal/version.js +1 -1
- package/dist/dts/Cause.d.ts +40 -1
- package/dist/dts/Cause.d.ts.map +1 -1
- package/dist/dts/Channel.d.ts +3 -3
- package/dist/dts/Channel.d.ts.map +1 -1
- package/dist/dts/Config.d.ts +5 -0
- package/dist/dts/Config.d.ts.map +1 -1
- package/dist/dts/Console.d.ts +2 -4
- package/dist/dts/Console.d.ts.map +1 -1
- package/dist/dts/Duration.d.ts +5 -0
- package/dist/dts/Duration.d.ts.map +1 -1
- package/dist/dts/Logger.d.ts +15 -0
- package/dist/dts/Logger.d.ts.map +1 -1
- package/dist/dts/PubSub.d.ts +15 -4
- package/dist/dts/PubSub.d.ts.map +1 -1
- package/dist/dts/Random.d.ts +8 -0
- package/dist/dts/Random.d.ts.map +1 -1
- package/dist/dts/RcMap.d.ts +93 -0
- package/dist/dts/RcMap.d.ts.map +1 -0
- package/dist/dts/RcRef.d.ts +83 -0
- package/dist/dts/RcRef.d.ts.map +1 -0
- package/dist/dts/Stream.d.ts +64 -26
- package/dist/dts/Stream.d.ts.map +1 -1
- package/dist/dts/index.d.ts +8 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/core-effect.d.ts.map +1 -1
- package/dist/dts/internal/fiberRuntime.d.ts.map +1 -1
- package/dist/dts/internal/logger.d.ts.map +1 -1
- package/dist/dts/internal/random.d.ts +1 -1
- package/dist/dts/internal/random.d.ts.map +1 -1
- package/dist/dts/internal/rcMap.d.ts +2 -0
- package/dist/dts/internal/rcMap.d.ts.map +1 -0
- package/dist/dts/internal/rcRef.d.ts +2 -0
- package/dist/dts/internal/rcRef.d.ts.map +1 -0
- package/dist/dts/internal/stream.d.ts +1 -0
- package/dist/dts/internal/stream.d.ts.map +1 -1
- package/dist/esm/Cause.js +21 -0
- package/dist/esm/Cause.js.map +1 -1
- package/dist/esm/Channel.js.map +1 -1
- package/dist/esm/Config.js.map +1 -1
- package/dist/esm/Console.js.map +1 -1
- package/dist/esm/Data.js +3 -1
- package/dist/esm/Data.js.map +1 -1
- package/dist/esm/Duration.js +20 -0
- package/dist/esm/Duration.js.map +1 -1
- package/dist/esm/Logger.js +10 -0
- package/dist/esm/Logger.js.map +1 -1
- package/dist/esm/PubSub.js.map +1 -1
- package/dist/esm/Random.js +8 -0
- package/dist/esm/Random.js.map +1 -1
- package/dist/esm/RcMap.js +44 -0
- package/dist/esm/RcMap.js.map +1 -0
- package/dist/esm/RcRef.js +43 -0
- package/dist/esm/RcRef.js.map +1 -0
- package/dist/esm/Stream.js +27 -0
- package/dist/esm/Stream.js.map +1 -1
- package/dist/esm/index.js +8 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/cause.js +21 -5
- package/dist/esm/internal/cause.js.map +1 -1
- package/dist/esm/internal/channel/channelExecutor.js.map +1 -1
- package/dist/esm/internal/channel.js.map +1 -1
- package/dist/esm/internal/core-effect.js +0 -5
- package/dist/esm/internal/core-effect.js.map +1 -1
- package/dist/esm/internal/core.js +11 -7
- package/dist/esm/internal/core.js.map +1 -1
- package/dist/esm/internal/defaultServices.js +1 -1
- package/dist/esm/internal/defaultServices.js.map +1 -1
- package/dist/esm/internal/fiberRuntime.js +2 -0
- package/dist/esm/internal/fiberRuntime.js.map +1 -1
- package/dist/esm/internal/logger.js +126 -26
- package/dist/esm/internal/logger.js.map +1 -1
- package/dist/esm/internal/pubsub.js +216 -36
- package/dist/esm/internal/pubsub.js.map +1 -1
- package/dist/esm/internal/random.js +2 -1
- package/dist/esm/internal/random.js.map +1 -1
- package/dist/esm/internal/rcMap.js +120 -0
- package/dist/esm/internal/rcMap.js.map +1 -0
- package/dist/esm/internal/rcRef.js +112 -0
- package/dist/esm/internal/rcRef.js.map +1 -0
- package/dist/esm/internal/stream.js +53 -8
- package/dist/esm/internal/stream.js.map +1 -1
- package/dist/esm/internal/version.js +1 -1
- package/package.json +17 -1
- package/src/Cause.ts +47 -1
- package/src/Channel.ts +3 -3
- package/src/Config.ts +6 -0
- package/src/Console.ts +2 -4
- package/src/Data.ts +1 -1
- package/src/Duration.ts +18 -0
- package/src/Logger.ts +19 -0
- package/src/PubSub.ts +11 -4
- package/src/Random.ts +9 -0
- package/src/RcMap.ts +103 -0
- package/src/RcRef.ts +91 -0
- package/src/Stream.ts +83 -26
- package/src/index.ts +10 -0
- package/src/internal/cause.ts +26 -5
- package/src/internal/channel/channelExecutor.ts +1 -1
- package/src/internal/channel.ts +4 -3
- package/src/internal/core-effect.ts +0 -5
- package/src/internal/core.ts +19 -9
- package/src/internal/defaultServices.ts +1 -1
- package/src/internal/fiberRuntime.ts +6 -0
- package/src/internal/logger.ts +133 -27
- package/src/internal/pubsub.ts +249 -58
- package/src/internal/random.ts +2 -1
- package/src/internal/rcMap.ts +213 -0
- package/src/internal/rcRef.ts +172 -0
- package/src/internal/stream.ts +325 -111
- package/src/internal/version.ts +1 -1
package/src/internal/pubsub.ts
CHANGED
|
@@ -28,6 +28,7 @@ export interface AtomicPubSub<in out A> {
|
|
|
28
28
|
publishAll(elements: Iterable<A>): Chunk.Chunk<A>
|
|
29
29
|
slide(): void
|
|
30
30
|
subscribe(): Subscription<A>
|
|
31
|
+
replayWindow(): ReplayWindow<A>
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/** @internal */
|
|
@@ -73,32 +74,49 @@ const removeSubscribers = <A>(
|
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
/** @internal */
|
|
76
|
-
export const bounded = <A>(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
export const bounded = <A>(
|
|
78
|
+
capacity: number | {
|
|
79
|
+
readonly capacity: number
|
|
80
|
+
readonly replay?: number | undefined
|
|
81
|
+
}
|
|
82
|
+
): Effect.Effect<PubSub.PubSub<A>> =>
|
|
83
|
+
core.suspend(() => {
|
|
84
|
+
const pubsub = makeBoundedPubSub<A>(capacity)
|
|
85
|
+
return makePubSub(pubsub, new BackPressureStrategy())
|
|
86
|
+
})
|
|
81
87
|
|
|
82
88
|
/** @internal */
|
|
83
|
-
export const dropping = <A>(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
export const dropping = <A>(
|
|
90
|
+
capacity: number | {
|
|
91
|
+
readonly capacity: number
|
|
92
|
+
readonly replay?: number | undefined
|
|
93
|
+
}
|
|
94
|
+
): Effect.Effect<PubSub.PubSub<A>> =>
|
|
95
|
+
core.suspend(() => {
|
|
96
|
+
const pubsub = makeBoundedPubSub<A>(capacity)
|
|
97
|
+
return makePubSub(pubsub, new DroppingStrategy())
|
|
98
|
+
})
|
|
88
99
|
|
|
89
100
|
/** @internal */
|
|
90
|
-
export const sliding = <A>(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
101
|
+
export const sliding = <A>(
|
|
102
|
+
capacity: number | {
|
|
103
|
+
readonly capacity: number
|
|
104
|
+
readonly replay?: number | undefined
|
|
105
|
+
}
|
|
106
|
+
): Effect.Effect<PubSub.PubSub<A>> =>
|
|
107
|
+
core.suspend(() => {
|
|
108
|
+
const pubsub = makeBoundedPubSub<A>(capacity)
|
|
109
|
+
return makePubSub(pubsub, new SlidingStrategy())
|
|
110
|
+
})
|
|
95
111
|
|
|
96
112
|
/** @internal */
|
|
97
|
-
export const unbounded = <A>(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
113
|
+
export const unbounded = <A>(options?: {
|
|
114
|
+
readonly replay?: number | undefined
|
|
115
|
+
}): Effect.Effect<PubSub.PubSub<A>> =>
|
|
116
|
+
core.suspend(() => {
|
|
117
|
+
const pubsub = makeUnboundedPubSub<A>(options)
|
|
118
|
+
return makePubSub(pubsub, new DroppingStrategy())
|
|
119
|
+
})
|
|
102
120
|
|
|
103
121
|
/** @internal */
|
|
104
122
|
export const capacity = <A>(self: PubSub.PubSub<A>): number => self.capacity()
|
|
@@ -138,21 +156,28 @@ export const subscribe = <A>(self: PubSub.PubSub<A>): Effect.Effect<Queue.Dequeu
|
|
|
138
156
|
self.subscribe
|
|
139
157
|
|
|
140
158
|
/** @internal */
|
|
141
|
-
const makeBoundedPubSub = <A>(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
159
|
+
const makeBoundedPubSub = <A>(
|
|
160
|
+
capacity: number | {
|
|
161
|
+
readonly capacity: number
|
|
162
|
+
readonly replay?: number | undefined
|
|
163
|
+
}
|
|
164
|
+
): AtomicPubSub<A> => {
|
|
165
|
+
const options = typeof capacity === "number" ? { capacity } : capacity
|
|
166
|
+
ensureCapacity(options.capacity)
|
|
167
|
+
const replayBuffer = options.replay && options.replay > 0 ? new ReplayBuffer<A>(Math.ceil(options.replay)) : undefined
|
|
168
|
+
if (options.capacity === 1) {
|
|
169
|
+
return new BoundedPubSubSingle(replayBuffer)
|
|
170
|
+
} else if (nextPow2(options.capacity) === options.capacity) {
|
|
171
|
+
return new BoundedPubSubPow2(options.capacity, replayBuffer)
|
|
147
172
|
} else {
|
|
148
|
-
return new BoundedPubSubArb(
|
|
173
|
+
return new BoundedPubSubArb(options.capacity, replayBuffer)
|
|
149
174
|
}
|
|
150
175
|
}
|
|
151
176
|
|
|
152
177
|
/** @internal */
|
|
153
|
-
const makeUnboundedPubSub = <A>(
|
|
154
|
-
|
|
155
|
-
}
|
|
178
|
+
const makeUnboundedPubSub = <A>(options?: {
|
|
179
|
+
readonly replay?: number | undefined
|
|
180
|
+
}): AtomicPubSub<A> => new UnboundedPubSub(options?.replay ? new ReplayBuffer(options.replay) : undefined)
|
|
156
181
|
|
|
157
182
|
/** @internal */
|
|
158
183
|
const makeSubscription = <A>(
|
|
@@ -180,17 +205,17 @@ export const unsafeMakeSubscription = <A>(
|
|
|
180
205
|
shutdownHook: Deferred.Deferred<void>,
|
|
181
206
|
shutdownFlag: MutableRef.MutableRef<boolean>,
|
|
182
207
|
strategy: PubSubStrategy<A>
|
|
183
|
-
): Queue.Dequeue<A> =>
|
|
184
|
-
|
|
208
|
+
): Queue.Dequeue<A> =>
|
|
209
|
+
new SubscriptionImpl(
|
|
185
210
|
pubsub,
|
|
186
211
|
subscribers,
|
|
187
212
|
subscription,
|
|
188
213
|
pollers,
|
|
189
214
|
shutdownHook,
|
|
190
215
|
shutdownFlag,
|
|
191
|
-
strategy
|
|
216
|
+
strategy,
|
|
217
|
+
pubsub.replayWindow()
|
|
192
218
|
)
|
|
193
|
-
}
|
|
194
219
|
|
|
195
220
|
/** @internal */
|
|
196
221
|
class BoundedPubSubArb<in out A> implements AtomicPubSub<A> {
|
|
@@ -200,12 +225,13 @@ class BoundedPubSubArb<in out A> implements AtomicPubSub<A> {
|
|
|
200
225
|
subscriberCount = 0
|
|
201
226
|
subscribersIndex = 0
|
|
202
227
|
|
|
203
|
-
readonly capacity: number
|
|
228
|
+
constructor(readonly capacity: number, readonly replayBuffer: ReplayBuffer<A> | undefined) {
|
|
229
|
+
this.array = Array.from({ length: capacity })
|
|
230
|
+
this.subscribers = Array.from({ length: capacity })
|
|
231
|
+
}
|
|
204
232
|
|
|
205
|
-
|
|
206
|
-
this.
|
|
207
|
-
this.subscribers = Array.from({ length: requestedCapacity })
|
|
208
|
-
this.capacity = requestedCapacity
|
|
233
|
+
replayWindow(): ReplayWindow<A> {
|
|
234
|
+
return this.replayBuffer ? new ReplayWindowImpl(this.replayBuffer) : emptyReplayWindow
|
|
209
235
|
}
|
|
210
236
|
|
|
211
237
|
isEmpty(): boolean {
|
|
@@ -230,11 +256,17 @@ class BoundedPubSubArb<in out A> implements AtomicPubSub<A> {
|
|
|
230
256
|
this.subscribers[index] = this.subscriberCount
|
|
231
257
|
this.publisherIndex += 1
|
|
232
258
|
}
|
|
259
|
+
if (this.replayBuffer) {
|
|
260
|
+
this.replayBuffer.offer(value)
|
|
261
|
+
}
|
|
233
262
|
return true
|
|
234
263
|
}
|
|
235
264
|
|
|
236
265
|
publishAll(elements: Iterable<A>): Chunk.Chunk<A> {
|
|
237
266
|
if (this.subscriberCount === 0) {
|
|
267
|
+
if (this.replayBuffer) {
|
|
268
|
+
this.replayBuffer.offerAll(elements)
|
|
269
|
+
}
|
|
238
270
|
return Chunk.empty()
|
|
239
271
|
}
|
|
240
272
|
const chunk = Chunk.fromIterable(elements)
|
|
@@ -253,6 +285,9 @@ class BoundedPubSubArb<in out A> implements AtomicPubSub<A> {
|
|
|
253
285
|
this.array[index] = a
|
|
254
286
|
this.subscribers[index] = this.subscriberCount
|
|
255
287
|
this.publisherIndex += 1
|
|
288
|
+
if (this.replayBuffer) {
|
|
289
|
+
this.replayBuffer.offer(a)
|
|
290
|
+
}
|
|
256
291
|
}
|
|
257
292
|
return Chunk.drop(chunk, iteratorIndex)
|
|
258
293
|
}
|
|
@@ -264,6 +299,9 @@ class BoundedPubSubArb<in out A> implements AtomicPubSub<A> {
|
|
|
264
299
|
this.subscribers[index] = 0
|
|
265
300
|
this.subscribersIndex += 1
|
|
266
301
|
}
|
|
302
|
+
if (this.replayBuffer) {
|
|
303
|
+
this.replayBuffer.slide()
|
|
304
|
+
}
|
|
267
305
|
}
|
|
268
306
|
|
|
269
307
|
subscribe(): Subscription<A> {
|
|
@@ -368,13 +406,14 @@ class BoundedPubSubPow2<in out A> implements AtomicPubSub<A> {
|
|
|
368
406
|
subscriberCount = 0
|
|
369
407
|
subscribersIndex = 0
|
|
370
408
|
|
|
371
|
-
readonly capacity: number
|
|
409
|
+
constructor(readonly capacity: number, readonly replayBuffer: ReplayBuffer<A> | undefined) {
|
|
410
|
+
this.array = Array.from({ length: capacity })
|
|
411
|
+
this.mask = capacity - 1
|
|
412
|
+
this.subscribers = Array.from({ length: capacity })
|
|
413
|
+
}
|
|
372
414
|
|
|
373
|
-
|
|
374
|
-
this.
|
|
375
|
-
this.mask = requestedCapacity - 1
|
|
376
|
-
this.subscribers = Array.from({ length: requestedCapacity })
|
|
377
|
-
this.capacity = requestedCapacity
|
|
415
|
+
replayWindow(): ReplayWindow<A> {
|
|
416
|
+
return this.replayBuffer ? new ReplayWindowImpl(this.replayBuffer) : emptyReplayWindow
|
|
378
417
|
}
|
|
379
418
|
|
|
380
419
|
isEmpty(): boolean {
|
|
@@ -399,11 +438,17 @@ class BoundedPubSubPow2<in out A> implements AtomicPubSub<A> {
|
|
|
399
438
|
this.subscribers[index] = this.subscriberCount
|
|
400
439
|
this.publisherIndex += 1
|
|
401
440
|
}
|
|
441
|
+
if (this.replayBuffer) {
|
|
442
|
+
this.replayBuffer.offer(value)
|
|
443
|
+
}
|
|
402
444
|
return true
|
|
403
445
|
}
|
|
404
446
|
|
|
405
447
|
publishAll(elements: Iterable<A>): Chunk.Chunk<A> {
|
|
406
448
|
if (this.subscriberCount === 0) {
|
|
449
|
+
if (this.replayBuffer) {
|
|
450
|
+
this.replayBuffer.offerAll(elements)
|
|
451
|
+
}
|
|
407
452
|
return Chunk.empty()
|
|
408
453
|
}
|
|
409
454
|
const chunk = Chunk.fromIterable(elements)
|
|
@@ -422,6 +467,9 @@ class BoundedPubSubPow2<in out A> implements AtomicPubSub<A> {
|
|
|
422
467
|
this.array[index] = elem
|
|
423
468
|
this.subscribers[index] = this.subscriberCount
|
|
424
469
|
this.publisherIndex += 1
|
|
470
|
+
if (this.replayBuffer) {
|
|
471
|
+
this.replayBuffer.offer(elem)
|
|
472
|
+
}
|
|
425
473
|
}
|
|
426
474
|
return Chunk.drop(chunk, iteratorIndex)
|
|
427
475
|
}
|
|
@@ -433,6 +481,9 @@ class BoundedPubSubPow2<in out A> implements AtomicPubSub<A> {
|
|
|
433
481
|
this.subscribers[index] = 0
|
|
434
482
|
this.subscribersIndex += 1
|
|
435
483
|
}
|
|
484
|
+
if (this.replayBuffer) {
|
|
485
|
+
this.replayBuffer.slide()
|
|
486
|
+
}
|
|
436
487
|
}
|
|
437
488
|
|
|
438
489
|
subscribe(): Subscription<A> {
|
|
@@ -536,6 +587,11 @@ class BoundedPubSubSingle<in out A> implements AtomicPubSub<A> {
|
|
|
536
587
|
value: A = AbsentValue as unknown as A
|
|
537
588
|
|
|
538
589
|
readonly capacity = 1
|
|
590
|
+
constructor(readonly replayBuffer: ReplayBuffer<A> | undefined) {}
|
|
591
|
+
|
|
592
|
+
replayWindow(): ReplayWindow<A> {
|
|
593
|
+
return this.replayBuffer ? new ReplayWindowImpl(this.replayBuffer) : emptyReplayWindow
|
|
594
|
+
}
|
|
539
595
|
|
|
540
596
|
pipe() {
|
|
541
597
|
return pipeArguments(this, arguments)
|
|
@@ -562,11 +618,17 @@ class BoundedPubSubSingle<in out A> implements AtomicPubSub<A> {
|
|
|
562
618
|
this.subscribers = this.subscriberCount
|
|
563
619
|
this.publisherIndex += 1
|
|
564
620
|
}
|
|
621
|
+
if (this.replayBuffer) {
|
|
622
|
+
this.replayBuffer.offer(value)
|
|
623
|
+
}
|
|
565
624
|
return true
|
|
566
625
|
}
|
|
567
626
|
|
|
568
627
|
publishAll(elements: Iterable<A>): Chunk.Chunk<A> {
|
|
569
628
|
if (this.subscriberCount === 0) {
|
|
629
|
+
if (this.replayBuffer) {
|
|
630
|
+
this.replayBuffer.offerAll(elements)
|
|
631
|
+
}
|
|
570
632
|
return Chunk.empty()
|
|
571
633
|
}
|
|
572
634
|
const chunk = Chunk.fromIterable(elements)
|
|
@@ -585,6 +647,9 @@ class BoundedPubSubSingle<in out A> implements AtomicPubSub<A> {
|
|
|
585
647
|
this.subscribers = 0
|
|
586
648
|
this.value = AbsentValue as unknown as A
|
|
587
649
|
}
|
|
650
|
+
if (this.replayBuffer) {
|
|
651
|
+
this.replayBuffer.slide()
|
|
652
|
+
}
|
|
588
653
|
}
|
|
589
654
|
|
|
590
655
|
subscribe(): Subscription<A> {
|
|
@@ -673,6 +738,11 @@ class UnboundedPubSub<in out A> implements AtomicPubSub<A> {
|
|
|
673
738
|
subscribersIndex = 0
|
|
674
739
|
|
|
675
740
|
readonly capacity = Number.MAX_SAFE_INTEGER
|
|
741
|
+
constructor(readonly replayBuffer: ReplayBuffer<A> | undefined) {}
|
|
742
|
+
|
|
743
|
+
replayWindow(): ReplayWindow<A> {
|
|
744
|
+
return this.replayBuffer ? new ReplayWindowImpl(this.replayBuffer) : emptyReplayWindow
|
|
745
|
+
}
|
|
676
746
|
|
|
677
747
|
isEmpty(): boolean {
|
|
678
748
|
return this.publisherHead === this.publisherTail
|
|
@@ -697,6 +767,9 @@ class UnboundedPubSub<in out A> implements AtomicPubSub<A> {
|
|
|
697
767
|
this.publisherTail = this.publisherTail.next
|
|
698
768
|
this.publisherIndex += 1
|
|
699
769
|
}
|
|
770
|
+
if (this.replayBuffer) {
|
|
771
|
+
this.replayBuffer.offer(value)
|
|
772
|
+
}
|
|
700
773
|
return true
|
|
701
774
|
}
|
|
702
775
|
|
|
@@ -705,6 +778,8 @@ class UnboundedPubSub<in out A> implements AtomicPubSub<A> {
|
|
|
705
778
|
for (const a of elements) {
|
|
706
779
|
this.publish(a)
|
|
707
780
|
}
|
|
781
|
+
} else if (this.replayBuffer) {
|
|
782
|
+
this.replayBuffer.offerAll(elements)
|
|
708
783
|
}
|
|
709
784
|
return Chunk.empty()
|
|
710
785
|
}
|
|
@@ -715,6 +790,9 @@ class UnboundedPubSub<in out A> implements AtomicPubSub<A> {
|
|
|
715
790
|
this.publisherHead.value = AbsentValue
|
|
716
791
|
this.subscribersIndex += 1
|
|
717
792
|
}
|
|
793
|
+
if (this.replayBuffer) {
|
|
794
|
+
this.replayBuffer.slide()
|
|
795
|
+
}
|
|
718
796
|
}
|
|
719
797
|
|
|
720
798
|
subscribe(): Subscription<A> {
|
|
@@ -841,9 +919,9 @@ class SubscriptionImpl<in out A> implements Queue.Dequeue<A> {
|
|
|
841
919
|
readonly pollers: MutableQueue.MutableQueue<Deferred.Deferred<A>>,
|
|
842
920
|
readonly shutdownHook: Deferred.Deferred<void>,
|
|
843
921
|
readonly shutdownFlag: MutableRef.MutableRef<boolean>,
|
|
844
|
-
readonly strategy: PubSubStrategy<A
|
|
845
|
-
|
|
846
|
-
}
|
|
922
|
+
readonly strategy: PubSubStrategy<A>,
|
|
923
|
+
readonly replayWindow: ReplayWindow<A>
|
|
924
|
+
) {}
|
|
847
925
|
|
|
848
926
|
pipe() {
|
|
849
927
|
return pipeArguments(this, arguments)
|
|
@@ -861,7 +939,7 @@ class SubscriptionImpl<in out A> implements Queue.Dequeue<A> {
|
|
|
861
939
|
return core.suspend(() =>
|
|
862
940
|
MutableRef.get(this.shutdownFlag)
|
|
863
941
|
? core.interrupt
|
|
864
|
-
: core.succeed(this.subscription.size())
|
|
942
|
+
: core.succeed(this.subscription.size() + this.replayWindow.remaining)
|
|
865
943
|
)
|
|
866
944
|
}
|
|
867
945
|
|
|
@@ -869,11 +947,15 @@ class SubscriptionImpl<in out A> implements Queue.Dequeue<A> {
|
|
|
869
947
|
if (MutableRef.get(this.shutdownFlag)) {
|
|
870
948
|
return Option.none()
|
|
871
949
|
}
|
|
872
|
-
return Option.some(this.subscription.size())
|
|
950
|
+
return Option.some(this.subscription.size() + this.replayWindow.remaining)
|
|
873
951
|
}
|
|
874
952
|
|
|
875
953
|
get isFull(): Effect.Effect<boolean> {
|
|
876
|
-
return core.
|
|
954
|
+
return core.suspend(() =>
|
|
955
|
+
MutableRef.get(this.shutdownFlag)
|
|
956
|
+
? core.interrupt
|
|
957
|
+
: core.succeed(this.subscription.size() === this.capacity())
|
|
958
|
+
)
|
|
877
959
|
}
|
|
878
960
|
|
|
879
961
|
get isEmpty(): Effect.Effect<boolean> {
|
|
@@ -915,6 +997,10 @@ class SubscriptionImpl<in out A> implements Queue.Dequeue<A> {
|
|
|
915
997
|
if (MutableRef.get(this.shutdownFlag)) {
|
|
916
998
|
return core.interrupt
|
|
917
999
|
}
|
|
1000
|
+
if (this.replayWindow.remaining > 0) {
|
|
1001
|
+
const message = this.replayWindow.take()!
|
|
1002
|
+
return core.succeed(message)
|
|
1003
|
+
}
|
|
918
1004
|
const message = MutableQueue.isEmpty(this.pollers)
|
|
919
1005
|
? this.subscription.poll(MutableQueue.EmptyMutableQueue)
|
|
920
1006
|
: MutableQueue.EmptyMutableQueue
|
|
@@ -950,6 +1036,9 @@ class SubscriptionImpl<in out A> implements Queue.Dequeue<A> {
|
|
|
950
1036
|
? unsafePollAllSubscription(this.subscription)
|
|
951
1037
|
: Chunk.empty()
|
|
952
1038
|
this.strategy.unsafeOnPubSubEmptySpace(this.pubsub, this.subscribers)
|
|
1039
|
+
if (this.replayWindow.remaining > 0) {
|
|
1040
|
+
return core.succeed(Chunk.appendAll(this.replayWindow.takeAll(), as))
|
|
1041
|
+
}
|
|
953
1042
|
return core.succeed(as)
|
|
954
1043
|
})
|
|
955
1044
|
}
|
|
@@ -959,11 +1048,19 @@ class SubscriptionImpl<in out A> implements Queue.Dequeue<A> {
|
|
|
959
1048
|
if (MutableRef.get(this.shutdownFlag)) {
|
|
960
1049
|
return core.interrupt
|
|
961
1050
|
}
|
|
1051
|
+
let replay: Chunk.Chunk<A> | undefined = undefined
|
|
1052
|
+
if (this.replayWindow.remaining >= max) {
|
|
1053
|
+
const as = this.replayWindow.takeN(max)
|
|
1054
|
+
return core.succeed(as)
|
|
1055
|
+
} else if (this.replayWindow.remaining > 0) {
|
|
1056
|
+
replay = this.replayWindow.takeAll()
|
|
1057
|
+
max = max - replay.length
|
|
1058
|
+
}
|
|
962
1059
|
const as = MutableQueue.isEmpty(this.pollers)
|
|
963
1060
|
? unsafePollN(this.subscription, max)
|
|
964
1061
|
: Chunk.empty()
|
|
965
1062
|
this.strategy.unsafeOnPubSubEmptySpace(this.pubsub, this.subscribers)
|
|
966
|
-
return core.succeed(as)
|
|
1063
|
+
return replay ? core.succeed(Chunk.appendAll(replay, as)) : core.succeed(as)
|
|
967
1064
|
})
|
|
968
1065
|
}
|
|
969
1066
|
|
|
@@ -1019,8 +1116,7 @@ class PubSubImpl<in out A> implements PubSub.PubSub<A> {
|
|
|
1019
1116
|
readonly shutdownHook: Deferred.Deferred<void>,
|
|
1020
1117
|
readonly shutdownFlag: MutableRef.MutableRef<boolean>,
|
|
1021
1118
|
readonly strategy: PubSubStrategy<A>
|
|
1022
|
-
) {
|
|
1023
|
-
}
|
|
1119
|
+
) {}
|
|
1024
1120
|
|
|
1025
1121
|
capacity(): number {
|
|
1026
1122
|
return this.pubsub.capacity
|
|
@@ -1075,7 +1171,7 @@ class PubSubImpl<in out A> implements PubSub.PubSub<A> {
|
|
|
1075
1171
|
return core.interrupt
|
|
1076
1172
|
}
|
|
1077
1173
|
|
|
1078
|
-
if (
|
|
1174
|
+
if (this.pubsub.publish(value)) {
|
|
1079
1175
|
this.strategy.unsafeCompleteSubscribers(this.pubsub, this.subscribers)
|
|
1080
1176
|
return core.succeed(true)
|
|
1081
1177
|
}
|
|
@@ -1179,9 +1275,7 @@ export const unsafeMakePubSub = <A>(
|
|
|
1179
1275
|
shutdownHook: Deferred.Deferred<void>,
|
|
1180
1276
|
shutdownFlag: MutableRef.MutableRef<boolean>,
|
|
1181
1277
|
strategy: PubSubStrategy<A>
|
|
1182
|
-
): PubSub.PubSub<A> =>
|
|
1183
|
-
return new PubSubImpl(pubsub, subscribers, scope, shutdownHook, shutdownFlag, strategy)
|
|
1184
|
-
}
|
|
1278
|
+
): PubSub.PubSub<A> => new PubSubImpl(pubsub, subscribers, scope, shutdownHook, shutdownFlag, strategy)
|
|
1185
1279
|
|
|
1186
1280
|
/** @internal */
|
|
1187
1281
|
const ensureCapacity = (capacity: number): void => {
|
|
@@ -1562,3 +1656,100 @@ const unsafeStrategyCompleteSubscribers = <A>(
|
|
|
1562
1656
|
}
|
|
1563
1657
|
}
|
|
1564
1658
|
}
|
|
1659
|
+
|
|
1660
|
+
interface ReplayNode<A> {
|
|
1661
|
+
value: A | AbsentValue
|
|
1662
|
+
next: ReplayNode<A> | null
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
class ReplayBuffer<A> {
|
|
1666
|
+
constructor(readonly capacity: number) {}
|
|
1667
|
+
|
|
1668
|
+
head: ReplayNode<A> = { value: AbsentValue, next: null }
|
|
1669
|
+
tail: ReplayNode<A> = this.head
|
|
1670
|
+
size = 0
|
|
1671
|
+
index = 0
|
|
1672
|
+
|
|
1673
|
+
slide() {
|
|
1674
|
+
this.index++
|
|
1675
|
+
}
|
|
1676
|
+
offer(a: A): void {
|
|
1677
|
+
this.tail.value = a
|
|
1678
|
+
this.tail.next = {
|
|
1679
|
+
value: AbsentValue,
|
|
1680
|
+
next: null
|
|
1681
|
+
}
|
|
1682
|
+
this.tail = this.tail.next
|
|
1683
|
+
if (this.size === this.capacity) {
|
|
1684
|
+
this.head = this.head.next!
|
|
1685
|
+
} else {
|
|
1686
|
+
this.size += 1
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
offerAll(as: Iterable<A>): void {
|
|
1690
|
+
for (const a of as) {
|
|
1691
|
+
this.offer(a)
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
interface ReplayWindow<A> {
|
|
1697
|
+
take(): A | undefined
|
|
1698
|
+
takeN(n: number): Chunk.Chunk<A>
|
|
1699
|
+
takeAll(): Chunk.Chunk<A>
|
|
1700
|
+
readonly remaining: number
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
class ReplayWindowImpl<A> implements ReplayWindow<A> {
|
|
1704
|
+
head: ReplayNode<A>
|
|
1705
|
+
index: number
|
|
1706
|
+
remaining: number
|
|
1707
|
+
constructor(readonly buffer: ReplayBuffer<A>) {
|
|
1708
|
+
this.index = buffer.index
|
|
1709
|
+
this.remaining = buffer.size
|
|
1710
|
+
this.head = buffer.head
|
|
1711
|
+
}
|
|
1712
|
+
fastForward() {
|
|
1713
|
+
while (this.index < this.buffer.index) {
|
|
1714
|
+
this.head = this.head.next!
|
|
1715
|
+
this.index++
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
take(): A | undefined {
|
|
1719
|
+
if (this.remaining === 0) {
|
|
1720
|
+
return undefined
|
|
1721
|
+
} else if (this.index < this.buffer.index) {
|
|
1722
|
+
this.fastForward()
|
|
1723
|
+
}
|
|
1724
|
+
this.remaining--
|
|
1725
|
+
const value = this.head.value
|
|
1726
|
+
this.head = this.head.next!
|
|
1727
|
+
return value as A
|
|
1728
|
+
}
|
|
1729
|
+
takeN(n: number): Chunk.Chunk<A> {
|
|
1730
|
+
if (this.remaining === 0) {
|
|
1731
|
+
return Chunk.empty()
|
|
1732
|
+
} else if (this.index < this.buffer.index) {
|
|
1733
|
+
this.fastForward()
|
|
1734
|
+
}
|
|
1735
|
+
const len = Math.min(n, this.remaining)
|
|
1736
|
+
const items = new Array(len)
|
|
1737
|
+
for (let i = 0; i < len; i++) {
|
|
1738
|
+
const value = this.head.value as A
|
|
1739
|
+
this.head = this.head.next!
|
|
1740
|
+
items[i] = value
|
|
1741
|
+
}
|
|
1742
|
+
this.remaining -= len
|
|
1743
|
+
return Chunk.unsafeFromArray(items)
|
|
1744
|
+
}
|
|
1745
|
+
takeAll(): Chunk.Chunk<A> {
|
|
1746
|
+
return this.takeN(this.remaining)
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
const emptyReplayWindow: ReplayWindow<never> = {
|
|
1751
|
+
remaining: 0,
|
|
1752
|
+
take: () => undefined,
|
|
1753
|
+
takeN: () => Chunk.empty(),
|
|
1754
|
+
takeAll: () => Chunk.empty()
|
|
1755
|
+
}
|
package/src/internal/random.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as Chunk from "../Chunk.js"
|
|
|
2
2
|
import * as Context from "../Context.js"
|
|
3
3
|
import type * as Effect from "../Effect.js"
|
|
4
4
|
import { pipe } from "../Function.js"
|
|
5
|
+
import * as Hash from "../Hash.js"
|
|
5
6
|
import type * as Random from "../Random.js"
|
|
6
7
|
import * as PCGRandom from "../Utils.js"
|
|
7
8
|
import * as core from "./core.js"
|
|
@@ -85,4 +86,4 @@ const swap = <A>(buffer: Array<A>, index1: number, index2: number): Array<A> =>
|
|
|
85
86
|
return buffer
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
export const make = (seed:
|
|
89
|
+
export const make = <A>(seed: A): Random.Random => new RandomImpl(Hash.hash(seed))
|