@fncts/io 0.0.35 → 0.0.37
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/Fiber/constructors.d.ts +5 -0
- package/Push/api.d.ts +70 -41
- package/Push/definition.d.ts +11 -13
- package/Push/internal.d.ts +7 -11
- package/RefSubject/Atomic.d.ts +8 -11
- package/RefSubject/Synchronized/definition.d.ts +4 -6
- package/RefSubject/api.d.ts +0 -1
- package/RefSubject/definition.d.ts +6 -8
- package/STM/definition.d.ts +17 -0
- package/Sink/api.d.ts +6 -6
- package/Subject/Atomic.d.ts +4 -6
- package/Subject/definition.d.ts +2 -2
- package/_cjs/Fiber/constructors.cjs +10 -2
- package/_cjs/Fiber/constructors.cjs.map +1 -1
- package/_cjs/IO/definition.cjs.map +1 -1
- package/_cjs/Layer/api.cjs.map +1 -1
- package/_cjs/Push/api.cjs +206 -175
- package/_cjs/Push/api.cjs.map +1 -1
- package/_cjs/Push/definition.cjs +12 -13
- package/_cjs/Push/definition.cjs.map +1 -1
- package/_cjs/Push/internal.cjs +37 -29
- package/_cjs/Push/internal.cjs.map +1 -1
- package/_cjs/RefSubject/Atomic.cjs +15 -19
- package/_cjs/RefSubject/Atomic.cjs.map +1 -1
- package/_cjs/RefSubject/Synchronized/definition.cjs +9 -10
- package/_cjs/RefSubject/Synchronized/definition.cjs.map +1 -1
- package/_cjs/RefSubject/api.cjs +5 -6
- package/_cjs/RefSubject/api.cjs.map +1 -1
- package/_cjs/RefSubject/definition.cjs.map +1 -1
- package/_cjs/STM/api.cjs +2 -2
- package/_cjs/STM/api.cjs.map +1 -1
- package/_cjs/STM/definition.cjs.map +1 -1
- package/_cjs/Sink/api.cjs +13 -13
- package/_cjs/Sink/api.cjs.map +1 -1
- package/_cjs/Subject/Atomic.cjs +4 -5
- package/_cjs/Subject/Atomic.cjs.map +1 -1
- package/_mjs/Fiber/constructors.mjs +7 -1
- package/_mjs/Fiber/constructors.mjs.map +1 -1
- package/_mjs/IO/definition.mjs.map +1 -1
- package/_mjs/Layer/api.mjs.map +1 -1
- package/_mjs/Push/api.mjs +194 -173
- package/_mjs/Push/api.mjs.map +1 -1
- package/_mjs/Push/definition.mjs +9 -10
- package/_mjs/Push/definition.mjs.map +1 -1
- package/_mjs/Push/internal.mjs +33 -22
- package/_mjs/Push/internal.mjs.map +1 -1
- package/_mjs/RefSubject/Atomic.mjs +15 -19
- package/_mjs/RefSubject/Atomic.mjs.map +1 -1
- package/_mjs/RefSubject/Synchronized/definition.mjs +9 -10
- package/_mjs/RefSubject/Synchronized/definition.mjs.map +1 -1
- package/_mjs/RefSubject/api.mjs +6 -7
- package/_mjs/RefSubject/api.mjs.map +1 -1
- package/_mjs/RefSubject/definition.mjs.map +1 -1
- package/_mjs/STM/api.mjs +2 -2
- package/_mjs/STM/api.mjs.map +1 -1
- package/_mjs/STM/definition.mjs.map +1 -1
- package/_mjs/Sink/api.mjs +10 -10
- package/_mjs/Sink/api.mjs.map +1 -1
- package/_mjs/Subject/Atomic.mjs +4 -5
- package/_mjs/Subject/Atomic.mjs.map +1 -1
- package/_src/Fiber/constructors.ts +5 -0
- package/_src/IO/definition.ts +0 -1
- package/_src/Layer/api.ts +0 -1
- package/_src/Push/api.ts +270 -335
- package/_src/Push/definition.ts +13 -17
- package/_src/Push/internal.ts +63 -31
- package/_src/RefSubject/Atomic.ts +16 -22
- package/_src/RefSubject/Synchronized/definition.ts +6 -9
- package/_src/RefSubject/api.ts +9 -12
- package/_src/RefSubject/definition.ts +6 -8
- package/_src/STM/api.ts +0 -5
- package/_src/STM/definition.ts +6 -0
- package/_src/Sink/api.ts +9 -9
- package/_src/Subject/Atomic.ts +6 -8
- package/_src/Subject/definition.ts +2 -2
- package/package.json +2 -2
package/_src/Push/api.ts
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
import type { _A, _E, _R } from "@fncts/base/types";
|
2
|
-
|
3
1
|
import { AtomicReference } from "@fncts/base/internal/AtomicReference";
|
2
|
+
import { IO } from "@fncts/io/IO";
|
3
|
+
import { withExhaust, withSwitch, withUnboundedConcurrency } from "@fncts/io/Push/internal";
|
4
4
|
|
5
|
-
import {
|
6
|
-
import { earlyExit, onEarlyExit } from "./internal.js";
|
5
|
+
import { Push, PushTypeId, PushVariance, Sink } from "./definition.js";
|
7
6
|
|
8
7
|
/**
|
9
8
|
* @tsplus pipeable fncts.io.Push as
|
@@ -14,45 +13,44 @@ export function as<B>(b: Lazy<B>) {
|
|
14
13
|
};
|
15
14
|
}
|
16
15
|
|
17
|
-
interface
|
18
|
-
|
19
|
-
|
20
|
-
end: () => void;
|
16
|
+
interface UnsafeSink<E, A> {
|
17
|
+
event: (value: A) => void;
|
18
|
+
error: (cause: Cause<E>) => void;
|
21
19
|
}
|
22
20
|
|
23
21
|
/**
|
24
22
|
* @tsplus static fncts.io.PushOps asyncInterrupt
|
25
23
|
*/
|
26
24
|
export function asyncInterrupt<R, E, A>(
|
27
|
-
make: (emitter:
|
25
|
+
make: (emitter: UnsafeSink<E, A>) => Either<IO<R, never, void>, Push<R, E, A>>,
|
28
26
|
): Push<R, E, A> {
|
29
|
-
return Push<R, E, A>(
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
27
|
+
return Push<R, E, A>(
|
28
|
+
<R1>(sink: Sink<R | R1, E, A>) =>
|
29
|
+
Do((Δ) => {
|
30
|
+
const future = Δ(Future.make<never, void>());
|
31
|
+
const scope = Δ(IO.scope);
|
32
|
+
const runtime = Δ(IO.runtime<R | R1>());
|
33
|
+
const unsafeSink: UnsafeSink<E, A> = {
|
34
|
+
event: (value) => runtime.unsafeRunOrFork(sink.event(value).forkIn(scope)),
|
35
|
+
error: (cause) => runtime.unsafeRunOrFork(sink.error(cause).fulfill(future).forkIn(scope)),
|
36
|
+
};
|
37
|
+
const eitherPush = Δ(IO(make(unsafeSink)));
|
38
|
+
Δ(
|
39
|
+
eitherPush.match(
|
40
|
+
(canceller) => future.await.onInterrupt(canceller),
|
41
|
+
(push) => push.run(sink),
|
42
|
+
),
|
43
|
+
);
|
44
|
+
}).scoped,
|
47
45
|
);
|
48
46
|
}
|
49
47
|
|
50
48
|
/**
|
51
49
|
* @tsplus static fncts.io.PushOps async
|
52
50
|
*/
|
53
|
-
export function async<E, A>(make: (
|
54
|
-
return Push.asyncInterrupt((
|
55
|
-
make(
|
51
|
+
export function async<E, A>(make: (sink: UnsafeSink<E, A>) => void): Push<never, E, A> {
|
52
|
+
return Push.asyncInterrupt((sink) => {
|
53
|
+
make(sink);
|
56
54
|
return Either.left(IO.unit);
|
57
55
|
});
|
58
56
|
}
|
@@ -62,31 +60,26 @@ export function async<E, A>(make: (emitter: UnsafeEmitter<E, A>) => void): Push<
|
|
62
60
|
*/
|
63
61
|
export function combineLatest<A extends ReadonlyArray<Push<any, any, any>>>(
|
64
62
|
streams: [...A],
|
65
|
-
): Push<
|
63
|
+
): Push<Push.EnvironmentOf<A[number]>, Push.ErrorOf<A[number]>, { [K in keyof A]: Push.ValueOf<A[K]> }>;
|
66
64
|
export function combineLatest<R, E, A>(streams: Iterable<Push<R, E, A>>): Push<R, E, ReadonlyArray<A>>;
|
67
65
|
export function combineLatest<R, E, A>(streams: Iterable<Push<R, E, A>>): Push<R, E, ReadonlyArray<A>> {
|
68
66
|
return Push((emitter) =>
|
69
67
|
Do((Δ) => {
|
70
68
|
const size = streams.size;
|
71
69
|
const ref: Array<A> = Δ(IO(Array(size)));
|
72
|
-
const latch = Δ(CountdownLatch(size));
|
73
70
|
const emitIfReady = IO(ref.filter((a) => a != null)).flatMap((as) =>
|
74
|
-
as.length === size ? emitter.
|
71
|
+
as.length === size ? emitter.event(as) : IO.unit,
|
75
72
|
);
|
76
73
|
Δ(
|
77
|
-
IO.
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
latch.countDown,
|
85
|
-
),
|
86
|
-
).forkScoped,
|
74
|
+
IO.foreachConcurrent(streams.zipWithIndex, ([i, stream]) =>
|
75
|
+
stream.run(
|
76
|
+
Sink(
|
77
|
+
(value) => IO((ref[i] = value)) > emitIfReady,
|
78
|
+
(cause) => emitter.error(cause),
|
79
|
+
),
|
80
|
+
),
|
87
81
|
),
|
88
82
|
);
|
89
|
-
Δ(latch.await > emitter.end);
|
90
83
|
}),
|
91
84
|
);
|
92
85
|
}
|
@@ -105,28 +98,7 @@ export function combineLatestWith<A, R1, E1, B, C>(that: Push<R1, E1, B>, f: (a:
|
|
105
98
|
*/
|
106
99
|
export function debounce(duration: Lazy<Duration>) {
|
107
100
|
return <R, E, A>(self: Push<R, E, A>): Push<R, E, A> => {
|
108
|
-
return
|
109
|
-
Do((Δ) => {
|
110
|
-
const ref = Δ(Ref.Synchronized.make<Fiber<never, unknown> | null>(null));
|
111
|
-
const latch = Δ(CountdownLatch(1));
|
112
|
-
Δ(
|
113
|
-
self.run(
|
114
|
-
Emitter(
|
115
|
-
(value) =>
|
116
|
-
ref.updateIO((previous) =>
|
117
|
-
Do((Δ) => {
|
118
|
-
Δ(IO.defer(previous ? previous.interrupt : latch.increment));
|
119
|
-
return Δ(IO.acquireRelease(emitter.emit(value).delay(duration), () => latch.countDown).forkScoped);
|
120
|
-
}),
|
121
|
-
),
|
122
|
-
(cause) => emitter.failCause(cause),
|
123
|
-
latch.countDown,
|
124
|
-
),
|
125
|
-
).forkScoped,
|
126
|
-
);
|
127
|
-
Δ(latch.await > emitter.end);
|
128
|
-
}),
|
129
|
-
);
|
101
|
+
return self.switchMapIO((a) => IO.succeedNow(a).delay(duration));
|
130
102
|
};
|
131
103
|
}
|
132
104
|
|
@@ -137,12 +109,88 @@ export function defer<R, E, A>(self: Lazy<Push<R, E, A>>): Push<R, E, A> {
|
|
137
109
|
return Push((emitter) => IO(self).flatMap((push) => push.run(emitter)));
|
138
110
|
}
|
139
111
|
|
112
|
+
/**
|
113
|
+
* @tsplus pipeable fncts.io.Push exhaustMap
|
114
|
+
*/
|
115
|
+
export function exhaustMap<A, R1, E1, B>(f: (a: A) => Push<R1, E1, B>) {
|
116
|
+
return <R, E>(self: Push<R, E, A>): Push<R | R1, E | E1, B> => {
|
117
|
+
return Push((sink) => withExhaust((fork) => self.run(Sink((a) => fork(f(a).run(sink)), sink.error))));
|
118
|
+
};
|
119
|
+
}
|
120
|
+
|
121
|
+
/**
|
122
|
+
* @tsplus pipeable fncts.io.Push exhaustMapIO
|
123
|
+
*/
|
124
|
+
export function exhaustMapIO<A, R1, E1, B>(f: (a: A) => IO<R1, E1, B>) {
|
125
|
+
return <R, E>(self: Push<R, E, A>): Push<R | R1, E | E1, B> => {
|
126
|
+
return self.exhaustMap((a) => Push.fromIO(f(a)));
|
127
|
+
};
|
128
|
+
}
|
129
|
+
|
130
|
+
/**
|
131
|
+
* @tsplus pipeable fncts.io.Push filterIO
|
132
|
+
*/
|
133
|
+
export function filterIO<A, R1, E1>(predicate: (a: A) => IO<R1, E1, boolean>) {
|
134
|
+
return <R, E>(self: Push<R, E, A>): Push<R | R1, E | E1, A> => {
|
135
|
+
return Push((sink) =>
|
136
|
+
self.run(
|
137
|
+
Sink(
|
138
|
+
(a) =>
|
139
|
+
predicate(a)
|
140
|
+
.flatMap((b) => (b ? sink.event(a) : IO.unit))
|
141
|
+
.catchAllCause(sink.error),
|
142
|
+
sink.error,
|
143
|
+
),
|
144
|
+
),
|
145
|
+
);
|
146
|
+
};
|
147
|
+
}
|
148
|
+
|
149
|
+
/**
|
150
|
+
* @tsplus pipeable fncts.io.Push filterMapIO
|
151
|
+
*/
|
152
|
+
export function filterMapIO<A, R1, E1, B>(f: (a: A) => IO<R1, E1, Maybe<B>>) {
|
153
|
+
return <R, E>(self: Push<R, E, A>): Push<R | R1, E | E1, B> => {
|
154
|
+
return Push((sink) =>
|
155
|
+
self.run(
|
156
|
+
Sink(
|
157
|
+
(a) =>
|
158
|
+
f(a)
|
159
|
+
.flatMap((mb) => mb.match(() => IO.unit, sink.event))
|
160
|
+
.catchAllCause(sink.error),
|
161
|
+
sink.error,
|
162
|
+
),
|
163
|
+
),
|
164
|
+
);
|
165
|
+
};
|
166
|
+
}
|
167
|
+
|
168
|
+
/**
|
169
|
+
* @tsplus pipeable fncts.io.Push filter
|
170
|
+
*/
|
171
|
+
export function filter<A, B extends A>(refinement: Refinement<A, B>): <R, E>(self: Push<R, E, A>) => Push<R, E, B>;
|
172
|
+
export function filter<A>(predicate: Predicate<A>): <R, E>(self: Push<R, E, A>) => Push<R, E, A>;
|
173
|
+
export function filter<A>(predicate: Predicate<A>) {
|
174
|
+
return <R, E>(self: Push<R, E, A>): Push<R, E, A> => {
|
175
|
+
return Push((sink) => self.run(Sink((a) => (predicate(a) ? sink.event(a) : IO.unit), sink.error)));
|
176
|
+
};
|
177
|
+
}
|
178
|
+
|
179
|
+
/**
|
180
|
+
* @tsplus pipeable fncts.io.Push filterMap
|
181
|
+
*/
|
182
|
+
export function filterMap<A, B>(f: (a: A) => Maybe<B>) {
|
183
|
+
return <R, E>(self: Push<R, E, A>): Push<R, E, B> => {
|
184
|
+
return Push((sink) => self.run(Sink((a) => f(a).match(() => IO.unit, sink.event), sink.error)));
|
185
|
+
};
|
186
|
+
}
|
187
|
+
|
140
188
|
/**
|
141
189
|
* @tsplus pipeable fncts.io.Push flatMapConcurrentBounded
|
142
190
|
*/
|
143
191
|
export function flatMapConcurrentBounded<A, R1, E1, B>(f: (a: A) => Push<R1, E1, B>, concurrency: number) {
|
144
192
|
return <R, E>(self: Push<R, E, A>): Push<R | R1, E | E1, B> => {
|
145
|
-
return Push(<R2>(emitter:
|
193
|
+
return Push(<R2>(emitter: Sink<R | R1 | R2, E | E1, B>) =>
|
146
194
|
Do((Δ) => {
|
147
195
|
const semaphore = Δ(Semaphore(concurrency));
|
148
196
|
Δ(self.flatMapConcurrentUnbounded((a) => f(a).transform((io) => semaphore.withPermit(io))).run(emitter));
|
@@ -156,22 +204,7 @@ export function flatMapConcurrentBounded<A, R1, E1, B>(f: (a: A) => Push<R1, E1,
|
|
156
204
|
*/
|
157
205
|
export function flatMapConcurrentUnbounded<A, R1, E1, B>(f: (a: A) => Push<R1, E1, B>) {
|
158
206
|
return <R, E>(self: Push<R, E, A>): Push<R | R1, E | E1, B> => {
|
159
|
-
return Push((
|
160
|
-
Do((Δ) => {
|
161
|
-
const latch = Δ(CountdownLatch(1));
|
162
|
-
Δ(
|
163
|
-
self.run(
|
164
|
-
Emitter(
|
165
|
-
(value) =>
|
166
|
-
latch.increment > f(value).run(Emitter(emitter.emit, emitter.failCause, latch.countDown)).forkScoped,
|
167
|
-
emitter.failCause,
|
168
|
-
latch.countDown,
|
169
|
-
),
|
170
|
-
).forkScoped,
|
171
|
-
);
|
172
|
-
Δ(latch.await > emitter.end);
|
173
|
-
}),
|
174
|
-
);
|
207
|
+
return Push((sink) => withUnboundedConcurrency((fork) => self.run(Sink((a) => fork(f(a).run(sink)), sink.error))));
|
175
208
|
};
|
176
209
|
}
|
177
210
|
|
@@ -211,12 +244,11 @@ export function flatten<R, E, R1, E1, A>(self: Push<R, E, Push<R1, E1, A>>): Pus
|
|
211
244
|
* @tsplus static fncts.io.PushOps fromIO
|
212
245
|
*/
|
213
246
|
export function fromIO<R, E, A>(io: Lazy<IO<R, E, A>>): Push<R, E, A> {
|
214
|
-
return Push(
|
215
|
-
(
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
) > emitter.end,
|
247
|
+
return Push((emitter) =>
|
248
|
+
IO.defer(io).matchCauseIO(
|
249
|
+
(cause) => emitter.error(cause),
|
250
|
+
(value) => emitter.event(value),
|
251
|
+
),
|
220
252
|
);
|
221
253
|
}
|
222
254
|
|
@@ -224,17 +256,20 @@ export function fromIO<R, E, A>(io: Lazy<IO<R, E, A>>): Push<R, E, A> {
|
|
224
256
|
* @tsplus static fncts.io.PushOps fromAsyncIterable
|
225
257
|
*/
|
226
258
|
export function fromAsyncIterable<A>(iterable: AsyncIterable<A>): Push<never, never, A> {
|
227
|
-
return Push((
|
259
|
+
return Push(<R>(sink: Sink<R, never, A>) =>
|
260
|
+
IO.asyncIO<R, never, void>((cb) => IO.defer(fromAsyncIterableLoop(iterable[Symbol.asyncIterator](), sink, cb))),
|
261
|
+
);
|
228
262
|
}
|
229
263
|
|
230
264
|
function fromAsyncIterableLoop<A, R>(
|
231
265
|
iterator: AsyncIterator<A>,
|
232
|
-
|
266
|
+
sink: Sink<R, never, A>,
|
267
|
+
cb: (io: UIO<void>) => void,
|
233
268
|
__tsplusTrace?: string,
|
234
269
|
): IO<R, never, void> {
|
235
270
|
return IO.fromPromiseHalt(iterator.next).matchCauseIO(
|
236
|
-
(cause) =>
|
237
|
-
(result) => (result.done ?
|
271
|
+
(cause) => sink.error(cause),
|
272
|
+
(result) => (result.done ? IO(cb(IO.unit)) : sink.event(result.value) > fromAsyncIterableLoop(iterator, sink, cb)),
|
238
273
|
);
|
239
274
|
}
|
240
275
|
|
@@ -242,13 +277,19 @@ function fromAsyncIterableLoop<A, R>(
|
|
242
277
|
* @tsplus static fncts.io.PushOps fromIterable
|
243
278
|
*/
|
244
279
|
export function fromIterable<A>(iterable: Iterable<A>): Push<never, never, A> {
|
245
|
-
return Push((
|
280
|
+
return Push(<R>(sink: Sink<R, never, A>) =>
|
281
|
+
IO.asyncIO<R, never, void>((cb) => IO.defer(fromIterableLoop(iterable[Symbol.iterator](), sink, cb))),
|
282
|
+
);
|
246
283
|
}
|
247
284
|
|
248
|
-
function fromIterableLoop<A, R>(
|
285
|
+
function fromIterableLoop<A, R>(
|
286
|
+
iterator: Iterator<A>,
|
287
|
+
sink: Sink<R, never, A>,
|
288
|
+
cb: (io: UIO<void>) => void,
|
289
|
+
): IO<R, never, void> {
|
249
290
|
return IO.defer(() => {
|
250
291
|
const value = iterator.next();
|
251
|
-
return value.done ?
|
292
|
+
return value.done ? IO(cb(IO.unit)) : sink.event(value.value) > fromIterableLoop(iterator, sink, cb);
|
252
293
|
});
|
253
294
|
}
|
254
295
|
|
@@ -260,12 +301,11 @@ export function multicast<R, E, A>(self: Push<R, E, A>): Push<R, E, A> {
|
|
260
301
|
}
|
261
302
|
|
262
303
|
interface MulticastObserver<E, A> {
|
263
|
-
readonly
|
304
|
+
readonly sink: Sink<any, E, A>;
|
264
305
|
readonly environment: Environment<any>;
|
265
|
-
readonly future: Future<never, void>;
|
266
306
|
}
|
267
307
|
|
268
|
-
export class Multicast<R, E, A> implements Push<R, E, A>,
|
308
|
+
export class Multicast<R, E, A> implements Push<R, E, A>, Sink<never, E, A> {
|
269
309
|
readonly [PushTypeId]: PushTypeId = PushTypeId;
|
270
310
|
declare [PushVariance]: {
|
271
311
|
readonly _R: (_: never) => R;
|
@@ -276,67 +316,59 @@ export class Multicast<R, E, A> implements Push<R, E, A>, Emitter<never, E, A> {
|
|
276
316
|
protected fiber: Fiber<never, unknown> | undefined;
|
277
317
|
constructor(readonly push: Push<R, E, A>) {}
|
278
318
|
|
279
|
-
run<R1>(
|
319
|
+
run<R1>(sink: Sink<R1, E, A>): IO<R | R1, never, void> {
|
280
320
|
return Do((Δ) => {
|
281
321
|
const environment = Δ(IO.environment<R1>());
|
282
|
-
const future = Δ(Future.make<never, void>());
|
283
322
|
Δ(
|
284
323
|
IO.defer(() => {
|
285
|
-
|
286
|
-
if (this.
|
287
|
-
|
288
|
-
} else {
|
289
|
-
return this.push
|
290
|
-
.run(this)
|
291
|
-
.schedule(Schedule.asap)
|
292
|
-
.forkScoped.tap((fiber) => IO((this.fiber = fiber)));
|
324
|
+
let io: URIO<R, void> = IO.unit;
|
325
|
+
if (this.observers.push({ sink: sink, environment }) === 1) {
|
326
|
+
io = this.push.run(this).forkDaemon.flatMap((fiber) => IO((this.fiber = fiber)));
|
293
327
|
}
|
328
|
+
return io > this.fiber!.await.ensuring(this.removeSink(sink));
|
294
329
|
}),
|
295
330
|
);
|
296
|
-
return Δ(future.await);
|
297
331
|
});
|
298
332
|
}
|
299
333
|
|
300
|
-
|
301
|
-
return IO.defer(IO.foreachDiscard(this.observers.slice(), (observer) => this.
|
302
|
-
}
|
303
|
-
|
304
|
-
failCause(cause: Cause<E>) {
|
305
|
-
return (
|
306
|
-
IO.defer(IO.foreachDiscard(this.observers.slice(), (observer) => this.runFailCause(cause, observer))) >
|
307
|
-
IO.defer(this.cleanup())
|
308
|
-
);
|
334
|
+
event(value: A) {
|
335
|
+
return IO.defer(IO.foreachDiscard(this.observers.slice(), (observer) => this.runValue(value, observer)));
|
309
336
|
}
|
310
337
|
|
311
|
-
|
312
|
-
return (
|
313
|
-
IO.defer(IO.foreachDiscard(this.observers.slice(), (observer) => this.runEnd(observer))) >
|
314
|
-
IO.defer(this.cleanup())
|
315
|
-
);
|
338
|
+
error(cause: Cause<E>) {
|
339
|
+
return IO.defer(IO.foreachDiscard(this.observers.slice(), (observer) => this.runError(cause, observer)));
|
316
340
|
}
|
317
341
|
|
318
|
-
protected
|
319
|
-
return observer.
|
320
|
-
.
|
321
|
-
.
|
322
|
-
.
|
342
|
+
protected runValue(value: A, observer: MulticastObserver<E, A>) {
|
343
|
+
return observer.sink
|
344
|
+
.event(value)
|
345
|
+
.provideEnvironment(observer.environment)
|
346
|
+
.catchAllCause(() => this.removeSink(observer.sink));
|
323
347
|
}
|
324
348
|
|
325
|
-
protected
|
326
|
-
|
327
|
-
|
349
|
+
protected runError(cause: Cause<E>, observer: MulticastObserver<E, A>) {
|
350
|
+
return observer.sink
|
351
|
+
.error(cause)
|
352
|
+
.provideEnvironment(observer.environment)
|
353
|
+
.catchAllCause(() => this.removeSink(observer.sink));
|
328
354
|
}
|
329
355
|
|
330
|
-
protected
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
356
|
+
protected removeSink(sink: Sink<any, E, A>) {
|
357
|
+
return IO.defer(() => {
|
358
|
+
if (this.observers.length === 0) {
|
359
|
+
return IO.unit;
|
360
|
+
}
|
361
|
+
const index = this.observers.findIndex((observer) => observer.sink === sink);
|
362
|
+
if (index > -1) {
|
363
|
+
this.observers.splice(index, 1);
|
364
|
+
if (this.observers.length === 0) {
|
365
|
+
const interrupt = this.fiber!.interrupt;
|
366
|
+
this.fiber = undefined;
|
367
|
+
return interrupt;
|
368
|
+
}
|
369
|
+
}
|
370
|
+
return IO.unit;
|
371
|
+
});
|
340
372
|
}
|
341
373
|
}
|
342
374
|
|
@@ -348,87 +380,26 @@ export function hold<R, E, A>(self: Push<R, E, A>): Push<R, E, A> {
|
|
348
380
|
}
|
349
381
|
|
350
382
|
export class Hold<R, E, A> extends Multicast<R, E, A> {
|
351
|
-
readonly
|
352
|
-
protected pendingEmitters: Array<readonly [Emitter<unknown, E, A>, Array<A>]> = [];
|
353
|
-
protected scheduledFiber: Fiber<any, any> | null = null;
|
383
|
+
readonly current = new AtomicReference(Nothing<A>());
|
354
384
|
|
355
|
-
constructor(
|
385
|
+
constructor(public push: Push<R, E, A>) {
|
356
386
|
super(push);
|
357
387
|
}
|
358
388
|
|
359
|
-
run<R1>(
|
360
|
-
|
361
|
-
return this.scheduleFlush(emitter).flatMap(() => super.run(emitter));
|
362
|
-
}
|
389
|
+
run<R1>(sink: Sink<R1, E, A>): IO<R | R1, never, void> {
|
390
|
+
const current = this.current.get;
|
363
391
|
|
364
|
-
|
365
|
-
|
366
|
-
return emitter.emit(value.value).flatMap(() => super.run(emitter));
|
392
|
+
if (current.isJust()) {
|
393
|
+
return sink.event(current.value) > super.run(sink);
|
367
394
|
}
|
368
395
|
|
369
|
-
return super.run(
|
396
|
+
return super.run(sink);
|
370
397
|
}
|
371
398
|
|
372
|
-
|
399
|
+
event(value: A): IO<never, never, void> {
|
373
400
|
return IO.defer(() => {
|
374
|
-
this.
|
375
|
-
return
|
376
|
-
});
|
377
|
-
}
|
378
|
-
|
379
|
-
failCause(cause: Cause<E>) {
|
380
|
-
return IO.defer(this.flushPending().flatMap(() => super.failCause(cause)));
|
381
|
-
}
|
382
|
-
|
383
|
-
get end() {
|
384
|
-
return IO.defer(this.flushPending().flatMap(() => super.end));
|
385
|
-
}
|
386
|
-
|
387
|
-
protected shouldScheduleFlush() {
|
388
|
-
return this.value.get.isJust() && this.observers.length > 0;
|
389
|
-
}
|
390
|
-
|
391
|
-
protected scheduleFlush<R>(observer: Emitter<R, E, A>) {
|
392
|
-
this.pendingEmitters.push([
|
393
|
-
observer,
|
394
|
-
this.value.get.match(
|
395
|
-
() => [],
|
396
|
-
(a) => [a],
|
397
|
-
),
|
398
|
-
]);
|
399
|
-
|
400
|
-
const interrupt = this.scheduledFiber ? this.scheduledFiber.interruptAsFork(FiberId.none) : IO.unit;
|
401
|
-
this.scheduledFiber = null;
|
402
|
-
|
403
|
-
return (IO.yieldNow > interrupt.flatMap(() => this.flushPending())).forkScoped.tap((fiber) =>
|
404
|
-
IO((this.scheduledFiber = fiber)),
|
405
|
-
);
|
406
|
-
}
|
407
|
-
|
408
|
-
protected flushPending() {
|
409
|
-
if (this.pendingEmitters.length === 0) {
|
410
|
-
return IO.unit;
|
411
|
-
}
|
412
|
-
|
413
|
-
const emitters = this.pendingEmitters;
|
414
|
-
this.pendingEmitters = [];
|
415
|
-
|
416
|
-
return IO.foreachDiscard(emitters, (pendingEmitter) => {
|
417
|
-
return IO.defer(() => {
|
418
|
-
const [emitter, values] = pendingEmitter;
|
419
|
-
const observer = this.observers.find((observer) => observer.emitter === emitter);
|
420
|
-
if (!observer) {
|
421
|
-
return IO.unit;
|
422
|
-
}
|
423
|
-
return IO.foreachDiscard(values, (value) => this.runEvent(value, observer));
|
424
|
-
});
|
425
|
-
});
|
426
|
-
}
|
427
|
-
|
428
|
-
protected addValue(value: A) {
|
429
|
-
this.value.set(Just(value));
|
430
|
-
this.pendingEmitters.forEach(([, values]) => {
|
431
|
-
values.push(value);
|
401
|
+
this.current.set(Just(value));
|
402
|
+
return super.event(value);
|
432
403
|
});
|
433
404
|
}
|
434
405
|
}
|
@@ -449,10 +420,9 @@ export function mapError<E, E1>(f: (e: E) => E1) {
|
|
449
420
|
return <R, A>(self: Push<R, E, A>): Push<R, E1, A> => {
|
450
421
|
return Push((emitter) =>
|
451
422
|
self.run(
|
452
|
-
|
453
|
-
(value) => emitter.
|
454
|
-
(cause) => emitter.
|
455
|
-
emitter.end,
|
423
|
+
Sink(
|
424
|
+
(value) => emitter.event(value),
|
425
|
+
(cause) => emitter.error(cause.map(f)),
|
456
426
|
),
|
457
427
|
),
|
458
428
|
);
|
@@ -466,10 +436,9 @@ export function mapErrorCause<E, E1>(f: (cause: Cause<E>) => Cause<E1>) {
|
|
466
436
|
return <R, A>(self: Push<R, E, A>): Push<R, E1, A> => {
|
467
437
|
return Push((emitter) =>
|
468
438
|
self.run(
|
469
|
-
|
470
|
-
(value) => emitter.
|
471
|
-
(cause) => emitter.
|
472
|
-
emitter.end,
|
439
|
+
Sink(
|
440
|
+
(value) => emitter.event(value),
|
441
|
+
(cause) => emitter.error(f(cause)),
|
473
442
|
),
|
474
443
|
),
|
475
444
|
);
|
@@ -483,14 +452,13 @@ export function mapIO<A, R1, E1, B>(f: (a: A) => IO<R1, E1, B>) {
|
|
483
452
|
return <R, E>(self: Push<R, E, A>): Push<R | R1, E | E1, B> =>
|
484
453
|
Push((emitter) =>
|
485
454
|
self.run(
|
486
|
-
|
455
|
+
Sink(
|
487
456
|
(value) =>
|
488
457
|
f(value).matchCauseIO(
|
489
|
-
(cause) => emitter.
|
490
|
-
(b) => emitter.
|
458
|
+
(cause) => emitter.error(cause),
|
459
|
+
(b) => emitter.event(b),
|
491
460
|
),
|
492
|
-
(cause) => emitter.
|
493
|
-
emitter.end,
|
461
|
+
(cause) => emitter.error(cause),
|
494
462
|
),
|
495
463
|
),
|
496
464
|
);
|
@@ -513,23 +481,10 @@ export function mergeAll<A extends ReadonlyArray<Push<any, any, any>>>(
|
|
513
481
|
): Push<Push.EnvironmentOf<A[number]>, Push.ErrorOf<A[number]>, Push.ValueOf<A[number]>>;
|
514
482
|
export function mergeAll<R, E, A>(streams: Iterable<Push<R, E, A>>): Push<R, E, A>;
|
515
483
|
export function mergeAll<R, E, A>(streams: Iterable<Push<R, E, A>>): Push<R, E, A> {
|
516
|
-
return Push((
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
streams.traverseIOConcurrent(
|
521
|
-
(stream) =>
|
522
|
-
stream.run(
|
523
|
-
Emitter(
|
524
|
-
(value) => emitter.emit(value),
|
525
|
-
(cause) => emitter.failCause(cause),
|
526
|
-
latch.countDown,
|
527
|
-
),
|
528
|
-
).forkScoped,
|
529
|
-
),
|
530
|
-
);
|
531
|
-
Δ(latch.await > emitter.end);
|
532
|
-
}),
|
484
|
+
return Push((sink) =>
|
485
|
+
IO.foreachConcurrentDiscard(streams, (stream) =>
|
486
|
+
stream.run(Sink(sink.event, (cause) => (cause.isInterruptedOnly ? IO.unit : sink.error(cause)))),
|
487
|
+
),
|
533
488
|
);
|
534
489
|
}
|
535
490
|
|
@@ -541,13 +496,14 @@ export function observe<A, R1, E1>(f: (a: A) => IO<R1, E1, void>, __tsplusTrace?
|
|
541
496
|
return Do((Δ) => {
|
542
497
|
const future = Δ(Future.make<E | E1, void>());
|
543
498
|
const fiber = Δ(
|
544
|
-
self
|
545
|
-
|
546
|
-
(
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
499
|
+
self
|
500
|
+
.run(
|
501
|
+
Sink(
|
502
|
+
(a) => f(a).catchAllCause((cause) => future.failCause(cause)),
|
503
|
+
(cause) => future.failCause(cause),
|
504
|
+
),
|
505
|
+
)
|
506
|
+
.flatMap(() => future.succeed(undefined)).forkScoped,
|
551
507
|
);
|
552
508
|
|
553
509
|
Δ(future.await);
|
@@ -573,18 +529,7 @@ export function repeatIOMaybe<R, E, A>(io: IO<R, Maybe<E>, A>, __tsplusTrace?: s
|
|
573
529
|
export function runCollect<R, E, A>(self: Push<R, E, A>): IO<R | Scope, E, Conc<A>> {
|
574
530
|
return IO.defer(() => {
|
575
531
|
const out: Array<A> = [];
|
576
|
-
return
|
577
|
-
(future) =>
|
578
|
-
self.run(
|
579
|
-
Emitter(
|
580
|
-
(value) => IO(out.push(value)),
|
581
|
-
(cause) => future.failCause(cause),
|
582
|
-
future.succeed(undefined),
|
583
|
-
),
|
584
|
-
) >
|
585
|
-
future.await >
|
586
|
-
IO(Conc.fromArray(out)),
|
587
|
-
);
|
532
|
+
return self.observe((a) => IO(out.push(a))).as(Conc.fromArray(out));
|
588
533
|
});
|
589
534
|
}
|
590
535
|
|
@@ -592,28 +537,18 @@ export function runCollect<R, E, A>(self: Push<R, E, A>): IO<R | Scope, E, Conc<
|
|
592
537
|
* @tsplus getter fncts.io.Push runDrain
|
593
538
|
*/
|
594
539
|
export function runDrain<R, E, A>(self: Push<R, E, A>): IO<R | Scope, E, void> {
|
595
|
-
return
|
596
|
-
(future) =>
|
597
|
-
self.run(
|
598
|
-
Emitter(
|
599
|
-
() => IO.unit,
|
600
|
-
(cause) => future.failCause(cause),
|
601
|
-
future.succeed(undefined),
|
602
|
-
),
|
603
|
-
) > future.await,
|
604
|
-
);
|
540
|
+
return self.observe(() => IO.unit);
|
605
541
|
}
|
606
542
|
|
607
543
|
/**
|
608
544
|
* @tsplus static fncts.io.PushOps scoped
|
609
545
|
*/
|
610
546
|
export function scoped<R, E, A>(io: Lazy<IO<R, E, A>>, __tsplusTrace?: string): Push<Exclude<R, Scope>, E, A> {
|
611
|
-
return Push(
|
612
|
-
(
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
) > emitter.end,
|
547
|
+
return Push((emitter) =>
|
548
|
+
IO.defer(io).scoped.matchCauseIO(
|
549
|
+
(cause) => emitter.error(cause),
|
550
|
+
(value) => emitter.event(value),
|
551
|
+
),
|
617
552
|
);
|
618
553
|
}
|
619
554
|
|
@@ -625,34 +560,29 @@ export function succeed<A>(value: Lazy<A>): Push<never, never, A> {
|
|
625
560
|
}
|
626
561
|
|
627
562
|
/**
|
628
|
-
* @tsplus pipeable fncts.io.
|
563
|
+
* @tsplus pipeable fncts.io.Push switchMap
|
629
564
|
*/
|
630
565
|
export function switchMap<A, R1, E1, B>(f: (a: A) => Push<R1, E1, B>) {
|
631
566
|
return <R, E>(self: Push<R, E, A>): Push<R | R1, E | E1, B> => {
|
632
|
-
return Push(
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
),
|
652
|
-
);
|
653
|
-
Δ(latch.await > emitter.end);
|
654
|
-
}),
|
655
|
-
);
|
567
|
+
return Push((sink) => withSwitch((fork) => self.run(Sink((a) => fork(f(a).run(sink)), sink.error))));
|
568
|
+
};
|
569
|
+
}
|
570
|
+
|
571
|
+
/**
|
572
|
+
* @tsplus pipeable fncts.io.Push switchMapIO
|
573
|
+
*/
|
574
|
+
export function switchMapIO<A, R1, E1, B>(f: (a: A) => IO<R1, E1, B>) {
|
575
|
+
return <R, E>(self: Push<R, E, A>): Push<R | R1, E | E1, B> => {
|
576
|
+
return self.switchMap((a) => Push.fromIO(f(a)));
|
577
|
+
};
|
578
|
+
}
|
579
|
+
|
580
|
+
/**
|
581
|
+
* @tsplus pipeable fncts.io.Push tap
|
582
|
+
*/
|
583
|
+
export function tap<A, R1, E1, B>(f: (a: A) => IO<R1, E1, B>) {
|
584
|
+
return <R, E>(self: Push<R, E, A>): Push<R | R1, E | E1, A> => {
|
585
|
+
return Push((sink) => self.run(Sink((a) => f(a).matchCauseIO(sink.error, () => sink.event(a)), sink.error)));
|
656
586
|
};
|
657
587
|
}
|
658
588
|
|
@@ -666,11 +596,11 @@ export function transform<R1 = never>(f: <R, E, A>(io: IO<R, E, A>) => IO<R | R1
|
|
666
596
|
function unfoldLoop<S, A, R1>(
|
667
597
|
s: S,
|
668
598
|
f: (s: S) => Maybe<readonly [A, S]>,
|
669
|
-
emitter:
|
599
|
+
emitter: Sink<R1, never, A>,
|
670
600
|
): IO<R1, never, void> {
|
671
601
|
return f(s).match(
|
672
|
-
() =>
|
673
|
-
([a, s]) => emitter.
|
602
|
+
() => IO.unit,
|
603
|
+
([a, s]) => emitter.event(a) > unfoldLoop(s, f, emitter),
|
674
604
|
);
|
675
605
|
}
|
676
606
|
|
@@ -684,16 +614,16 @@ export function unfold<S, A>(s: S, f: (s: S) => Maybe<readonly [A, S]>): Push<ne
|
|
684
614
|
function unfoldIOLoop<S, R, E, A, R1>(
|
685
615
|
s: S,
|
686
616
|
f: (s: S) => IO<R, E, Maybe<readonly [A, S]>>,
|
687
|
-
emitter:
|
617
|
+
emitter: Sink<R1, E, A>,
|
688
618
|
): IO<R | R1, never, void> {
|
689
619
|
return f(s)
|
690
620
|
.flatMap((result) =>
|
691
621
|
result.match(
|
692
|
-
() =>
|
693
|
-
([a, s]) => emitter.
|
622
|
+
() => IO.unit,
|
623
|
+
([a, s]) => emitter.event(a) > unfoldIOLoop(s, f, emitter),
|
694
624
|
),
|
695
625
|
)
|
696
|
-
.catchAllCause((cause) => emitter.
|
626
|
+
.catchAllCause((cause) => emitter.error(cause));
|
697
627
|
}
|
698
628
|
|
699
629
|
/**
|
@@ -708,18 +638,21 @@ export function unfoldIO<S, R, E, A>(s: S, f: (s: S) => IO<R, E, Maybe<readonly
|
|
708
638
|
*/
|
709
639
|
export function untilFuture<E1, B>(future: Future<E1, B>) {
|
710
640
|
return <R, E, A>(self: Push<R, E, A>): Push<R, E | E1, A> => {
|
711
|
-
return Push((
|
712
|
-
|
713
|
-
const
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
641
|
+
return Push(<R1>(sink: Sink<R1, E | E1, A>) =>
|
642
|
+
IO.asyncIO<R | R1, never, void>((cb) => {
|
643
|
+
const exit = IO(cb(IO.unit));
|
644
|
+
return Do((Δ) => {
|
645
|
+
const streamFiber = Δ(self.run(sink).fork);
|
646
|
+
const futureFiber = Δ(
|
647
|
+
future.await
|
648
|
+
.matchCauseIO(
|
649
|
+
(cause) => sink.error(cause),
|
650
|
+
() => IO.unit,
|
651
|
+
)
|
652
|
+
.zipRight(exit).fork,
|
653
|
+
);
|
654
|
+
Δ(Fiber.joinAll([streamFiber, futureFiber]));
|
655
|
+
});
|
723
656
|
}),
|
724
657
|
);
|
725
658
|
};
|
@@ -730,19 +663,21 @@ export function untilFuture<E1, B>(future: Future<E1, B>) {
|
|
730
663
|
*/
|
731
664
|
export function untilPush<R1, E1, B>(signal: Push<R1, E1, B>) {
|
732
665
|
return <R, E, A>(self: Push<R, E, A>): Push<R | R1, E | E1, A> => {
|
733
|
-
return Push((
|
734
|
-
|
735
|
-
const
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
(
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
666
|
+
return Push(<R2>(sink: Sink<R2, E | E1, A>) =>
|
667
|
+
IO.asyncIO<R | R1 | R2, never, void>((cb) => {
|
668
|
+
const exit = IO(cb(IO.unit));
|
669
|
+
return Do((Δ) => {
|
670
|
+
const signalFiber = Δ(
|
671
|
+
signal.run(
|
672
|
+
Sink(
|
673
|
+
() => exit,
|
674
|
+
(cause) => sink.error(cause),
|
675
|
+
),
|
676
|
+
).fork,
|
677
|
+
);
|
678
|
+
const streamFiber = Δ(self.run(sink).fork);
|
679
|
+
Δ(Fiber.joinAll([signalFiber, streamFiber]));
|
680
|
+
});
|
746
681
|
}),
|
747
682
|
);
|
748
683
|
};
|