@fncts/io 0.0.9 → 0.0.10
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/Channel/api.d.ts +27 -4
- package/Channel/internal/MergeDecision.d.ts +14 -0
- package/STM/api.d.ts +7 -0
- package/Sink/api.d.ts +455 -7
- package/TReentrantLock/api.d.ts +97 -0
- package/TReentrantLock/definition.d.ts +65 -0
- package/TReentrantLock.d.ts +2 -0
- package/_cjs/Cached/api.cjs +1 -1
- package/_cjs/Cached/api.cjs.map +1 -1
- package/_cjs/Channel/api/mapOutIOC.cjs +1 -1
- package/_cjs/Channel/api/mapOutIOC.cjs.map +1 -1
- package/_cjs/Channel/api/mergeAllWith.cjs +2 -2
- package/_cjs/Channel/api/mergeAllWith.cjs.map +1 -1
- package/_cjs/Channel/api/mergeWith.cjs +1 -1
- package/_cjs/Channel/api/mergeWith.cjs.map +1 -1
- package/_cjs/Channel/api.cjs +87 -32
- package/_cjs/Channel/api.cjs.map +1 -1
- package/_cjs/Channel/internal/MergeDecision.cjs +11 -2
- package/_cjs/Channel/internal/MergeDecision.cjs.map +1 -1
- package/_cjs/IO/api/foreachC.cjs +2 -2
- package/_cjs/IO/api/foreachC.cjs.map +1 -1
- package/_cjs/STM/api.cjs +15 -6
- package/_cjs/STM/api.cjs.map +1 -1
- package/_cjs/Sink/api.cjs +1180 -40
- package/_cjs/Sink/api.cjs.map +1 -1
- package/_cjs/Stream/api.cjs +28 -28
- package/_cjs/Stream/api.cjs.map +1 -1
- package/_cjs/TReentrantLock/api.cjs +297 -0
- package/_cjs/TReentrantLock/api.cjs.map +1 -0
- package/_cjs/TReentrantLock/definition.cjs +125 -0
- package/_cjs/TReentrantLock/definition.cjs.map +1 -0
- package/_cjs/TReentrantLock.cjs +32 -0
- package/_cjs/TReentrantLock.cjs.map +1 -0
- package/_cjs/collection/immutable/Conc/filterIO.cjs +35 -0
- package/_cjs/collection/immutable/Conc/filterIO.cjs.map +1 -0
- package/_cjs/collection/immutable/Conc.cjs +13 -0
- package/_cjs/collection/immutable/Conc.cjs.map +1 -1
- package/_mjs/Cached/api.mjs +1 -1
- package/_mjs/Cached/api.mjs.map +1 -1
- package/_mjs/Channel/api/mapOutIOC.mjs +1 -1
- package/_mjs/Channel/api/mapOutIOC.mjs.map +1 -1
- package/_mjs/Channel/api/mergeAllWith.mjs +2 -2
- package/_mjs/Channel/api/mergeAllWith.mjs.map +1 -1
- package/_mjs/Channel/api/mergeWith.mjs +1 -1
- package/_mjs/Channel/api/mergeWith.mjs.map +1 -1
- package/_mjs/Channel/api.mjs +75 -30
- package/_mjs/Channel/api.mjs.map +1 -1
- package/_mjs/Channel/internal/MergeDecision.mjs +7 -0
- package/_mjs/Channel/internal/MergeDecision.mjs.map +1 -1
- package/_mjs/IO/api/foreachC.mjs +2 -2
- package/_mjs/IO/api/foreachC.mjs.map +1 -1
- package/_mjs/STM/api.mjs +13 -6
- package/_mjs/STM/api.mjs.map +1 -1
- package/_mjs/Sink/api.mjs +996 -31
- package/_mjs/Sink/api.mjs.map +1 -1
- package/_mjs/Stream/api.mjs +28 -28
- package/_mjs/Stream/api.mjs.map +1 -1
- package/_mjs/TReentrantLock/api.mjs +243 -0
- package/_mjs/TReentrantLock/api.mjs.map +1 -0
- package/_mjs/TReentrantLock/definition.mjs +102 -0
- package/_mjs/TReentrantLock/definition.mjs.map +1 -0
- package/_mjs/TReentrantLock.mjs +4 -0
- package/_mjs/TReentrantLock.mjs.map +1 -0
- package/_mjs/collection/immutable/Conc/filterIO.mjs +22 -0
- package/_mjs/collection/immutable/Conc/filterIO.mjs.map +1 -0
- package/_mjs/collection/immutable/Conc.mjs +1 -0
- package/_mjs/collection/immutable/Conc.mjs.map +1 -1
- package/_src/Channel/api.ts +98 -11
- package/_src/Channel/internal/MergeDecision.ts +15 -0
- package/_src/IO/api.ts +1 -1
- package/_src/STM/api.ts +9 -0
- package/_src/Sink/api.ts +1350 -19
- package/_src/TFuture/definition.ts +1 -1
- package/_src/TReentrantLock/api.ts +193 -0
- package/_src/TReentrantLock/definition.ts +86 -0
- package/_src/TReentrantLock.ts +4 -0
- package/_src/collection/immutable/Conc/filterIO.ts +16 -0
- package/_src/collection/immutable/Conc.ts +1 -0
- package/collection/immutable/Conc/filterIO.d.ts +7 -0
- package/collection/immutable/Conc.d.ts +1 -0
- package/package.json +3 -3
package/_src/Sink/api.ts
CHANGED
@@ -1,18 +1,214 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
import { AtomicReference } from "@fncts/base/internal/AtomicReference";
|
2
|
+
|
3
|
+
import { MergeDecision } from "../Channel/internal/MergeDecision.js";
|
4
|
+
|
5
|
+
/**
|
6
|
+
* @tsplus fluent fncts.io.Sink apFirst
|
7
|
+
*/
|
8
|
+
export function apFirst<R, E, In, L, Z, R1, E1, In1 extends In, L1 extends L, Z1>(
|
9
|
+
self: Sink<R, E, In, L, Z>,
|
10
|
+
that: Lazy<Sink<R1, E1, In1, L1, Z1>>,
|
11
|
+
): Sink<R & R1, E | E1, In & In1, L | L1, Z> {
|
12
|
+
return self.zipWith(that, (z, _) => z);
|
13
|
+
}
|
14
|
+
|
15
|
+
/**
|
16
|
+
* @tsplus fluent fncts.io.Sink apFirstC
|
17
|
+
*/
|
18
|
+
export function apFirstC<R, E, In, L, Z, R1, E1, In1 extends In, L1 extends L, Z1>(
|
19
|
+
self: Sink<R, E, In, L, Z>,
|
20
|
+
that: Lazy<Sink<R1, E1, In1, L1, Z1>>,
|
21
|
+
): Sink<R & R1, E | E1, In & In1, L | L1, Z> {
|
22
|
+
return self.zipWithC(that, (z, _) => z);
|
23
|
+
}
|
24
|
+
|
25
|
+
/**
|
26
|
+
* @tsplus fluent fncts.io.Sink apSecond
|
27
|
+
*/
|
28
|
+
export function apSecond<R, E, In, L, Z, R1, E1, In1 extends In, L1 extends L, Z1>(
|
29
|
+
self: Sink<R, E, In, L, Z>,
|
30
|
+
that: Lazy<Sink<R1, E1, In1, L1, Z1>>,
|
31
|
+
): Sink<R & R1, E | E1, In & In1, L | L1, Z1> {
|
32
|
+
return self.zipWith(that, (_, z1) => z1);
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* @tsplus fluent fncts.io.Sink apSecondC
|
37
|
+
*/
|
38
|
+
export function apSecondC<R, E, In, L, Z, R1, E1, In1 extends In, L1 extends L, Z1>(
|
39
|
+
self: Sink<R, E, In, L, Z>,
|
40
|
+
that: Lazy<Sink<R1, E1, In1, L1, Z1>>,
|
41
|
+
): Sink<R & R1, E | E1, In & In1, L | L1, Z1> {
|
42
|
+
return self.zipWithC(that, (_, z1) => z1);
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* @tsplus fluent fncts.io.Sink as
|
47
|
+
*/
|
48
|
+
export function as<R, E, In, L, Z, Z1>(self: Sink<R, E, In, L, Z>, z: Lazy<Z1>): Sink<R, E, In, L, Z1> {
|
49
|
+
return self.map(() => z());
|
50
|
+
}
|
51
|
+
|
52
|
+
/**
|
53
|
+
* @tsplus fluent fncts.io.Sink collectAll
|
54
|
+
*/
|
55
|
+
export function collectAll<R, E, In extends L, L, Z>(
|
56
|
+
self: Sink<R, E, In, L, Z>,
|
57
|
+
__tsplusTrace?: string,
|
58
|
+
): Sink<R, E, In, L, Conc<Z>> {
|
59
|
+
return self.collectAllWhileWith(
|
60
|
+
Conc.empty<Z>(),
|
61
|
+
() => true,
|
62
|
+
(s, z) => s.append(z),
|
6
63
|
);
|
7
64
|
}
|
8
65
|
|
9
66
|
/**
|
10
|
-
*
|
11
|
-
|
12
|
-
|
67
|
+
* @tsplus fluent fncts.io.Sink collectAllWhileWith
|
68
|
+
*/
|
69
|
+
export function collectAllWhileWith<R, E, In extends L, L, Z, S>(
|
70
|
+
self: Sink<R, E, In, L, Z>,
|
71
|
+
z: Lazy<S>,
|
72
|
+
p: Predicate<Z>,
|
73
|
+
f: (s: S, z: Z) => S,
|
74
|
+
__tsplusTrace?: string,
|
75
|
+
): Sink<R, E, In, L, S> {
|
76
|
+
return new Sink(
|
77
|
+
Channel.fromIO(Ref.make<Conc<In>>(Conc.empty()).zip(Ref.make(false))).flatMap(([leftoversRef, upstreamDoneRef]) => {
|
78
|
+
const upstreamMarker: Channel<unknown, never, Conc<In>, unknown, never, Conc<In>, unknown> = Channel.readWith(
|
79
|
+
(inp) => Channel.writeNow(inp) > upstreamMarker,
|
80
|
+
Channel.failNow,
|
81
|
+
(x) => Channel.fromIO(upstreamDoneRef.set(true)).as(x),
|
82
|
+
);
|
83
|
+
|
84
|
+
function loop(currentResult: S): Channel<R, never, Conc<In>, unknown, E, Conc<L>, S> {
|
85
|
+
return self.channel.collectElements.matchChannel(Channel.failNow, ([leftovers, doneValue]) => {
|
86
|
+
if (p(doneValue)) {
|
87
|
+
return (
|
88
|
+
Channel.fromIO(leftoversRef.set(leftovers.flatten as Conc<In>)) >
|
89
|
+
Channel.fromIO(upstreamDoneRef.get).flatMap((upstreamDone) => {
|
90
|
+
const accumulatedResult = f(currentResult, doneValue);
|
91
|
+
if (upstreamDone) return Channel.writeNow(leftovers.flatten).as(accumulatedResult);
|
92
|
+
else return loop(accumulatedResult);
|
93
|
+
})
|
94
|
+
);
|
95
|
+
} else {
|
96
|
+
return Channel.writeNow(leftovers.flatten).as(currentResult);
|
97
|
+
}
|
98
|
+
});
|
99
|
+
}
|
100
|
+
|
101
|
+
return upstreamMarker.pipeTo(Channel.bufferChunk(leftoversRef)).pipeTo(loop(z()));
|
102
|
+
}),
|
103
|
+
);
|
104
|
+
}
|
105
|
+
|
106
|
+
/**
|
107
|
+
* @tsplus getter fncts.io.Sink collectLeftover
|
108
|
+
*/
|
109
|
+
export function collectLeftover<R, E, In, L, Z>(
|
110
|
+
self: Sink<R, E, In, L, Z>,
|
111
|
+
__tsplusTrace?: string,
|
112
|
+
): Sink<R, E, In, never, readonly [Z, Conc<L>]> {
|
113
|
+
return new Sink(self.channel.collectElements.map(([chunks, z]) => [z, chunks.flatten]));
|
114
|
+
}
|
115
|
+
|
116
|
+
/**
|
117
|
+
* @tsplus fluent fncts.io.Sink contramap
|
118
|
+
*/
|
119
|
+
export function contramap<R, E, In, L, Z, In1>(self: Sink<R, E, In, L, Z>, f: (inp: In1) => In): Sink<R, E, In1, L, Z> {
|
120
|
+
return self.contramapChunks((chunk) => chunk.map(f));
|
121
|
+
}
|
122
|
+
|
123
|
+
/**
|
124
|
+
* @tsplus fluent fncts.io.Sink contramapChunks
|
125
|
+
*/
|
126
|
+
export function contramapChunks<R, E, In, L, Z, In1>(
|
127
|
+
self: Sink<R, E, In, L, Z>,
|
128
|
+
f: (chunk: Conc<In1>) => Conc<In>,
|
129
|
+
): Sink<R, E, In1, L, Z> {
|
130
|
+
const loop: Channel<R, never, Conc<In1>, unknown, never, Conc<In>, unknown> = Channel.readWith(
|
131
|
+
(chunk) => Channel.writeNow(f(chunk)) > loop,
|
132
|
+
Channel.failNow,
|
133
|
+
Channel.succeedNow,
|
134
|
+
);
|
135
|
+
return new Sink(loop >>> self.channel);
|
136
|
+
}
|
137
|
+
|
138
|
+
/**
|
139
|
+
* @tsplus fluent fncts.io.Sink contramapChunksIO
|
140
|
+
*/
|
141
|
+
export function contramapChunksIO<R, E, In, L, Z, R1, E1, In1>(
|
142
|
+
self: Sink<R, E, In, L, Z>,
|
143
|
+
f: (chunk: Conc<In1>) => IO<R1, E1, Conc<In>>,
|
144
|
+
): Sink<R & R1, E | E1, In1, L, Z> {
|
145
|
+
const loop: Channel<R & R1, never, Conc<In1>, unknown, E | E1, Conc<In>, unknown> = Channel.readWith(
|
146
|
+
(chunk) => Channel.fromIO(f(chunk)).flatMap(Channel.writeNow) > loop,
|
147
|
+
Channel.failNow,
|
148
|
+
Channel.succeedNow,
|
149
|
+
);
|
150
|
+
return new Sink(loop.pipeToOrFail(self.channel));
|
151
|
+
}
|
152
|
+
|
153
|
+
/**
|
154
|
+
* @tsplus fluent fncts.io.Sink contramapIO
|
155
|
+
*/
|
156
|
+
export function contramapIO<R, E, In, L, Z, R1, E1, In1>(
|
157
|
+
self: Sink<R, E, In, L, Z>,
|
158
|
+
f: (inp: In1) => IO<R1, E1, In>,
|
159
|
+
): Sink<R & R1, E | E1, In1, L, Z> {
|
160
|
+
return self.contramapChunksIO((chunk) => chunk.mapIO(f));
|
161
|
+
}
|
162
|
+
|
163
|
+
/**
|
164
|
+
* @tsplus fluent fncts.io.Sink dimap
|
13
165
|
*/
|
14
|
-
export function
|
15
|
-
|
166
|
+
export function dimap<R, E, In, L, Z, In1, Z1>(
|
167
|
+
self: Sink<R, E, In, L, Z>,
|
168
|
+
f: (inp: In1) => In,
|
169
|
+
g: (z: Z) => Z1,
|
170
|
+
): Sink<R, E, In1, L, Z1> {
|
171
|
+
return self.contramap(f).map(g);
|
172
|
+
}
|
173
|
+
|
174
|
+
/**
|
175
|
+
* @tsplus fluent fncts.io.Sink dimapChunks
|
176
|
+
*/
|
177
|
+
export function dimapChunks<R, E, In, L, Z, In1, Z1>(
|
178
|
+
self: Sink<R, E, In, L, Z>,
|
179
|
+
f: (chunk: Conc<In1>) => Conc<In>,
|
180
|
+
g: (z: Z) => Z1,
|
181
|
+
): Sink<R, E, In1, L, Z1> {
|
182
|
+
return self.contramapChunks(f).map(g);
|
183
|
+
}
|
184
|
+
|
185
|
+
/**
|
186
|
+
* @tsplus fluent fncts.io.Sink dimapChunksIO
|
187
|
+
*/
|
188
|
+
export function dimapChunksIO<R, E, In, L, Z, R1, E1, In1, R2, E2, Z1>(
|
189
|
+
self: Sink<R, E, In, L, Z>,
|
190
|
+
f: (chunk: Conc<In1>) => IO<R1, E1, Conc<In>>,
|
191
|
+
g: (z: Z) => IO<R2, E2, Z1>,
|
192
|
+
): Sink<R & R1 & R2, E | E1 | E2, In1, L, Z1> {
|
193
|
+
return self.contramapChunksIO(f).mapIO(g);
|
194
|
+
}
|
195
|
+
|
196
|
+
/**
|
197
|
+
* @tsplus fluent fncts.io.Sink dimapIO
|
198
|
+
*/
|
199
|
+
export function dimapIO<R, E, In, L, Z, R1, E1, In1, R2, E2, Z1>(
|
200
|
+
self: Sink<R, E, In, L, Z>,
|
201
|
+
f: (inp: In1) => IO<R1, E1, In>,
|
202
|
+
g: (z: Z) => IO<R2, E2, Z1>,
|
203
|
+
): Sink<R & R1 & R2, E | E1 | E2, In1, L, Z1> {
|
204
|
+
return self.contramapIO(f).mapIO(g);
|
205
|
+
}
|
206
|
+
|
207
|
+
/**
|
208
|
+
* @tsplus static fncts.io.SinkOps defer
|
209
|
+
*/
|
210
|
+
export function defer<R, E, In, L, Z>(sink: Lazy<Sink<R, E, In, L, Z>>): Sink<R, E, In, L, Z> {
|
211
|
+
return new Sink(Channel.defer(sink().channel));
|
16
212
|
}
|
17
213
|
|
18
214
|
const drainLoop: Channel<unknown, never, Conc<unknown>, unknown, never, Conc<never>, void> = Channel.readWithCause(
|
@@ -48,15 +244,361 @@ export function dropWhile<Err, In>(predicate: Predicate<In>): Sink<unknown, neve
|
|
48
244
|
return new Sink(loop);
|
49
245
|
}
|
50
246
|
|
247
|
+
/**
|
248
|
+
* @tsplus static fncts.io.SinkOps environment
|
249
|
+
*/
|
250
|
+
export function environment<R>(__tsplusTrace?: string): Sink<R, never, unknown, never, Environment<R>> {
|
251
|
+
return Sink.fromIO(IO.environment<R>());
|
252
|
+
}
|
253
|
+
|
254
|
+
/**
|
255
|
+
* @tsplus static fncts.io.SinkOps environmentWith
|
256
|
+
*/
|
257
|
+
export function environmentWith<R, Z>(
|
258
|
+
f: (r: Environment<R>) => Z,
|
259
|
+
__tsplusTrace?: string,
|
260
|
+
): Sink<R, never, unknown, never, Z> {
|
261
|
+
return Sink.fromIO(IO.environmentWith(f));
|
262
|
+
}
|
263
|
+
|
264
|
+
/**
|
265
|
+
* @tsplus static fncts.io.SinkOps environmentWithIO
|
266
|
+
*/
|
267
|
+
export function environmentWithIO<R, R1, E, Z>(
|
268
|
+
f: (r: Environment<R>) => IO<R1, E, Z>,
|
269
|
+
__tsplusTrace?: string,
|
270
|
+
): Sink<R & R1, E, unknown, never, Z> {
|
271
|
+
return Sink.fromIO(IO.environmentWithIO(f));
|
272
|
+
}
|
273
|
+
|
274
|
+
/**
|
275
|
+
* @tsplus static fncts.io.SinkOps environmentWithSink
|
276
|
+
*/
|
277
|
+
export function environmentWithSink<R, R1, E, In, L, Z>(
|
278
|
+
f: (r: Environment<R>) => Sink<R1, E, In, L, Z>,
|
279
|
+
__tsplusTrace?: string,
|
280
|
+
): Sink<R & R1, E, In, L, Z> {
|
281
|
+
return new Sink(Channel.unwrap(IO.environmentWith(f.compose((s) => s.channel))));
|
282
|
+
}
|
283
|
+
|
284
|
+
/**
|
285
|
+
* @tsplus static fncts.io.SinkOps fail
|
286
|
+
*/
|
287
|
+
export function fail<E>(e: Lazy<E>): Sink<unknown, E, unknown, never, never> {
|
288
|
+
return new Sink(Channel.fail(e));
|
289
|
+
}
|
290
|
+
|
291
|
+
/**
|
292
|
+
* @tsplus static fncts.io.SinkOps failCause
|
293
|
+
*/
|
294
|
+
export function failCause<E>(cause: Lazy<Cause<E>>, __tsplusTrace?: string): Sink<unknown, E, unknown, never, never> {
|
295
|
+
return new Sink(Channel.failCause(cause));
|
296
|
+
}
|
297
|
+
|
298
|
+
/**
|
299
|
+
* @tsplus static fncts.io.SinkOps failCauseNow
|
300
|
+
*/
|
301
|
+
export function failCauseNow<E>(cause: Cause<E>, __tsplusTrace?: string): Sink<unknown, E, unknown, never, never> {
|
302
|
+
return new Sink(Channel.failCauseNow(cause));
|
303
|
+
}
|
304
|
+
|
305
|
+
/**
|
306
|
+
* @tsplus static fncts.io.SinkOps failNow
|
307
|
+
*/
|
308
|
+
export function failNow<E>(e: E, __tsplusTrace?: string): Sink<unknown, E, unknown, never, never> {
|
309
|
+
return new Sink(Channel.failNow(e));
|
310
|
+
}
|
311
|
+
|
312
|
+
/**
|
313
|
+
* @tsplus static fncts.io.SinkOps filterInput
|
314
|
+
*/
|
315
|
+
export function filterInput<R, E, In, L, Z>(
|
316
|
+
self: Sink<R, E, In, L, Z>,
|
317
|
+
p: Predicate<In>,
|
318
|
+
__tsplusTrace?: string,
|
319
|
+
): Sink<R, E, In, L, Z> {
|
320
|
+
return self.contramapChunks((chunk) => chunk.filter(p));
|
321
|
+
}
|
322
|
+
|
323
|
+
/**
|
324
|
+
* @tsplus static fncts.io.SinkOps filterInputIO
|
325
|
+
*/
|
326
|
+
export function filterInputIO<R, E, In, L, Z, R1, E1>(
|
327
|
+
self: Sink<R, E, In, L, Z>,
|
328
|
+
p: (inp: In) => IO<R1, E1, boolean>,
|
329
|
+
__tsplusTrace?: string,
|
330
|
+
): Sink<R & R1, E | E1, In, L, Z> {
|
331
|
+
return self.contramapChunksIO((chunk) => chunk.filterIO(p));
|
332
|
+
}
|
333
|
+
|
334
|
+
/**
|
335
|
+
* @tsplus fluent fncts.io.Sink findIO
|
336
|
+
*/
|
337
|
+
export function findIO<R, E, In extends L, L, Z, R1, E1>(
|
338
|
+
self: Sink<R, E, In, L, Z>,
|
339
|
+
f: (z: Z) => IO<R1, E1, boolean>,
|
340
|
+
__tsplusTrace?: string,
|
341
|
+
): Sink<R & R1, E | E1, In, L, Maybe<Z>> {
|
342
|
+
return new Sink(
|
343
|
+
Channel.fromIO(Ref.make(Conc.empty<In>()).zip(Ref.make(false))).flatMap(([leftoversRef, upstreamDoneRef]) => {
|
344
|
+
const upstreamMarker: Channel<unknown, never, Conc<In>, unknown, never, Conc<In>, unknown> = Channel.readWith(
|
345
|
+
(inp) => Channel.writeNow(inp) > upstreamMarker,
|
346
|
+
Channel.failNow,
|
347
|
+
(x) => Channel.fromIO(upstreamDoneRef.set(true)).as(x),
|
348
|
+
);
|
349
|
+
|
350
|
+
const loop: Channel<
|
351
|
+
R & R1,
|
352
|
+
never,
|
353
|
+
Conc<In>,
|
354
|
+
unknown,
|
355
|
+
E | E1,
|
356
|
+
Conc<L>,
|
357
|
+
Maybe<Z>
|
358
|
+
> = self.channel.collectElements.matchChannel(Channel.failNow, ([leftovers, doneValue]) =>
|
359
|
+
Channel.fromIO(f(doneValue)).flatMap(
|
360
|
+
(satisfied) =>
|
361
|
+
Channel.fromIO(leftoversRef.set(leftovers.flatten as Conc<In>)) >
|
362
|
+
Channel.fromIO(upstreamDoneRef.get).flatMap((upstreamDone) => {
|
363
|
+
if (satisfied) return Channel.writeNow(leftovers.flatten).as(Just(doneValue));
|
364
|
+
else if (upstreamDone) return Channel.writeNow(leftovers.flatten).as(Nothing());
|
365
|
+
else return loop;
|
366
|
+
}),
|
367
|
+
),
|
368
|
+
);
|
369
|
+
|
370
|
+
return (upstreamMarker >>> Channel.bufferChunk(leftoversRef)) >>> loop;
|
371
|
+
}),
|
372
|
+
);
|
373
|
+
}
|
374
|
+
|
375
|
+
/**
|
376
|
+
* @tsplus fluent fncts.io.Sink flatMap
|
377
|
+
*/
|
378
|
+
export function flatMap<R, E, In, L, Z, R1, E1, In1 extends In, L1, Z1>(
|
379
|
+
self: Sink<R, E, In, L, Z>,
|
380
|
+
f: (z: Z) => Sink<R1, E1, In1, L1, Z1>,
|
381
|
+
__tsplusTrace?: string,
|
382
|
+
): Sink<R & R1, E | E1, In1, L | L1, Z1> {
|
383
|
+
return self.matchSink(Sink.failNow, f);
|
384
|
+
}
|
385
|
+
|
386
|
+
/**
|
387
|
+
* @tsplus static fncts.io.SinkOps fromChannel
|
388
|
+
* @tsplus static fncts.io.SinkOps __call
|
389
|
+
*/
|
390
|
+
export function fromChannel<R, E, In, L, Z>(
|
391
|
+
channel: Channel<R, never, Conc<In>, unknown, E, Conc<L>, Z>,
|
392
|
+
): Sink<R, E, In, L, Z> {
|
393
|
+
return new Sink(channel);
|
394
|
+
}
|
395
|
+
|
396
|
+
/**
|
397
|
+
* @tsplus static fncts.io.SinkOps fromPush
|
398
|
+
*/
|
399
|
+
export function fromPush<R, E, In, L, Z, R1>(
|
400
|
+
push: IO<Has<Scope> & R, never, (_: Maybe<Conc<In>>) => IO<R1, readonly [Either<E, Z>, Conc<L>], void>>,
|
401
|
+
__tsplusTrace?: string,
|
402
|
+
): Sink<R & R1, E, In, L, Z> {
|
403
|
+
return new Sink(Channel.unwrapScoped(push.map(fromPushPull)));
|
404
|
+
}
|
405
|
+
|
406
|
+
function fromPushPull<R, E, In, L, Z>(
|
407
|
+
push: (_: Maybe<Conc<In>>) => IO<R, readonly [Either<E, Z>, Conc<L>], void>,
|
408
|
+
): Channel<R, never, Conc<In>, unknown, E, Conc<L>, Z> {
|
409
|
+
return Channel.readWith(
|
410
|
+
(inp: Conc<In>) =>
|
411
|
+
Channel.fromIO(push(Just(inp))).matchChannel(
|
412
|
+
([r, leftovers]) =>
|
413
|
+
r.match(
|
414
|
+
(e) => Channel.writeNow(leftovers) > Channel.failNow(e),
|
415
|
+
(z) => Channel.writeNow(leftovers) > Channel.succeedNow(z),
|
416
|
+
),
|
417
|
+
() => fromPushPull(push),
|
418
|
+
),
|
419
|
+
Channel.failNow,
|
420
|
+
() =>
|
421
|
+
Channel.fromIO(push(Nothing())).matchChannel(
|
422
|
+
([r, leftovers]) =>
|
423
|
+
r.match(
|
424
|
+
(e) => Channel.writeNow(leftovers) > Channel.failNow(e),
|
425
|
+
(z) => Channel.writeNow(leftovers) > Channel.succeedNow(z),
|
426
|
+
),
|
427
|
+
() => Channel.fromIO(IO.halt(new Error("empty sink"))),
|
428
|
+
),
|
429
|
+
);
|
430
|
+
}
|
431
|
+
|
432
|
+
/**
|
433
|
+
* @tsplus static fncts.io.SinkOps fromQueue
|
434
|
+
*/
|
435
|
+
export function fromQueue<In>(queue: Lazy<Queue.Enqueue<In>>): Sink<unknown, never, In, never, void> {
|
436
|
+
return Sink.unwrap(IO.succeed(queue).map((queue) => Sink.foreachChunk((inp) => queue.offerAll(inp))));
|
437
|
+
}
|
438
|
+
|
439
|
+
/**
|
440
|
+
* @tsplus static fncts.io.SinkOps fromQueueWithShutdown
|
441
|
+
*/
|
442
|
+
export function fromQueueWithShutdown<In>(queue: Lazy<Queue.Enqueue<In>>): Sink<unknown, never, In, never, void> {
|
443
|
+
return Sink.unwrapScoped(
|
444
|
+
IO.succeed(queue)
|
445
|
+
.acquireRelease((queue) => queue.shutdown)
|
446
|
+
.map((queue) => Sink.fromQueue(queue)),
|
447
|
+
);
|
448
|
+
}
|
449
|
+
|
450
|
+
/**
|
451
|
+
* @tsplus static fncts.io.SinkOps fromHub
|
452
|
+
*/
|
453
|
+
export function fromHub<In>(hub: Lazy<Hub<In>>): Sink<unknown, never, In, never, void> {
|
454
|
+
return Sink.fromQueue(hub);
|
455
|
+
}
|
456
|
+
|
457
|
+
/**
|
458
|
+
* @tsplus static fncts.io.SinkOps fromHubWithShutdown
|
459
|
+
*/
|
460
|
+
export function fromHubWithShutdown<In>(hub: Lazy<Hub<In>>): Sink<unknown, never, In, never, void> {
|
461
|
+
return Sink.fromQueueWithShutdown(hub);
|
462
|
+
}
|
463
|
+
|
464
|
+
/**
|
465
|
+
* @tsplus static fncts.io.SinkOps fromIO
|
466
|
+
*/
|
467
|
+
export function fromIO<R, E, Z>(b: Lazy<IO<R, E, Z>>): Sink<R, E, unknown, never, Z> {
|
468
|
+
return new Sink(Channel.fromIO(b));
|
469
|
+
}
|
470
|
+
|
471
|
+
/**
|
472
|
+
* @tsplus static fncts.io.SinkOps halt
|
473
|
+
*/
|
474
|
+
export function halt(defect: Lazy<unknown>, __tsplusTrace?: string): Sink<unknown, never, unknown, never, never> {
|
475
|
+
return Sink.failCause(Cause.halt(defect()));
|
476
|
+
}
|
477
|
+
|
478
|
+
/**
|
479
|
+
* @tsplus static fncts.io.SinkOps haltNow
|
480
|
+
*/
|
481
|
+
export function haltNow(defect: unknown, __tsplusTrace?: string): Sink<unknown, never, unknown, never, never> {
|
482
|
+
return Sink.failCauseNow(Cause.halt(defect));
|
483
|
+
}
|
484
|
+
|
485
|
+
/**
|
486
|
+
* @tsplus static fncts.io.SinkOps head
|
487
|
+
*/
|
488
|
+
export function head<In>(__tsplusTrace?: string): Sink<unknown, never, In, In, Maybe<In>> {
|
489
|
+
return Sink.fold(
|
490
|
+
Nothing(),
|
491
|
+
(elem) => elem.isNothing(),
|
492
|
+
(s, inp) =>
|
493
|
+
s.match(
|
494
|
+
() => Just(inp),
|
495
|
+
() => s,
|
496
|
+
),
|
497
|
+
);
|
498
|
+
}
|
499
|
+
|
500
|
+
/**
|
501
|
+
* @tsplus getter fncts.io.Sink ignoreLeftover
|
502
|
+
*/
|
503
|
+
export function ignoreLeftover<R, E, In, L, Z>(
|
504
|
+
self: Sink<R, E, In, L, Z>,
|
505
|
+
__tsplusTrace?: string,
|
506
|
+
): Sink<R, E, In, never, Z> {
|
507
|
+
return new Sink(self.channel.drain);
|
508
|
+
}
|
509
|
+
|
510
|
+
/**
|
511
|
+
* @tsplus static fncts.io.SinkOps last
|
512
|
+
*/
|
513
|
+
export function last<In>(__tsplusTrace?: string): Sink<unknown, never, In, In, Maybe<In>> {
|
514
|
+
return Sink.foldLeft(Nothing(), (_, inp) => Just(inp));
|
515
|
+
}
|
516
|
+
|
517
|
+
/**
|
518
|
+
* @tsplus static fncts.io.SinkOps leftover
|
519
|
+
*/
|
520
|
+
export function leftover<L>(c: Lazy<Conc<L>>, __tsplusTrace?: string): Sink<unknown, never, unknown, L, void> {
|
521
|
+
return new Sink(Channel.write(c));
|
522
|
+
}
|
523
|
+
|
524
|
+
/**
|
525
|
+
* @tsplus static fncts.io.SinkOps log
|
526
|
+
*/
|
527
|
+
export function log(message: Lazy<string>, __tsplusTrace?: string): Sink<unknown, never, unknown, never, void> {
|
528
|
+
return Sink.fromIO(IO.log(message));
|
529
|
+
}
|
530
|
+
|
531
|
+
/**
|
532
|
+
* A sink that collects all of its inputs into a chunk.
|
533
|
+
*
|
534
|
+
* @tsplus static fncts.io.SinkOps collectAll
|
535
|
+
*/
|
536
|
+
export function makeCollectAll<In>(): Sink<unknown, never, In, never, Conc<In>> {
|
537
|
+
return new Sink(collectLoop<In>(Conc.empty()));
|
538
|
+
}
|
539
|
+
|
540
|
+
function collectLoop<A>(state: Conc<A>): Channel<unknown, never, Conc<A>, unknown, never, Conc<never>, Conc<A>> {
|
541
|
+
return Channel.readWithCause(
|
542
|
+
(inp: Conc<A>) => collectLoop(state.concat(inp)),
|
543
|
+
Channel.failCauseNow,
|
544
|
+
() => Channel.endNow(state),
|
545
|
+
);
|
546
|
+
}
|
547
|
+
|
548
|
+
export function makeCollectAllN<In>(n: Lazy<number>): Sink<unknown, never, In, In, Conc<In>> {
|
549
|
+
return Sink.fromIO(IO.succeed(new ConcBuilder<In>())).flatMap((builder) =>
|
550
|
+
Sink.foldUntil<In, ConcBuilder<In>>(builder, n, (builder, inp) => builder.append(inp)).map((builder) =>
|
551
|
+
builder.result(),
|
552
|
+
),
|
553
|
+
);
|
554
|
+
}
|
555
|
+
|
51
556
|
/**
|
52
557
|
* A sink that executes the provided effectful function for every element fed to it.
|
53
558
|
*
|
54
559
|
* @tsplus static fncts.io.SinkOps foreach
|
55
560
|
*/
|
56
|
-
export function
|
561
|
+
export function makeForeach<R, Err, In>(
|
562
|
+
f: (inp: In) => IO<R, Err, any>,
|
563
|
+
__tsplusTrace?: string,
|
564
|
+
): Sink<R, Err, In, In, void> {
|
57
565
|
return Sink.foreachWhile((inp) => f(inp).as(true));
|
58
566
|
}
|
59
567
|
|
568
|
+
/**
|
569
|
+
* @tsplus static fncts.io.SinkOps foreachChunk
|
570
|
+
*/
|
571
|
+
export function makeForeachChunk<R, E, In>(
|
572
|
+
f: (inp: Conc<In>) => IO<R, E, void>,
|
573
|
+
__tsplusTrace?: string,
|
574
|
+
): Sink<R, E, In, never, void> {
|
575
|
+
const process: Channel<R, E, Conc<In>, unknown, E, never, void> = Channel.readWithCause(
|
576
|
+
(inp: Conc<In>) => Channel.fromIO(f(inp)) > process,
|
577
|
+
Channel.failCauseNow,
|
578
|
+
() => Channel.unit,
|
579
|
+
);
|
580
|
+
|
581
|
+
return new Sink(process);
|
582
|
+
}
|
583
|
+
|
584
|
+
/**
|
585
|
+
* A sink that executes the provided effectful function for every element fed to it
|
586
|
+
* until `f` evaluates to `false`.
|
587
|
+
*
|
588
|
+
* @tsplus static fncts.io.SinkOps foreachWhile
|
589
|
+
*/
|
590
|
+
export function makeForeachWhile<R, Err, In>(
|
591
|
+
f: (_: In) => IO<R, Err, boolean>,
|
592
|
+
__tsplusTrace?: string,
|
593
|
+
): Sink<R, Err, In, In, void> {
|
594
|
+
const process: Channel<R, Err, Conc<In>, unknown, Err, Conc<In>, void> = Channel.readWithCause(
|
595
|
+
(inp: Conc<In>) => foreachWhileLoop(f, inp, 0, inp.length, process),
|
596
|
+
Channel.failCauseNow,
|
597
|
+
() => Channel.unit,
|
598
|
+
);
|
599
|
+
return new Sink(process);
|
600
|
+
}
|
601
|
+
|
60
602
|
function foreachWhileLoop<R, Err, In>(
|
61
603
|
f: (_: In) => IO<R, Err, boolean>,
|
62
604
|
chunk: Conc<In>,
|
@@ -73,16 +615,805 @@ function foreachWhileLoop<R, Err, In>(
|
|
73
615
|
}
|
74
616
|
|
75
617
|
/**
|
76
|
-
*
|
77
|
-
|
618
|
+
* @tsplus static fncts.io.SinkOps foreachChunkWhile
|
619
|
+
*/
|
620
|
+
export function makeForeachChunkWhile<R, E, In>(
|
621
|
+
f: (chunk: Conc<In>) => IO<R, E, boolean>,
|
622
|
+
__tsplusTrace?: string,
|
623
|
+
): Sink<R, E, In, In, void> {
|
624
|
+
const reader: Channel<R, E, Conc<In>, unknown, E, never, void> = Channel.readWith(
|
625
|
+
(inp: Conc<In>) => Channel.fromIO(f(inp)).flatMap((cont) => (cont ? reader : Channel.unit)),
|
626
|
+
Channel.failNow,
|
627
|
+
() => Channel.unit,
|
628
|
+
);
|
629
|
+
|
630
|
+
return new Sink(reader);
|
631
|
+
}
|
632
|
+
|
633
|
+
/**
|
634
|
+
* @tsplus static fncts.io.SinkOps fold
|
635
|
+
*/
|
636
|
+
export function makeFold<In, S>(
|
637
|
+
z: Lazy<S>,
|
638
|
+
contFn: Predicate<S>,
|
639
|
+
f: (s: S, inp: In) => S,
|
640
|
+
__tsplusTrace?: string,
|
641
|
+
): Sink<unknown, never, In, In, S> {
|
642
|
+
return Sink.defer(new Sink(foldReader(z(), contFn, f)));
|
643
|
+
}
|
644
|
+
|
645
|
+
/**
|
646
|
+
* @tsplus tailRec
|
647
|
+
*/
|
648
|
+
function foldChunkSplit<S, In>(
|
649
|
+
contFn: (s: S) => boolean,
|
650
|
+
f: (s: S, inp: In) => S,
|
651
|
+
s: S,
|
652
|
+
chunk: Conc<In>,
|
653
|
+
idx: number,
|
654
|
+
len: number,
|
655
|
+
): readonly [S, Conc<In>] {
|
656
|
+
if (idx === len) {
|
657
|
+
return [s, Conc.empty()];
|
658
|
+
} else {
|
659
|
+
const s1 = f(s, chunk[idx]);
|
660
|
+
if (contFn(s1)) {
|
661
|
+
return foldChunkSplit(contFn, f, s1, chunk, idx + 1, len);
|
662
|
+
} else {
|
663
|
+
return [s1, chunk.drop(idx + 1)];
|
664
|
+
}
|
665
|
+
}
|
666
|
+
}
|
667
|
+
|
668
|
+
function foldReader<S, In>(
|
669
|
+
s: S,
|
670
|
+
contFn: Predicate<S>,
|
671
|
+
f: (s: S, inp: In) => S,
|
672
|
+
): Channel<unknown, never, Conc<In>, any, never, Conc<In>, S> {
|
673
|
+
if (!contFn(s)) {
|
674
|
+
return Channel.succeedNow(s);
|
675
|
+
} else {
|
676
|
+
return Channel.readWith(
|
677
|
+
(inp: Conc<In>) => {
|
678
|
+
const [nextS, leftovers] = foldChunkSplit(contFn, f, s, inp, 0, inp.length);
|
679
|
+
if (leftovers.isNonEmpty) {
|
680
|
+
return Channel.writeNow(leftovers).as(nextS);
|
681
|
+
} else {
|
682
|
+
return foldReader(nextS, contFn, f);
|
683
|
+
}
|
684
|
+
},
|
685
|
+
(_: never) => Channel.failNow(_),
|
686
|
+
(_: S) => Channel.succeedNow(_),
|
687
|
+
);
|
688
|
+
}
|
689
|
+
}
|
690
|
+
|
691
|
+
/**
|
692
|
+
* @tsplus static fncts.io.SinkOps foldUntil
|
693
|
+
*/
|
694
|
+
export function makeFoldUntil<In, S>(
|
695
|
+
z: Lazy<S>,
|
696
|
+
max: Lazy<number>,
|
697
|
+
f: (s: S, inp: In) => S,
|
698
|
+
__tsplusTrace?: string,
|
699
|
+
): Sink<unknown, never, In, In, S> {
|
700
|
+
return Sink.unwrap(
|
701
|
+
IO.succeed(max).map((max) =>
|
702
|
+
Sink.fold<In, readonly [S, number]>(
|
703
|
+
[z(), 0],
|
704
|
+
([_, n]) => n < max,
|
705
|
+
([o, count], i) => [f(o, i), count + 1],
|
706
|
+
).map(([s]) => s),
|
707
|
+
),
|
708
|
+
);
|
709
|
+
}
|
710
|
+
|
711
|
+
/**
|
712
|
+
* @tsplus static fncts.io.SinkOps foldChunks
|
713
|
+
*/
|
714
|
+
export function makeFoldChunks<In, S>(
|
715
|
+
z: Lazy<S>,
|
716
|
+
contFn: Predicate<S>,
|
717
|
+
f: (s: S, inp: Conc<In>) => S,
|
718
|
+
): Sink<unknown, never, In, never, S> {
|
719
|
+
return Sink.defer(new Sink(foldChunksReader(z(), contFn, f)));
|
720
|
+
}
|
721
|
+
|
722
|
+
function foldChunksReader<In, S>(
|
723
|
+
s: S,
|
724
|
+
contFn: Predicate<S>,
|
725
|
+
f: (s: S, inp: Conc<In>) => S,
|
726
|
+
): Channel<unknown, never, Conc<In>, unknown, never, never, S> {
|
727
|
+
if (!contFn(s)) {
|
728
|
+
return Channel.succeedNow(s);
|
729
|
+
} else {
|
730
|
+
return Channel.readWith(
|
731
|
+
(inp: Conc<In>) => {
|
732
|
+
const nextS = f(s, inp);
|
733
|
+
return foldChunksReader(nextS, contFn, f);
|
734
|
+
},
|
735
|
+
(err: never) => Channel.failNow(err),
|
736
|
+
(_: any) => Channel.succeedNow(_),
|
737
|
+
);
|
738
|
+
}
|
739
|
+
}
|
740
|
+
|
741
|
+
/**
|
742
|
+
* @tsplus static fncts.io.SinkOps foldChunksIO
|
743
|
+
*/
|
744
|
+
export function makeFoldChunksIO<Env, Err, In, S>(
|
745
|
+
z: Lazy<S>,
|
746
|
+
contFn: Predicate<S>,
|
747
|
+
f: (s: S, inp: Conc<In>) => IO<Env, Err, S>,
|
748
|
+
): Sink<Env, Err, In, In, S> {
|
749
|
+
return Sink.defer(new Sink(foldChunksIOReader(z(), contFn, f)));
|
750
|
+
}
|
751
|
+
|
752
|
+
function foldChunksIOReader<Env, Err, In, S>(
|
753
|
+
s: S,
|
754
|
+
contFn: Predicate<S>,
|
755
|
+
f: (s: S, inp: Conc<In>) => IO<Env, Err, S>,
|
756
|
+
): Channel<Env, Err, Conc<In>, unknown, Err, never, S> {
|
757
|
+
if (!contFn(s)) {
|
758
|
+
return Channel.succeedNow(s);
|
759
|
+
} else {
|
760
|
+
return Channel.readWith(
|
761
|
+
(inp: Conc<In>) => Channel.fromIO(f(s, inp)).flatMap((s) => foldChunksIOReader(s, contFn, f)),
|
762
|
+
(err: Err) => Channel.failNow(err),
|
763
|
+
(_: any) => Channel.succeedNow(_),
|
764
|
+
);
|
765
|
+
}
|
766
|
+
}
|
767
|
+
|
768
|
+
/**
|
769
|
+
* @tsplus static fncts.io.SinkOps foldLeft
|
770
|
+
*/
|
771
|
+
export function makeFoldLeft<In, S>(z: Lazy<S>, f: (s: S, inp: In) => S): Sink<unknown, never, In, never, S> {
|
772
|
+
return Sink.fold(z, () => true, f).ignoreLeftover;
|
773
|
+
}
|
774
|
+
|
775
|
+
/**
|
776
|
+
* @tsplus static fncts.io.SinkOps foldLeftChunks
|
777
|
+
*/
|
778
|
+
export function makeFoldLeftChunks<In, S>(
|
779
|
+
z: Lazy<S>,
|
780
|
+
f: (s: S, inp: Conc<In>) => S,
|
781
|
+
): Sink<unknown, never, In, never, S> {
|
782
|
+
return Sink.foldChunks(z, () => true, f).ignoreLeftover;
|
783
|
+
}
|
784
|
+
|
785
|
+
/**
|
786
|
+
* @tsplus static fncts.io.SinkOps foldLeftChunksIO
|
787
|
+
*/
|
788
|
+
export function makeFoldLeftChunksIO<R, E, In, S>(
|
789
|
+
z: Lazy<S>,
|
790
|
+
f: (s: S, inp: Conc<In>) => IO<R, E, S>,
|
791
|
+
): Sink<R, E, In, In, S> {
|
792
|
+
return Sink.foldChunksIO(z, () => true, f);
|
793
|
+
}
|
794
|
+
|
795
|
+
/**
|
796
|
+
* @tsplus static fncts.io.SinkOps foldLeftIO
|
797
|
+
*/
|
798
|
+
export function makeFoldLeftIO<R, E, In, S>(z: Lazy<S>, f: (s: S, inp: In) => IO<R, E, S>): Sink<R, E, In, In, S> {
|
799
|
+
return Sink.foldIO(z, () => true, f);
|
800
|
+
}
|
801
|
+
|
802
|
+
/**
|
803
|
+
* @tsplus static fncts.io.SinkOps foldIO
|
804
|
+
*/
|
805
|
+
export function makeFoldIO<R, E, In, S>(
|
806
|
+
z: Lazy<S>,
|
807
|
+
contFn: Predicate<S>,
|
808
|
+
f: (s: S, inp: In) => IO<R, E, S>,
|
809
|
+
): Sink<R, E, In, In, S> {
|
810
|
+
return Sink.defer(new Sink(foldIOReader(z(), contFn, f)));
|
811
|
+
}
|
812
|
+
|
813
|
+
function foldChunkSplitIO<R, E, In, S>(
|
814
|
+
s: S,
|
815
|
+
contFn: (s: S) => boolean,
|
816
|
+
f: (s: S, inp: In) => IO<R, E, S>,
|
817
|
+
chunk: Conc<In>,
|
818
|
+
idx: number,
|
819
|
+
len: number,
|
820
|
+
): IO<R, E, readonly [S, Maybe<Conc<In>>]> {
|
821
|
+
if (idx === len) {
|
822
|
+
return IO.succeedNow([s, Nothing()]);
|
823
|
+
} else {
|
824
|
+
return f(s, chunk[idx]).flatMap((s1) => {
|
825
|
+
if (contFn(s1)) {
|
826
|
+
return foldChunkSplitIO(s1, contFn, f, chunk, idx + 1, len);
|
827
|
+
} else {
|
828
|
+
return IO.succeedNow([s1, Just(chunk.drop(idx + 1))]);
|
829
|
+
}
|
830
|
+
});
|
831
|
+
}
|
832
|
+
}
|
833
|
+
|
834
|
+
function foldIOReader<R, E, In, S>(
|
835
|
+
s: S,
|
836
|
+
contFn: (s: S) => boolean,
|
837
|
+
f: (s: S, inp: In) => IO<R, E, S>,
|
838
|
+
): Channel<R, E, Conc<In>, unknown, E, Conc<In>, S> {
|
839
|
+
if (!contFn(s)) {
|
840
|
+
return Channel.succeedNow(s);
|
841
|
+
} else {
|
842
|
+
return Channel.readWith(
|
843
|
+
(inp: Conc<In>) =>
|
844
|
+
Channel.fromIO(foldChunkSplitIO(s, contFn, f, inp, 0, inp.length)).flatMap(([nextS, leftovers]) =>
|
845
|
+
leftovers.match(
|
846
|
+
() => foldIOReader(nextS, contFn, f),
|
847
|
+
(l) => Channel.writeNow(l).as(nextS),
|
848
|
+
),
|
849
|
+
),
|
850
|
+
(err: E) => Channel.failNow(err),
|
851
|
+
(_: any) => Channel.succeedNow(_),
|
852
|
+
);
|
853
|
+
}
|
854
|
+
}
|
855
|
+
|
856
|
+
/**
|
857
|
+
* @tsplus static fncts.io.SinkOps foldUntilIO
|
858
|
+
*/
|
859
|
+
export function makeFoldUntilIO<R, E, In, S>(
|
860
|
+
z: Lazy<S>,
|
861
|
+
max: Lazy<number>,
|
862
|
+
f: (s: S, inp: In) => IO<R, E, S>,
|
863
|
+
): Sink<R, E, In, In, S> {
|
864
|
+
return Sink.foldIO<R, E, In, readonly [S, number]>(
|
865
|
+
[z(), 0],
|
866
|
+
([_, n]) => n < max(),
|
867
|
+
([o, count], i) => f(o, i).map((s) => [s, count + 1]),
|
868
|
+
).map(([s]) => s);
|
869
|
+
}
|
870
|
+
|
871
|
+
/**
|
872
|
+
* @tsplus static fncts.io.SinkOps foldWeightedDecompose
|
873
|
+
*/
|
874
|
+
export function makeFoldWeightedDecompose<In, S>(
|
875
|
+
z: Lazy<S>,
|
876
|
+
costFn: (s: S, inp: In) => number,
|
877
|
+
max: Lazy<number>,
|
878
|
+
decompose: (inp: In) => Conc<In>,
|
879
|
+
f: (s: S, inp: In) => S,
|
880
|
+
): Sink<unknown, never, In, In, S> {
|
881
|
+
return Sink.defer(() => {
|
882
|
+
/**
|
883
|
+
* @tsplus tailRec
|
884
|
+
*/
|
885
|
+
function fold(
|
886
|
+
inp: Conc<In>,
|
887
|
+
s: S,
|
888
|
+
max: number,
|
889
|
+
dirty: boolean,
|
890
|
+
cost: number,
|
891
|
+
idx: number,
|
892
|
+
): readonly [S, number, boolean, Conc<In>] {
|
893
|
+
if (idx === inp.length) {
|
894
|
+
return [s, cost, dirty, Conc.empty()];
|
895
|
+
} else {
|
896
|
+
const elem = inp[idx];
|
897
|
+
const total = cost + costFn(s, elem);
|
898
|
+
|
899
|
+
if (total <= max) {
|
900
|
+
return fold(inp, f(s, elem), max, true, total, idx + 1);
|
901
|
+
} else {
|
902
|
+
const decomposed = decompose(elem);
|
903
|
+
|
904
|
+
if (decomposed.length <= 1 && !dirty) {
|
905
|
+
return [f(s, elem), total, true, inp.drop(idx + 1)];
|
906
|
+
} else if (decomposed.length <= 1 && dirty) {
|
907
|
+
return [s, cost, dirty, inp.drop(idx)];
|
908
|
+
} else {
|
909
|
+
return fold(decomposed.concat(inp.drop(idx + 1)), s, max, dirty, cost, 0);
|
910
|
+
}
|
911
|
+
}
|
912
|
+
}
|
913
|
+
}
|
914
|
+
function go(
|
915
|
+
s: S,
|
916
|
+
cost: number,
|
917
|
+
dirty: boolean,
|
918
|
+
max: number,
|
919
|
+
): Channel<unknown, never, Conc<In>, unknown, never, Conc<In>, S> {
|
920
|
+
return Channel.readWith(
|
921
|
+
(inp: Conc<In>) => {
|
922
|
+
const [nextS, nextCost, nextDirty, leftovers] = fold(inp, s, max, dirty, cost, 0);
|
923
|
+
|
924
|
+
if (leftovers.isNonEmpty) {
|
925
|
+
return Channel.writeNow(leftovers) > Channel.succeedNow(nextS);
|
926
|
+
} else if (cost > max) {
|
927
|
+
return Channel.succeedNow(nextS);
|
928
|
+
} else {
|
929
|
+
return go(nextS, nextCost, nextDirty, max);
|
930
|
+
}
|
931
|
+
},
|
932
|
+
(err: never) => Channel.failNow(err),
|
933
|
+
(_: any) => Channel.succeedNow(s),
|
934
|
+
);
|
935
|
+
}
|
936
|
+
|
937
|
+
return new Sink(go(z(), 0, false, max()));
|
938
|
+
});
|
939
|
+
}
|
940
|
+
|
941
|
+
/**
|
942
|
+
* @tsplus static fncts.io.SinkOps foldWeightedDecomposeIO
|
943
|
+
*/
|
944
|
+
export function makeFoldWeightedDecomposeIO<R, E, In, S, R1, E1, R2, E2>(
|
945
|
+
z: Lazy<S>,
|
946
|
+
costFn: (s: S, inp: In) => IO<R1, E1, number>,
|
947
|
+
max: Lazy<number>,
|
948
|
+
decompose: (inp: In) => IO<R2, E2, Conc<In>>,
|
949
|
+
f: (s: S, inp: In) => IO<R, E, S>,
|
950
|
+
): Sink<R & R1 & R2, E | E1 | E2, In, In, S> {
|
951
|
+
return Sink.defer(() => {
|
952
|
+
function fold(
|
953
|
+
inp: Conc<In>,
|
954
|
+
s: S,
|
955
|
+
max: number,
|
956
|
+
dirty: boolean,
|
957
|
+
cost: number,
|
958
|
+
idx: number,
|
959
|
+
): IO<R & R1 & R2, E | E1 | E2, readonly [S, number, boolean, Conc<In>]> {
|
960
|
+
if (idx === inp.length) {
|
961
|
+
return IO.succeedNow([s, cost, dirty, Conc.empty()]);
|
962
|
+
} else {
|
963
|
+
const elem = inp[idx];
|
964
|
+
return costFn(s, elem)
|
965
|
+
.map((_) => cost + _)
|
966
|
+
.flatMap((total) => {
|
967
|
+
if (total <= max) {
|
968
|
+
return f(s, elem).flatMap((s) => fold(inp, s, max, true, total, idx + 1));
|
969
|
+
} else {
|
970
|
+
return decompose(elem).flatMap((decomposed) => {
|
971
|
+
if (decomposed.length <= 1 && !dirty) {
|
972
|
+
return f(s, elem).map((s) => [s, total, true, inp.drop(idx + 1)]);
|
973
|
+
} else if (decomposed.length <= 1 && dirty) {
|
974
|
+
return IO.succeedNow([s, cost, dirty, inp.drop(idx)]);
|
975
|
+
} else {
|
976
|
+
return fold(decomposed.concat(inp.drop(idx + 1)), s, max, dirty, cost, 0);
|
977
|
+
}
|
978
|
+
});
|
979
|
+
}
|
980
|
+
});
|
981
|
+
}
|
982
|
+
}
|
983
|
+
function go(
|
984
|
+
s: S,
|
985
|
+
cost: number,
|
986
|
+
dirty: boolean,
|
987
|
+
max: number,
|
988
|
+
): Channel<R & R1 & R2, E | E1 | E2, Conc<In>, unknown, E | E1 | E2, Conc<In>, S> {
|
989
|
+
return Channel.readWith(
|
990
|
+
(inp: Conc<In>) =>
|
991
|
+
Channel.fromIO(fold(inp, s, max, dirty, cost, 0)).flatMap(([nextS, nextCost, nextDirty, leftovers]) => {
|
992
|
+
if (leftovers.isNonEmpty) {
|
993
|
+
return Channel.writeNow(leftovers) > Channel.succeedNow(nextS);
|
994
|
+
} else if (cost > max) {
|
995
|
+
return Channel.succeedNow(nextS);
|
996
|
+
} else {
|
997
|
+
return go(nextS, nextCost, nextDirty, max);
|
998
|
+
}
|
999
|
+
}),
|
1000
|
+
(err: E | E1 | E2) => Channel.failNow(err),
|
1001
|
+
(_: any) => Channel.succeedNow(s),
|
1002
|
+
);
|
1003
|
+
}
|
1004
|
+
|
1005
|
+
return new Sink(go(z(), 0, false, max()));
|
1006
|
+
});
|
1007
|
+
}
|
1008
|
+
|
1009
|
+
/**
|
1010
|
+
* @tsplus static fncts.io.SinkOps foldWeighted
|
1011
|
+
*/
|
1012
|
+
export function makeFoldWeighted<In, S>(
|
1013
|
+
z: Lazy<S>,
|
1014
|
+
costFn: (s: S, inp: In) => number,
|
1015
|
+
max: Lazy<number>,
|
1016
|
+
f: (s: S, inp: In) => S,
|
1017
|
+
): Sink<unknown, never, In, In, S> {
|
1018
|
+
return Sink.foldWeightedDecompose(z, costFn, max, Conc.single, f);
|
1019
|
+
}
|
1020
|
+
|
1021
|
+
/**
|
1022
|
+
* @tsplus static fncts.io.SinkOps foldWeightedIO
|
1023
|
+
*/
|
1024
|
+
export function makeFoldWeightedIO<R, E, In, S, R1, E1>(
|
1025
|
+
z: Lazy<S>,
|
1026
|
+
costFn: (s: S, inp: In) => IO<R, E, number>,
|
1027
|
+
max: Lazy<number>,
|
1028
|
+
f: (s: S, inp: In) => IO<R1, E1, S>,
|
1029
|
+
): Sink<R & R1, E | E1, In, In, S> {
|
1030
|
+
return Sink.foldWeightedDecomposeIO(z, costFn, max, (inp) => IO.succeedNow(Conc.single(inp)), f);
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
/**
|
1034
|
+
* Transforms this sink's result.
|
78
1035
|
*
|
79
|
-
* @tsplus
|
1036
|
+
* @tsplus fluent fncts.io.Sink map
|
80
1037
|
*/
|
81
|
-
export function
|
82
|
-
|
83
|
-
|
1038
|
+
export function map_<R, E, In, L, Z, Z1>(
|
1039
|
+
self: Sink<R, E, In, L, Z>,
|
1040
|
+
f: (z: Z) => Z1,
|
1041
|
+
__tsplusTrace?: string,
|
1042
|
+
): Sink<R, E, In, L, Z1> {
|
1043
|
+
return new Sink(self.channel.map(f));
|
1044
|
+
}
|
1045
|
+
|
1046
|
+
/**
|
1047
|
+
* Transforms the errors emitted by this sink using `f`.
|
1048
|
+
*
|
1049
|
+
* @tsplus fluent fncts.io.Sink mapError
|
1050
|
+
*/
|
1051
|
+
export function mapError_<R, E, In, L, Z, E1>(
|
1052
|
+
self: Sink<R, E, In, L, Z>,
|
1053
|
+
f: (e: E) => E1,
|
1054
|
+
__tsplusTrace?: string,
|
1055
|
+
): Sink<R, E1, In, L, Z> {
|
1056
|
+
return new Sink(self.channel.mapError(f));
|
1057
|
+
}
|
1058
|
+
|
1059
|
+
/**
|
1060
|
+
* Effectfully transforms this sink's result.
|
1061
|
+
*
|
1062
|
+
* @tsplus fluent fncts.io.Sink mapIO
|
1063
|
+
*/
|
1064
|
+
export function mapIO_<R, E, In, L, Z, R1, E1, Z1>(
|
1065
|
+
self: Sink<R, E, In, L, Z>,
|
1066
|
+
f: (z: Z) => IO<R1, E1, Z1>,
|
1067
|
+
__tsplusTrace?: string,
|
1068
|
+
): Sink<R & R1, E | E1, In, L, Z1> {
|
1069
|
+
return new Sink(self.channel.mapIO(f));
|
1070
|
+
}
|
1071
|
+
|
1072
|
+
/**
|
1073
|
+
* Runs this sink until it yields a result, then uses that result to create
|
1074
|
+
* another sink from the provided function which will continue to run until it
|
1075
|
+
* yields a result.
|
1076
|
+
*
|
1077
|
+
* This function essentially runs sinks in sequence.
|
1078
|
+
*
|
1079
|
+
* @tsplus fluent fncts.io.Sink matchSink
|
1080
|
+
*/
|
1081
|
+
export function matchSink_<R, E, In, L, Z, R1, E1, In1 extends In, L1, Z1, R2, E2, In2 extends In, L2, Z2>(
|
1082
|
+
self: Sink<R, E, In, L, Z>,
|
1083
|
+
onFailure: (e: E) => Sink<R1, E1, In1, L1, Z1>,
|
1084
|
+
onSuccess: (z: Z) => Sink<R2, E2, In2, L2, Z2>,
|
1085
|
+
__tsplusTrace?: string,
|
1086
|
+
): Sink<R & R1 & R2, E1 | E2, In1 & In2, L | L1 | L2, Z1 | Z2> {
|
1087
|
+
return new Sink<R & R1 & R2, E1 | E2, In1 & In2, L | L1 | L2, Z1 | Z2>(
|
1088
|
+
self.channel.doneCollect.matchChannel(
|
1089
|
+
(e) => onFailure(e).channel,
|
1090
|
+
([leftovers, z]) =>
|
1091
|
+
Channel.defer(() => {
|
1092
|
+
const leftoversRef = new AtomicReference(leftovers.filter((c) => c.isNonEmpty));
|
1093
|
+
const refReader = Channel.succeed(leftoversRef.getAndSet(Conc.empty())).flatMap((chunk) =>
|
1094
|
+
Channel.writeChunk(chunk as unknown as Conc<Conc<In1 & In2>>),
|
1095
|
+
);
|
1096
|
+
const passthrough = Channel.id<never, Conc<In1 & In2>, unknown>();
|
1097
|
+
const continuationSink = (refReader > passthrough).pipeTo(onSuccess(z).channel);
|
1098
|
+
return continuationSink.doneCollect.flatMap(
|
1099
|
+
([newLeftovers, z1]) =>
|
1100
|
+
Channel.succeed(leftoversRef.get).flatMap(Channel.writeChunk) > Channel.writeChunk(newLeftovers).as(z1),
|
1101
|
+
);
|
1102
|
+
}),
|
1103
|
+
),
|
1104
|
+
);
|
1105
|
+
}
|
1106
|
+
|
1107
|
+
/**
|
1108
|
+
* @tsplus fluent fncts.io.Sink orElse
|
1109
|
+
*/
|
1110
|
+
export function orElse<R, E, In, L, Z, R1, E1, In1, L1, Z1>(
|
1111
|
+
self: Sink<R, E, In, L, Z>,
|
1112
|
+
that: Lazy<Sink<R1, E1, In1, L1, Z1>>,
|
1113
|
+
__tsplusTrace?: string,
|
1114
|
+
): Sink<R & R1, E | E1, In & In1, L | L1, Z | Z1> {
|
1115
|
+
return Sink.defer(new Sink<R & R1, E | E1, In & In1, L | L1, Z | Z1>(self.channel.orElse(that().channel)));
|
1116
|
+
}
|
1117
|
+
|
1118
|
+
/**
|
1119
|
+
* @tsplus fluent fncts.io.Sink provideEnvironment
|
1120
|
+
*/
|
1121
|
+
export function provideEnvironment<R, E, In, L, Z>(
|
1122
|
+
self: Sink<R, E, In, L, Z>,
|
1123
|
+
r: Lazy<Environment<R>>,
|
1124
|
+
__tsplusTrace?: string,
|
1125
|
+
): Sink<unknown, E, In, L, Z> {
|
1126
|
+
return new Sink(self.channel.provideEnvironment(r));
|
1127
|
+
}
|
1128
|
+
|
1129
|
+
/**
|
1130
|
+
* @tsplus fluent fncts.io.Sink race
|
1131
|
+
*/
|
1132
|
+
export function race<R, E, In, L, Z, R1, E1, In1, L1, Z1>(
|
1133
|
+
self: Sink<R, E, In, L, Z>,
|
1134
|
+
that: Lazy<Sink<R1, E1, In1, L1, Z1>>,
|
1135
|
+
): Sink<R & R1, E | E1, In & In1, L | L1, Z | Z1> {
|
1136
|
+
return self.raceBoth(that).map((result) => result.value);
|
1137
|
+
}
|
1138
|
+
|
1139
|
+
/**
|
1140
|
+
* @tsplus fluent fncts.io.Sink raceBoth
|
1141
|
+
*/
|
1142
|
+
export function raceBoth<R, E, In, L, Z, R1, E1, In1, L1, Z1>(
|
1143
|
+
self: Sink<R, E, In, L, Z>,
|
1144
|
+
that: Lazy<Sink<R1, E1, In1, L1, Z1>>,
|
1145
|
+
capacity: Lazy<number> = () => 16,
|
1146
|
+
): Sink<R & R1, E | E1, In & In1, L | L1, Either<Z, Z1>> {
|
1147
|
+
return self.raceWith(
|
1148
|
+
that,
|
1149
|
+
(selfDone) => MergeDecision.Done(IO.fromExitNow(selfDone).map(Either.left)),
|
1150
|
+
(thatDone) => MergeDecision.Done(IO.fromExitNow(thatDone).map(Either.right)),
|
1151
|
+
capacity,
|
1152
|
+
);
|
1153
|
+
}
|
1154
|
+
|
1155
|
+
/**
|
1156
|
+
* @tsplus fluent fncts.io.Sink raceWith
|
1157
|
+
*/
|
1158
|
+
export function raceWith<R, E, In, L, Z, R1, E1, In1, L1, Z1, R2, E2, Z2, R3, E3, Z3>(
|
1159
|
+
self: Sink<R, E, In, L, Z>,
|
1160
|
+
that: Lazy<Sink<R1, E1, In1, L1, Z1>>,
|
1161
|
+
leftDone: (exit: Exit<E, Z>) => MergeDecision<R1, E1, Z1, E2, Z2>,
|
1162
|
+
rightDone: (exit: Exit<E1, Z1>) => MergeDecision<R, E, Z, E3, Z3>,
|
1163
|
+
capacity: Lazy<number> = () => 16,
|
1164
|
+
__tsplusTrace?: string,
|
1165
|
+
): Sink<R & R1 & R2 & R3, E2 | E3, In & In1, L | L1, Z2 | Z3> {
|
1166
|
+
const scoped = IO.defer(() => {
|
1167
|
+
const that0 = that();
|
1168
|
+
const capacity0 = capacity();
|
1169
|
+
return Do((_) => {
|
1170
|
+
const hub = _(Hub.makeBounded<Either<Exit<never, any>, Conc<In & In1>>>(capacity()));
|
1171
|
+
const c1 = _(Channel.fromHubScoped(hub));
|
1172
|
+
const c2 = _(Channel.fromHubScoped(hub));
|
1173
|
+
const reader = Channel.toHub(hub);
|
1174
|
+
const writer = c1.pipeTo(self.channel).mergeWith(c2.pipeTo(that0.channel), leftDone, rightDone);
|
1175
|
+
const channel = reader.mergeWith(
|
1176
|
+
writer,
|
1177
|
+
() => MergeDecision.Await(IO.fromExitNow),
|
1178
|
+
(done) => MergeDecision.Done(IO.fromExitNow(done)),
|
1179
|
+
);
|
1180
|
+
return new Sink<R & R1 & R2 & R3, E2 | E3, In & In1, L | L1, Z2 | Z3>(channel);
|
1181
|
+
});
|
1182
|
+
});
|
1183
|
+
return Sink.unwrapScoped(scoped);
|
1184
|
+
}
|
1185
|
+
|
1186
|
+
/**
|
1187
|
+
* @tsplus static fncts.io.SinkOps service
|
1188
|
+
*/
|
1189
|
+
export function service<S>(/** @tsplus auto */ tag: Tag<S>): Sink<Has<S>, never, unknown, never, S> {
|
1190
|
+
return Sink.serviceWith(Function.identity);
|
1191
|
+
}
|
1192
|
+
|
1193
|
+
/**
|
1194
|
+
* @tsplus static fncts.io.SinkOps serviceWith
|
1195
|
+
*/
|
1196
|
+
export function serviceWith<S, Z>(
|
1197
|
+
f: (service: S) => Z,
|
1198
|
+
/** @tsplus auto */ tag: Tag<S>,
|
1199
|
+
): Sink<Has<S>, never, unknown, never, Z> {
|
1200
|
+
return Sink.fromIO(IO.serviceWith(f, tag));
|
1201
|
+
}
|
1202
|
+
|
1203
|
+
/**
|
1204
|
+
* @tsplus static fncts.io.SinkOps serviceWithIO
|
1205
|
+
*/
|
1206
|
+
export function serviceWithIO<S, R, E, Z>(
|
1207
|
+
f: (service: S) => IO<R, E, Z>,
|
1208
|
+
/** @tsplus auto */ tag: Tag<S>,
|
1209
|
+
): Sink<Has<S> & R, E, unknown, never, Z> {
|
1210
|
+
return Sink.fromIO(IO.serviceWithIO(f, tag));
|
1211
|
+
}
|
1212
|
+
|
1213
|
+
/**
|
1214
|
+
* @tsplus static fncts.io.SinkOps serviceWithSink
|
1215
|
+
*/
|
1216
|
+
export function serviceWithSink<S, R, E, In, L, Z>(
|
1217
|
+
f: (service: S) => Sink<R, E, In, L, Z>,
|
1218
|
+
/** @tsplus auto */ tag: Tag<S>,
|
1219
|
+
): Sink<Has<S> & R, E, In, L, Z> {
|
1220
|
+
return new Sink(
|
1221
|
+
Channel.unwrap(
|
1222
|
+
IO.serviceWith(
|
1223
|
+
f.compose((s) => s.channel),
|
1224
|
+
tag,
|
1225
|
+
),
|
1226
|
+
),
|
1227
|
+
);
|
1228
|
+
}
|
1229
|
+
|
1230
|
+
/**
|
1231
|
+
* @tsplus fluent fncts.io.Sink splitWhere
|
1232
|
+
*/
|
1233
|
+
export function splitWhere<R, E, In, L extends In, Z>(
|
1234
|
+
self: Sink<R, E, In, L, Z>,
|
1235
|
+
p: Predicate<In>,
|
1236
|
+
): Sink<R, E, In, In, Z> {
|
1237
|
+
return new Sink(
|
1238
|
+
Channel.fromIO(Ref.make<Conc<In>>(Conc.empty())).flatMap((ref) =>
|
1239
|
+
splitter<R, E, In>(p, false, ref)
|
1240
|
+
.pipeToOrFail(self.channel)
|
1241
|
+
.collectElements.flatMap(([leftovers, z]) =>
|
1242
|
+
Channel.fromIO(ref.get).flatMap(
|
1243
|
+
(leftover) => Channel.writeNow(leftover.concat(leftovers.flatten)) > Channel.succeedNow(z),
|
1244
|
+
),
|
1245
|
+
),
|
1246
|
+
),
|
1247
|
+
);
|
1248
|
+
}
|
1249
|
+
|
1250
|
+
function splitter<R, E, In>(
|
1251
|
+
p: Predicate<In>,
|
1252
|
+
written: boolean,
|
1253
|
+
leftovers: Ref<Conc<In>>,
|
1254
|
+
): Channel<R, never, Conc<In>, unknown, E, Conc<In>, unknown> {
|
1255
|
+
return Channel.readWithCause(
|
1256
|
+
(inp) => {
|
1257
|
+
if (inp.isEmpty) {
|
1258
|
+
return splitter(p, written, leftovers);
|
1259
|
+
} else if (written) {
|
1260
|
+
const index = inp.findIndex(p);
|
1261
|
+
if (index === -1) {
|
1262
|
+
return Channel.writeNow(inp) > splitter<R, E, In>(p, true, leftovers);
|
1263
|
+
} else {
|
1264
|
+
const [left, right] = inp.splitAt(index);
|
1265
|
+
return Channel.writeNow(left) > Channel.fromIO(leftovers.set(right));
|
1266
|
+
}
|
1267
|
+
} else {
|
1268
|
+
const index = inp.findIndex(p);
|
1269
|
+
if (index === -1) {
|
1270
|
+
return Channel.writeNow(inp) > splitter<R, E, In>(p, true, leftovers);
|
1271
|
+
} else {
|
1272
|
+
const [left, right] = inp.splitAt(Math.max(index, 1));
|
1273
|
+
return Channel.writeNow(left) > Channel.fromIO(leftovers.set(right));
|
1274
|
+
}
|
1275
|
+
}
|
1276
|
+
},
|
84
1277
|
Channel.failCauseNow,
|
85
|
-
|
1278
|
+
Channel.succeedNow,
|
1279
|
+
);
|
1280
|
+
}
|
1281
|
+
|
1282
|
+
/**
|
1283
|
+
* @tsplus static fncts.io.SinkOps succeed
|
1284
|
+
*/
|
1285
|
+
export function succeed<Z>(z: Lazy<Z>, __tsplusTrace?: string): Sink<unknown, never, unknown, never, Z> {
|
1286
|
+
return new Sink(Channel.succeed(z));
|
1287
|
+
}
|
1288
|
+
|
1289
|
+
/**
|
1290
|
+
* @tsplus static fncts.io.SinkOps succeedNow
|
1291
|
+
*/
|
1292
|
+
export function succeedNow<Z>(z: Z, __tsplusTrace?: string): Sink<unknown, never, unknown, never, Z> {
|
1293
|
+
return new Sink(Channel.succeedNow(z));
|
1294
|
+
}
|
1295
|
+
|
1296
|
+
/**
|
1297
|
+
* @tsplus fluent fncts.io.Sink summarized
|
1298
|
+
*/
|
1299
|
+
export function summarized<R, E, In, L, Z, R1, E1, B, C>(
|
1300
|
+
self: Sink<R, E, In, L, Z>,
|
1301
|
+
summary: Lazy<IO<R1, E1, B>>,
|
1302
|
+
f: (b1: B, b2: B) => C,
|
1303
|
+
__tsplusTrace?: string,
|
1304
|
+
): Sink<R & R1, E | E1, In, L, readonly [Z, C]> {
|
1305
|
+
return new Sink(
|
1306
|
+
Channel.unwrap(
|
1307
|
+
IO.succeed(summary).map((summary) =>
|
1308
|
+
Channel.fromIO(summary).flatMap((start) =>
|
1309
|
+
self.channel.flatMap((done) => Channel.fromIO(summary).map((end) => [done, f(start, end)])),
|
1310
|
+
),
|
1311
|
+
),
|
1312
|
+
),
|
1313
|
+
);
|
1314
|
+
}
|
1315
|
+
|
1316
|
+
/**
|
1317
|
+
* @tsplus getter fncts.io.Sink timed
|
1318
|
+
*/
|
1319
|
+
export function timed<R, E, In, L, Z>(
|
1320
|
+
self: Sink<R, E, In, L, Z>,
|
1321
|
+
__tsplusTrace?: string,
|
1322
|
+
): Sink<R, E, In, L, readonly [Z, Duration]> {
|
1323
|
+
return self.summarized(Clock.currentTime, (start, end) => Duration.fromInterval(start, end));
|
1324
|
+
}
|
1325
|
+
|
1326
|
+
/**
|
1327
|
+
* @tsplus static fncts.io.SinkOps unwrap
|
1328
|
+
*/
|
1329
|
+
export function unwrap<R, E, R1, E1, In, L, Z>(
|
1330
|
+
io: Lazy<IO<R, E, Sink<R1, E1, In, L, Z>>>,
|
1331
|
+
): Sink<R & R1, E | E1, In, L, Z> {
|
1332
|
+
return new Sink(Channel.unwrap(io().map((sink) => sink.channel)));
|
1333
|
+
}
|
1334
|
+
|
1335
|
+
/**
|
1336
|
+
* Creates a sink produced from a scoped effect.
|
1337
|
+
*
|
1338
|
+
* @tsplus static fncts.io.SinkOps unwrapScoped
|
1339
|
+
*/
|
1340
|
+
export function unwrapScoped<R, E, R1, E1, In, L, Z>(
|
1341
|
+
scoped: Lazy<IO<Has<Scope> & R, E, Sink<R1, E1, In, L, Z>>>,
|
1342
|
+
): Sink<R & R1, E | E1, In, L, Z> {
|
1343
|
+
return new Sink(Channel.unwrapScoped(scoped().map((sink) => sink.channel)));
|
1344
|
+
}
|
1345
|
+
|
1346
|
+
/**
|
1347
|
+
* @tsplus fluent fncts.io.Sink zip
|
1348
|
+
*/
|
1349
|
+
export function zip<R, E, In, L, Z, R1, E1, In1 extends In, L1 extends L, Z1>(
|
1350
|
+
self: Sink<R, E, In, L, Z>,
|
1351
|
+
that: Lazy<Sink<R1, E1, In1, L1, Z1>>,
|
1352
|
+
): Sink<R & R1, E | E1, In & In1, L | L1, readonly [Z, Z1]> {
|
1353
|
+
return self.zipWith(that, Function.tuple);
|
1354
|
+
}
|
1355
|
+
|
1356
|
+
/**
|
1357
|
+
* @tsplus fluent fncts.io.Sink zipC
|
1358
|
+
*/
|
1359
|
+
export function zipC<R, E, In, L, Z, R1, E1, In1 extends In, L1 extends L, Z1>(
|
1360
|
+
self: Sink<R, E, In, L, Z>,
|
1361
|
+
that: Lazy<Sink<R1, E1, In1, L1, Z1>>,
|
1362
|
+
): Sink<R & R1, E | E1, In & In1, L | L1, readonly [Z, Z1]> {
|
1363
|
+
return self.zipWithC(that, Function.tuple);
|
1364
|
+
}
|
1365
|
+
|
1366
|
+
/**
|
1367
|
+
* Feeds inputs to this sink until it yields a result, then switches over to
|
1368
|
+
* the provided sink until it yields a result, finally combining the two
|
1369
|
+
* results with `f`.
|
1370
|
+
*
|
1371
|
+
* @tsplus fluent fncts.io.Sink zipWith
|
1372
|
+
*/
|
1373
|
+
export function zipWith<R, E, In, L, Z, R1, E1, In1 extends In, L1 extends L, Z1, Z2>(
|
1374
|
+
self: Lazy<Sink<R, E, In, L, Z>>,
|
1375
|
+
that: Lazy<Sink<R1, E1, In1, L1, Z1>>,
|
1376
|
+
f: (z: Z, z1: Z1) => Z2,
|
1377
|
+
): Sink<R & R1, E | E1, In & In1, L | L1, Z2> {
|
1378
|
+
return Sink.defer(self().flatMap((z) => that().map((z1) => f(z, z1))));
|
1379
|
+
}
|
1380
|
+
|
1381
|
+
/**
|
1382
|
+
* Runs both sinks in parallel on the input and combines the results using the
|
1383
|
+
* provided function.
|
1384
|
+
*
|
1385
|
+
* @tsplus fluent fncts.io.Sink zipWithC
|
1386
|
+
*/
|
1387
|
+
export function zipWithC<R, E, In, L, Z, R1, E1, In1, L1, Z1, Z2>(
|
1388
|
+
self: Lazy<Sink<R, E, In, L, Z>>,
|
1389
|
+
that: Lazy<Sink<R1, E1, In1, L1, Z1>>,
|
1390
|
+
f: (z: Z, z1: Z1) => Z2,
|
1391
|
+
): Sink<R & R1, E | E1, In & In1, L | L1, Z2> {
|
1392
|
+
return Sink.defer(
|
1393
|
+
self().raceWith(
|
1394
|
+
that(),
|
1395
|
+
(exit) =>
|
1396
|
+
exit.match(
|
1397
|
+
(err) => MergeDecision.Done(IO.failCauseNow(err)),
|
1398
|
+
(lz) =>
|
1399
|
+
MergeDecision.Await((exit) =>
|
1400
|
+
exit.match(
|
1401
|
+
(cause) => IO.failCauseNow(cause),
|
1402
|
+
(rz) => IO.succeedNow(f(lz, rz)),
|
1403
|
+
),
|
1404
|
+
),
|
1405
|
+
),
|
1406
|
+
(exit) =>
|
1407
|
+
exit.match(
|
1408
|
+
(err) => MergeDecision.Done(IO.failCauseNow(err)),
|
1409
|
+
(rz) =>
|
1410
|
+
MergeDecision.Await((exit) =>
|
1411
|
+
exit.match(
|
1412
|
+
(cause) => IO.failCauseNow(cause),
|
1413
|
+
(lz) => IO.succeedNow(f(lz, rz)),
|
1414
|
+
),
|
1415
|
+
),
|
1416
|
+
),
|
1417
|
+
),
|
86
1418
|
);
|
87
|
-
return new Sink(process);
|
88
1419
|
}
|