@fncts/io 0.0.35 → 0.0.36
Sign up to get free protection for your applications and to get access to all the features.
- 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 +1 -1
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
|
};
|