brass-runtime 1.12.1 → 1.13.3

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.
@@ -0,0 +1,407 @@
1
+ import {
2
+ Cause,
3
+ Exit,
4
+ Scope,
5
+ async,
6
+ asyncFail,
7
+ asyncFlatMap,
8
+ asyncFold,
9
+ asyncMapError,
10
+ asyncSucceed,
11
+ asyncSync,
12
+ fail,
13
+ flatMap,
14
+ getCurrentFiber,
15
+ map,
16
+ mapError,
17
+ none,
18
+ orElseOptional,
19
+ raceWith,
20
+ some,
21
+ succeed,
22
+ sync,
23
+ unsafeGetCurrentRuntime,
24
+ unsafeRunFoldWithEnv
25
+ } from "./chunk-T5XJDGTQ.mjs";
26
+
27
+ // src/core/stream/stream.ts
28
+ var widenOpt = (opt) => opt._tag === "None" ? none : some(opt.value);
29
+ var fromPull = (pull) => ({
30
+ _tag: "FromPull",
31
+ pull
32
+ });
33
+ var unwrapScoped = (acquire, release) => ({
34
+ _tag: "Scoped",
35
+ acquire,
36
+ release
37
+ });
38
+ var managedStream = (acquire) => ({
39
+ _tag: "Managed",
40
+ acquire
41
+ });
42
+ var mergeStream = (left, right, flip = true) => ({
43
+ _tag: "Merge",
44
+ left,
45
+ right,
46
+ flip
47
+ });
48
+ var EMPTY_STREAM = { _tag: "Empty" };
49
+ var emptyStream = () => EMPTY_STREAM;
50
+ var emitStream = (value) => ({
51
+ _tag: "Emit",
52
+ value
53
+ });
54
+ var concatStream = (left, right) => ({
55
+ _tag: "Concat",
56
+ left,
57
+ right
58
+ });
59
+ var flattenStream = (stream) => ({
60
+ _tag: "Flatten",
61
+ stream
62
+ });
63
+ function streamToRaceWithHandler(winnerSide, leftStream, rightStream, flip, id) {
64
+ return (exit, otherFiber, scope) => {
65
+ if (exit._tag === "Failure") {
66
+ }
67
+ if (exit._tag === "Success") {
68
+ }
69
+ if (exit._tag === "Success") {
70
+ const [a, tailWin] = exit.value;
71
+ otherFiber.interrupt();
72
+ const next = winnerSide === "L" ? fromPull(makeMergePull(tailWin, rightStream, !flip, id)) : fromPull(makeMergePull(leftStream, tailWin, !flip, id));
73
+ return asyncSucceed([a, next]);
74
+ }
75
+ if (exit.cause._tag === "Interrupt") {
76
+ return async((_env, cb) => {
77
+ cb(Exit.failCause(Cause.interrupt()));
78
+ });
79
+ }
80
+ const opt = exit.cause.error;
81
+ if (opt._tag === "None") {
82
+ return winnerSide === "L" ? uncons(rightStream) : uncons(leftStream);
83
+ }
84
+ return asyncFail(opt);
85
+ };
86
+ }
87
+ function makeMergePull(onLeft, onRight, flip, mergePullId) {
88
+ const id = ++mergePullId;
89
+ const onLeftHandler = streamToRaceWithHandler("L", onLeft, onRight, flip, id);
90
+ const onRightHandler = streamToRaceWithHandler("R", onLeft, onRight, flip, id);
91
+ return async((_env, cb) => {
92
+ const runtime = unsafeGetCurrentRuntime();
93
+ const scope = new Scope(runtime);
94
+ const handler = raceWith(
95
+ uncons(onLeft),
96
+ uncons(onRight),
97
+ scope,
98
+ onLeftHandler,
99
+ onRightHandler
100
+ );
101
+ scope.fork(handler).join((ex) => {
102
+ scope.close(ex);
103
+ cb(ex);
104
+ });
105
+ });
106
+ }
107
+ function merge(left, right) {
108
+ return fromPull(makeMergePull(left, right, true, 0));
109
+ }
110
+ function uncons(self) {
111
+ switch (self._tag) {
112
+ case "Empty":
113
+ return fail(none);
114
+ case "Emit":
115
+ return map(
116
+ mapError(self.value, (e) => some(e)),
117
+ (a) => [a, EMPTY_STREAM]
118
+ );
119
+ case "FromPull":
120
+ return self.pull;
121
+ case "Concat":
122
+ return orElseOptional(
123
+ map(
124
+ uncons(self.left),
125
+ ([a, tail]) => [a, concatStream(tail, self.right)]
126
+ ),
127
+ () => uncons(self.right)
128
+ );
129
+ case "Flatten":
130
+ return flatMap(
131
+ uncons(self.stream),
132
+ ([head, tail]) => orElseOptional(
133
+ map(
134
+ uncons(head),
135
+ ([a, as]) => [
136
+ a,
137
+ concatStream(as, flattenStream(tail))
138
+ ]
139
+ ),
140
+ () => uncons(flattenStream(tail))
141
+ )
142
+ );
143
+ case "Merge":
144
+ return makeMergePull(self.left, self.right, self.flip, 0);
145
+ case "Scoped":
146
+ return async((env, cb) => {
147
+ const runtime = unsafeGetCurrentRuntime();
148
+ const scope = new Scope(runtime);
149
+ const fiber = getCurrentFiber();
150
+ fiber?.addFinalizer((exit) => {
151
+ try {
152
+ scope.close(exit);
153
+ } catch {
154
+ }
155
+ });
156
+ const closeWith = (exit) => {
157
+ if (exit._tag === "Failure") {
158
+ const err = exit.cause.error;
159
+ if (err && typeof err === "object" && err._tag === "None") {
160
+ scope.close({ _tag: "Success", value: void 0 });
161
+ return;
162
+ }
163
+ }
164
+ scope.close(exit);
165
+ };
166
+ const wrap = (s) => fromPull(
167
+ async((env2, cb2) => {
168
+ const pull = uncons(s);
169
+ unsafeRunFoldWithEnv(
170
+ pull,
171
+ env2,
172
+ (cause) => {
173
+ const ex = Exit.failCause(cause);
174
+ closeWith(ex);
175
+ cb2(ex);
176
+ },
177
+ ([a, tail]) => {
178
+ cb2(Exit.succeed([a, wrap(tail)]));
179
+ }
180
+ );
181
+ })
182
+ );
183
+ scope.fork(self.acquire).join((ex) => {
184
+ if (ex._tag === "Failure") {
185
+ closeWith(ex);
186
+ cb({ _tag: "Failure", cause: { _tag: "Fail", error: some(ex.cause.error) } });
187
+ return;
188
+ }
189
+ scope.addFinalizer((exit) => self.release(exit));
190
+ const inner = ex.value;
191
+ unsafeGetCurrentRuntime().fork(uncons(wrap(inner))).join(cb);
192
+ });
193
+ });
194
+ case "Managed":
195
+ return async((env, cb) => {
196
+ const runtime = unsafeGetCurrentRuntime();
197
+ const scope = new Scope(runtime);
198
+ getCurrentFiber()?.addFinalizer((exit) => {
199
+ try {
200
+ scope.close(exit);
201
+ } catch {
202
+ }
203
+ });
204
+ const closeWith = (exit) => {
205
+ if (exit._tag === "Failure") {
206
+ const err = exit.cause.error;
207
+ if (err && typeof err === "object" && err._tag === "None") {
208
+ scope.close({ _tag: "Success", value: void 0 });
209
+ return;
210
+ }
211
+ }
212
+ scope.close(exit);
213
+ };
214
+ scope.fork(self.acquire).join((ex) => {
215
+ if (ex._tag === "Failure") {
216
+ scope.close(ex);
217
+ cb({ _tag: "Failure", cause: { _tag: "Fail", error: some(ex.cause.error) } });
218
+ return;
219
+ }
220
+ const { stream: inner, release } = ex.value;
221
+ scope.addFinalizer((exit) => release(exit));
222
+ const wrap = (s) => fromPull(
223
+ async((env2, cb2) => {
224
+ uncons(s)(env2, (ex2) => {
225
+ if (ex2._tag === "Failure") {
226
+ closeWith(ex2);
227
+ cb2(ex2);
228
+ return;
229
+ }
230
+ const [a, tail] = ex2.value;
231
+ cb2(Exit.succeed([a, wrap(tail)]));
232
+ });
233
+ })
234
+ );
235
+ unsafeGetCurrentRuntime().fork(uncons(wrap(inner))).join(cb);
236
+ });
237
+ });
238
+ }
239
+ }
240
+ function assertNever(x, msg) {
241
+ throw new Error(msg ?? `Unexpected value: ${String(x)}`);
242
+ }
243
+ function mapStream(self, f) {
244
+ switch (self._tag) {
245
+ case "Empty":
246
+ return emptyStream();
247
+ case "Emit":
248
+ return emitStream(map(self.value, f));
249
+ case "FromPull":
250
+ return fromPull(
251
+ map(self.pull, ([a, tail]) => [f(a), mapStream(tail, f)])
252
+ );
253
+ case "Concat":
254
+ return concatStream(mapStream(self.left, f), mapStream(self.right, f));
255
+ case "Flatten": {
256
+ const mappedOuter = mapStream(
257
+ self.stream,
258
+ (inner) => mapStream(inner, f)
259
+ );
260
+ return flattenStream(mappedOuter);
261
+ }
262
+ case "Merge":
263
+ return mergeStream(
264
+ mapStream(self.left, f),
265
+ mapStream(self.right, f),
266
+ self.flip
267
+ );
268
+ case "Scoped":
269
+ return unwrapScoped(
270
+ map(self.acquire, (s) => mapStream(s, f)),
271
+ self.release
272
+ );
273
+ case "Managed":
274
+ return managedStream(
275
+ map(self.acquire, ({ stream, release }) => ({
276
+ stream: mapStream(stream, f),
277
+ release
278
+ }))
279
+ );
280
+ default:
281
+ return assertNever(self);
282
+ }
283
+ }
284
+ function rangeStream(start, end) {
285
+ const go = (i) => fromPull(
286
+ i > end ? asyncFail(none) : asyncSucceed([i, go(i + 1)])
287
+ );
288
+ return go(start);
289
+ }
290
+ function zip(left, right) {
291
+ const pull = asyncFold(
292
+ asyncMapError(uncons(left), (opt) => widenOpt(opt)),
293
+ // si left termina o falla, el zip termina/falla igual
294
+ (opt) => asyncFail(opt),
295
+ ([a, tailL]) => asyncFold(
296
+ asyncMapError(uncons(right), (opt) => widenOpt(opt)),
297
+ (opt) => asyncFail(opt),
298
+ ([b, tailR]) => asyncSucceed([
299
+ [a, b],
300
+ zip(tailL, tailR)
301
+ ])
302
+ )
303
+ );
304
+ return fromPull(pull);
305
+ }
306
+ function foreachStream(stream, f) {
307
+ const loop = (cur) => asyncFold(
308
+ // uncons: Option<E> -> Option<E|E2>
309
+ asyncMapError(uncons(cur), (opt) => widenOpt(opt)),
310
+ (opt) => {
311
+ if (opt._tag === "None") return asyncSucceed(void 0);
312
+ return asyncFail(opt);
313
+ },
314
+ ([a, tail]) => asyncFlatMap(
315
+ // f(a): E2 -> Option<E|E2>
316
+ asyncMapError(f(a), (e2) => some(e2)),
317
+ () => loop(tail)
318
+ )
319
+ );
320
+ return asyncFold(
321
+ loop(stream),
322
+ (opt) => {
323
+ if (opt._tag === "None") return asyncSucceed(void 0);
324
+ return asyncFail(opt.value);
325
+ },
326
+ () => asyncSucceed(void 0)
327
+ );
328
+ }
329
+ function fromArray(values) {
330
+ let s = emptyStream();
331
+ for (let i = values.length - 1; i >= 0; i--) {
332
+ const head = emitStream(succeed(values[i]));
333
+ s = concatStream(head, s);
334
+ }
335
+ return s;
336
+ }
337
+ function collectStream(stream) {
338
+ const loop = (cur, acc) => asyncFold(
339
+ uncons(cur),
340
+ (opt) => {
341
+ if (opt._tag === "None") return succeed(acc);
342
+ return fail(opt);
343
+ },
344
+ ([a, tail]) => loop(tail, [...acc, a])
345
+ );
346
+ return mapError(loop(stream, []), (opt) => {
347
+ if (opt._tag === "Some") return opt.value;
348
+ throw new Error("unreachable: stream end handled as success");
349
+ });
350
+ }
351
+ function readerStream(reader, normalizeError) {
352
+ const pull = async((_, cb) => {
353
+ reader.read().then(({ done, value }) => {
354
+ if (done) {
355
+ cb({ _tag: "Failure", cause: { _tag: "Fail", error: none } });
356
+ return;
357
+ }
358
+ cb({
359
+ _tag: "Success",
360
+ value: [value, fromPull(pull)]
361
+ });
362
+ }).catch((e) => {
363
+ cb({ _tag: "Failure", cause: { _tag: "Fail", error: some(normalizeError(e)) } });
364
+ });
365
+ });
366
+ return fromPull(pull);
367
+ }
368
+ function streamFromReadableStream(body, normalizeError) {
369
+ if (!body) return emptyStream();
370
+ let reader;
371
+ return unwrapScoped(
372
+ // acquire: produce un ZStream
373
+ sync(() => {
374
+ reader = body.getReader();
375
+ return readerStream(reader, normalizeError);
376
+ }),
377
+ // release: se corre en fin / error / interrupción
378
+ () => asyncSync(() => {
379
+ try {
380
+ reader?.cancel();
381
+ } catch {
382
+ }
383
+ })
384
+ );
385
+ }
386
+
387
+ export {
388
+ widenOpt,
389
+ fromPull,
390
+ unwrapScoped,
391
+ managedStream,
392
+ mergeStream,
393
+ emptyStream,
394
+ emitStream,
395
+ concatStream,
396
+ flattenStream,
397
+ merge,
398
+ uncons,
399
+ assertNever,
400
+ mapStream,
401
+ rangeStream,
402
+ zip,
403
+ foreachStream,
404
+ fromArray,
405
+ collectStream,
406
+ streamFromReadableStream
407
+ };