effect 3.3.5 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/Micro/package.json +6 -0
  2. package/dist/cjs/Array.js +18 -3
  3. package/dist/cjs/Array.js.map +1 -1
  4. package/dist/cjs/Chunk.js +13 -2
  5. package/dist/cjs/Chunk.js.map +1 -1
  6. package/dist/cjs/Effect.js +110 -8
  7. package/dist/cjs/Effect.js.map +1 -1
  8. package/dist/cjs/Either.js +31 -1
  9. package/dist/cjs/Either.js.map +1 -1
  10. package/dist/cjs/ManagedRuntime.js.map +1 -1
  11. package/dist/cjs/Micro.js +2383 -0
  12. package/dist/cjs/Micro.js.map +1 -0
  13. package/dist/cjs/Option.js +1 -2
  14. package/dist/cjs/Option.js.map +1 -1
  15. package/dist/cjs/Schedule.js +2 -2
  16. package/dist/cjs/Stream.js.map +1 -1
  17. package/dist/cjs/Tuple.js +16 -9
  18. package/dist/cjs/Tuple.js.map +1 -1
  19. package/dist/cjs/index.js +4 -2
  20. package/dist/cjs/index.js.map +1 -1
  21. package/dist/cjs/internal/core-effect.js +4 -2
  22. package/dist/cjs/internal/core-effect.js.map +1 -1
  23. package/dist/cjs/internal/core.js +12 -2
  24. package/dist/cjs/internal/core.js.map +1 -1
  25. package/dist/cjs/internal/fiberRuntime.js +32 -0
  26. package/dist/cjs/internal/fiberRuntime.js.map +1 -1
  27. package/dist/cjs/internal/stream.js.map +1 -1
  28. package/dist/cjs/internal/version.js +1 -1
  29. package/dist/dts/Array.d.ts +14 -0
  30. package/dist/dts/Array.d.ts.map +1 -1
  31. package/dist/dts/Cause.d.ts +1 -1
  32. package/dist/dts/Chunk.d.ts +11 -0
  33. package/dist/dts/Chunk.d.ts.map +1 -1
  34. package/dist/dts/Effect.d.ts +109 -5
  35. package/dist/dts/Effect.d.ts.map +1 -1
  36. package/dist/dts/Either.d.ts +35 -0
  37. package/dist/dts/Either.d.ts.map +1 -1
  38. package/dist/dts/ManagedRuntime.d.ts +15 -0
  39. package/dist/dts/ManagedRuntime.d.ts.map +1 -1
  40. package/dist/dts/Micro.d.ts +2002 -0
  41. package/dist/dts/Micro.d.ts.map +1 -0
  42. package/dist/dts/Option.d.ts +2 -0
  43. package/dist/dts/Option.d.ts.map +1 -1
  44. package/dist/dts/Schedule.d.ts +2 -2
  45. package/dist/dts/Stream.d.ts +45 -6
  46. package/dist/dts/Stream.d.ts.map +1 -1
  47. package/dist/dts/Tuple.d.ts +18 -0
  48. package/dist/dts/Tuple.d.ts.map +1 -1
  49. package/dist/dts/index.d.ts +7 -0
  50. package/dist/dts/index.d.ts.map +1 -1
  51. package/dist/dts/internal/core-effect.d.ts.map +1 -1
  52. package/dist/dts/internal/core.d.ts.map +1 -1
  53. package/dist/dts/internal/fiberRuntime.d.ts.map +1 -1
  54. package/dist/esm/Array.js +14 -0
  55. package/dist/esm/Array.js.map +1 -1
  56. package/dist/esm/Chunk.js +11 -0
  57. package/dist/esm/Chunk.js.map +1 -1
  58. package/dist/esm/Effect.js +107 -5
  59. package/dist/esm/Effect.js.map +1 -1
  60. package/dist/esm/Either.js +30 -0
  61. package/dist/esm/Either.js.map +1 -1
  62. package/dist/esm/ManagedRuntime.js.map +1 -1
  63. package/dist/esm/Micro.js +2307 -0
  64. package/dist/esm/Micro.js.map +1 -0
  65. package/dist/esm/Option.js +1 -1
  66. package/dist/esm/Option.js.map +1 -1
  67. package/dist/esm/Schedule.js +2 -2
  68. package/dist/esm/Stream.js.map +1 -1
  69. package/dist/esm/Tuple.js +15 -8
  70. package/dist/esm/Tuple.js.map +1 -1
  71. package/dist/esm/index.js +7 -0
  72. package/dist/esm/index.js.map +1 -1
  73. package/dist/esm/internal/core-effect.js +2 -0
  74. package/dist/esm/internal/core-effect.js.map +1 -1
  75. package/dist/esm/internal/core.js +10 -1
  76. package/dist/esm/internal/core.js.map +1 -1
  77. package/dist/esm/internal/fiberRuntime.js +32 -0
  78. package/dist/esm/internal/fiberRuntime.js.map +1 -1
  79. package/dist/esm/internal/stream.js.map +1 -1
  80. package/dist/esm/internal/version.js +1 -1
  81. package/package.json +9 -1
  82. package/src/Array.ts +15 -0
  83. package/src/Cause.ts +1 -1
  84. package/src/Chunk.ts +12 -0
  85. package/src/Effect.ts +117 -5
  86. package/src/Either.ts +51 -0
  87. package/src/ManagedRuntime.ts +16 -0
  88. package/src/Micro.ts +3826 -0
  89. package/src/Option.ts +12 -1
  90. package/src/Schedule.ts +2 -2
  91. package/src/Stream.ts +60 -8
  92. package/src/Tuple.ts +18 -8
  93. package/src/index.ts +8 -0
  94. package/src/internal/core-effect.ts +33 -0
  95. package/src/internal/core.ts +18 -1
  96. package/src/internal/fiberRuntime.ts +32 -0
  97. package/src/internal/stream.ts +8 -4
  98. package/src/internal/version.ts +1 -1
package/src/Micro.ts ADDED
@@ -0,0 +1,3826 @@
1
+ /**
2
+ * A lightweight alternative to the `Effect` data type, with a subset of the functionality.
3
+ *
4
+ * @since 3.4.0
5
+ * @experimental
6
+ */
7
+ import type { Channel, ChannelTypeId } from "./Channel.js"
8
+ import * as Context from "./Context.js"
9
+ import type { Effect, EffectTypeId } from "./Effect.js"
10
+ import * as Effectable from "./Effectable.js"
11
+ import * as Either from "./Either.js"
12
+ import { constTrue, constVoid, dual, identity, type LazyArg } from "./Function.js"
13
+ import { globalValue } from "./GlobalValue.js"
14
+ import type { Inspectable } from "./Inspectable.js"
15
+ import { NodeInspectSymbol, toStringUnknown } from "./Inspectable.js"
16
+ import { StructuralPrototype } from "./internal/effectable.js"
17
+ import { SingleShotGen } from "./internal/singleShotGen.js"
18
+ import * as Option from "./Option.js"
19
+ import { type Pipeable, pipeArguments } from "./Pipeable.js"
20
+ import { isIterable, isTagged, type Predicate, type Refinement } from "./Predicate.js"
21
+ import type { ReadonlyRecord } from "./Record.js"
22
+ import type { Sink, SinkTypeId } from "./Sink.js"
23
+ import type { Stream, StreamTypeId } from "./Stream.js"
24
+ import type { Concurrency, Covariant, Equals, NoInfer, NotFunction, Simplify } from "./Types.js"
25
+ import { YieldWrap, yieldWrapGet } from "./Utils.js"
26
+
27
+ /**
28
+ * @since 3.4.0
29
+ * @experimental
30
+ * @category type ids
31
+ */
32
+ export const TypeId: unique symbol = Symbol.for("effect/Micro")
33
+
34
+ /**
35
+ * @since 3.4.0
36
+ * @experimental
37
+ * @category type ids
38
+ */
39
+ export type TypeId = typeof TypeId
40
+
41
+ /**
42
+ * @since 3.4.0
43
+ * @experimental
44
+ * @category symbols
45
+ */
46
+ export const runSymbol: unique symbol = Symbol.for("effect/Micro/runSymbol")
47
+
48
+ /**
49
+ * @since 3.4.0
50
+ * @experimental
51
+ * @category symbols
52
+ */
53
+ export type runSymbol = typeof runSymbol
54
+
55
+ /**
56
+ * A lightweight alternative to the `Effect` data type, with a subset of the functionality.
57
+ *
58
+ * @since 3.4.0
59
+ * @experimental
60
+ * @category models
61
+ */
62
+ export interface Micro<out A, out E = never, out R = never> extends Effect<A, E, R> {
63
+ readonly [TypeId]: Micro.Variance<A, E, R>
64
+ readonly [runSymbol]: (env: Env<any>, onResult: (result: Result<A, E>) => void) => void
65
+ [Symbol.iterator](): MicroIterator<Micro<A, E, R>>
66
+ }
67
+
68
+ /**
69
+ * @since 3.4.0
70
+ * @experimental
71
+ */
72
+ export declare namespace Micro {
73
+ /**
74
+ * @since 3.4.0
75
+ * @experimental
76
+ */
77
+ export interface Variance<A, E, R> {
78
+ _A: Covariant<A>
79
+ _E: Covariant<E>
80
+ _R: Covariant<R>
81
+ }
82
+
83
+ /**
84
+ * @since 3.4.0
85
+ * @experimental
86
+ */
87
+ export type Success<T> = T extends Micro<infer _A, infer _E, infer _R> ? _A : never
88
+
89
+ /**
90
+ * @since 3.4.0
91
+ * @experimental
92
+ */
93
+ export type Error<T> = T extends Micro<infer _A, infer _E, infer _R> ? _E : never
94
+
95
+ /**
96
+ * @since 3.4.0
97
+ * @experimental
98
+ */
99
+ export type Context<T> = T extends Micro<infer _A, infer _E, infer _R> ? _R : never
100
+ }
101
+
102
+ /**
103
+ * @since 3.4.0
104
+ * @experimental
105
+ * @category guards
106
+ */
107
+ export const isMicro = (u: unknown): u is Micro<any, any, any> => typeof u === "object" && u !== null && TypeId in u
108
+
109
+ /**
110
+ * @since 3.4.0
111
+ * @experimental
112
+ * @category models
113
+ */
114
+ export interface MicroIterator<T extends Micro<any, any, any>> {
115
+ next(...args: ReadonlyArray<any>): IteratorResult<YieldWrap<T>, Micro.Success<T>>
116
+ }
117
+
118
+ // ----------------------------------------------------------------------------
119
+ // Failures
120
+ // ----------------------------------------------------------------------------
121
+
122
+ /**
123
+ * @since 3.4.0
124
+ * @experimental
125
+ * @category failure
126
+ */
127
+ export const FailureTypeId = Symbol.for("effect/Micro/Failure")
128
+
129
+ /**
130
+ * @since 3.4.0
131
+ * @experimental
132
+ * @category failure
133
+ */
134
+ export type FailureTypeId = typeof FailureTypeId
135
+
136
+ /**
137
+ * A Micro Failure is a data type that represents the different ways a Micro can fail.
138
+ *
139
+ * @since 3.4.0
140
+ * @experimental
141
+ * @category failure
142
+ */
143
+ export type Failure<E> = Failure.Unexpected | Failure.Expected<E> | Failure.Aborted
144
+
145
+ /**
146
+ * @since 3.4.0
147
+ * @experimental
148
+ * @category failure
149
+ */
150
+ export declare namespace Failure {
151
+ /**
152
+ * @since 3.4.0
153
+ * @experimental
154
+ */
155
+ export interface Proto<Tag extends string, E> extends Pipeable, globalThis.Error {
156
+ readonly [FailureTypeId]: {
157
+ _E: Covariant<E>
158
+ }
159
+ readonly _tag: Tag
160
+ readonly traces: ReadonlyArray<string>
161
+ }
162
+
163
+ /**
164
+ * @since 3.4.0
165
+ * @experimental
166
+ * @category failure
167
+ */
168
+ export interface Unexpected extends Proto<"Unexpected", never> {
169
+ readonly defect: unknown
170
+ }
171
+
172
+ /**
173
+ * @since 3.4.0
174
+ * @experimental
175
+ * @category failure
176
+ */
177
+ export interface Expected<E> extends Proto<"Expected", E> {
178
+ readonly error: E
179
+ }
180
+
181
+ /**
182
+ * @since 3.4.0
183
+ * @experimental
184
+ * @category failure
185
+ */
186
+ export interface Aborted extends Proto<"Aborted", never> {}
187
+ }
188
+
189
+ const failureVariance = {
190
+ _E: identity
191
+ }
192
+
193
+ abstract class FailureImpl<Tag extends string, E> extends globalThis.Error implements Failure.Proto<Tag, E> {
194
+ readonly [FailureTypeId]: {
195
+ _E: Covariant<E>
196
+ }
197
+ constructor(
198
+ readonly _tag: Tag,
199
+ originalError: unknown,
200
+ readonly traces: ReadonlyArray<string>
201
+ ) {
202
+ const failureName = `Failure${_tag}`
203
+ let name: string
204
+ let message: string
205
+ let stack: string
206
+ if (originalError instanceof globalThis.Error) {
207
+ name = `(${failureName}) ${originalError.name}`
208
+ message = originalError.message as string
209
+ const messageLines = message.split("\n").length
210
+ stack = originalError.stack
211
+ ? `(${failureName}) ${originalError.stack.split("\n").slice(0, messageLines + 3).join("\n")}`
212
+ : `${name}: ${message}`
213
+ } else {
214
+ name = failureName
215
+ message = toStringUnknown(originalError, 0)
216
+ stack = `${name}: ${message}`
217
+ }
218
+ if (traces.length > 0) {
219
+ stack += `\n ${traces.join("\n ")}`
220
+ }
221
+ super(message)
222
+ this[FailureTypeId] = failureVariance
223
+ this.name = name
224
+ this.stack = stack
225
+ }
226
+ pipe() {
227
+ return pipeArguments(this, arguments)
228
+ }
229
+ toString() {
230
+ return this.stack
231
+ }
232
+ [NodeInspectSymbol]() {
233
+ return this.stack
234
+ }
235
+ }
236
+
237
+ class FailureExpectedImpl<E> extends FailureImpl<"Expected", E> implements Failure.Expected<E> {
238
+ constructor(readonly error: E, traces: ReadonlyArray<string> = []) {
239
+ super("Expected", error, traces)
240
+ }
241
+ }
242
+
243
+ /**
244
+ * @since 3.4.0
245
+ * @experimental
246
+ * @category failure
247
+ */
248
+ export const FailureExpected = <E>(error: E, traces: ReadonlyArray<string> = []): Failure<E> =>
249
+ new FailureExpectedImpl(error, traces)
250
+
251
+ class FailureUnexpectedImpl extends FailureImpl<"Unexpected", never> implements Failure.Unexpected {
252
+ constructor(readonly defect: unknown, traces: ReadonlyArray<string> = []) {
253
+ super("Unexpected", defect, traces)
254
+ }
255
+ }
256
+
257
+ /**
258
+ * @since 3.4.0
259
+ * @experimental
260
+ * @category failure
261
+ */
262
+ export const FailureUnexpected = (defect: unknown, traces: ReadonlyArray<string> = []): Failure<never> =>
263
+ new FailureUnexpectedImpl(defect, traces)
264
+
265
+ class FailureAbortedImpl extends FailureImpl<"Aborted", never> implements Failure.Aborted {
266
+ constructor(traces: ReadonlyArray<string> = []) {
267
+ super("Aborted", "aborted", traces)
268
+ }
269
+ }
270
+
271
+ /**
272
+ * @since 3.4.0
273
+ * @experimental
274
+ * @category failure
275
+ */
276
+ export const FailureAborted = (traces: ReadonlyArray<string> = []): Failure<never> => new FailureAbortedImpl(traces)
277
+
278
+ /**
279
+ * @since 3.4.0
280
+ * @experimental
281
+ * @category failure
282
+ */
283
+ export const failureIsExpected = <E>(self: Failure<E>): self is Failure.Expected<E> => self._tag === "Expected"
284
+
285
+ /**
286
+ * @since 3.4.0
287
+ * @experimental
288
+ * @category failure
289
+ */
290
+ export const failureIsUnexpected = <E>(self: Failure<E>): self is Failure.Unexpected => self._tag === "Unexpected"
291
+
292
+ /**
293
+ * @since 3.4.0
294
+ * @experimental
295
+ * @category failure
296
+ */
297
+ export const failureIsAborted = <E>(self: Failure<E>): self is Failure.Aborted => self._tag === "Aborted"
298
+
299
+ /**
300
+ * @since 3.4.0
301
+ * @experimental
302
+ * @category failure
303
+ */
304
+ export const failureSquash = <E>(self: Failure<E>): unknown =>
305
+ self._tag === "Expected" ? self.error : self._tag === "Unexpected" ? self.defect : self
306
+
307
+ /**
308
+ * @since 3.4.0
309
+ * @experimental
310
+ * @category failure
311
+ */
312
+ export const failureWithTrace: {
313
+ (trace: string): <E>(self: Failure<E>) => Failure<E>
314
+ <E>(self: Failure<E>, trace: string): Failure<E>
315
+ } = dual(2, <E>(self: Failure<E>, trace: string): Failure<E> => {
316
+ if (self._tag === "Expected") {
317
+ return FailureExpected(self.error, [...self.traces, trace])
318
+ } else if (self._tag === "Unexpected") {
319
+ return FailureUnexpected(self.defect, [...self.traces, trace])
320
+ }
321
+ return FailureAborted([...self.traces, trace])
322
+ })
323
+
324
+ // ----------------------------------------------------------------------------
325
+ // Result
326
+ // ----------------------------------------------------------------------------
327
+
328
+ /**
329
+ * The Micro Result type is a data type that represents the result of a Micro
330
+ * computation.
331
+ *
332
+ * It uses the `Either` data type to represent the success and failure cases.
333
+ *
334
+ * @since 3.4.0
335
+ * @experimental
336
+ * @category result
337
+ */
338
+ export type Result<A, E = never> = Either.Either<A, Failure<E>>
339
+
340
+ /**
341
+ * @since 3.4.0
342
+ * @experimental
343
+ * @category result
344
+ */
345
+ export const ResultAborted: Result<never> = Either.left(FailureAborted())
346
+
347
+ /**
348
+ * @since 3.4.0
349
+ * @experimental
350
+ * @category result
351
+ */
352
+ export const ResultSuccess: <A>(a: A) => Result<A, never> = Either.right
353
+
354
+ /**
355
+ * @since 3.4.0
356
+ * @experimental
357
+ * @category result
358
+ */
359
+ export const ResultFail = <E>(e: E): Result<never, E> => Either.left(FailureExpected(e))
360
+
361
+ /**
362
+ * @since 3.4.0
363
+ * @experimental
364
+ * @category result
365
+ */
366
+ export const ResultFailUnexpected = (defect: unknown): Result<never> => Either.left(FailureUnexpected(defect))
367
+
368
+ /**
369
+ * @since 3.4.0
370
+ * @experimental
371
+ * @category result
372
+ */
373
+ export const ResultFailWith: <E>(failure: Failure<E>) => Result<never, E> = Either.left
374
+
375
+ /**
376
+ * @since 3.4.0
377
+ * @experimental
378
+ * @category result
379
+ */
380
+ export const resultIsSuccess: <A, E>(self: Result<A, E>) => self is Either.Right<Failure<E>, A> = Either.isRight
381
+
382
+ /**
383
+ * @since 3.4.0
384
+ * @experimental
385
+ * @category result
386
+ */
387
+ export const resultIsFailure: <A, E>(self: Result<A, E>) => self is Either.Left<Failure<E>, A> = Either.isLeft
388
+
389
+ /**
390
+ * @since 3.4.0
391
+ * @experimental
392
+ * @category result
393
+ */
394
+ export const resultIsAborted = <A, E>(self: Result<A, E>): self is Either.Left<Failure.Aborted, A> =>
395
+ resultIsFailure(self) && self.left._tag === "Aborted"
396
+
397
+ /**
398
+ * @since 3.4.0
399
+ * @experimental
400
+ * @category result
401
+ */
402
+ export const resultIsFailureExpected = <A, E>(self: Result<A, E>): self is Either.Left<Failure.Expected<E>, A> =>
403
+ resultIsFailure(self) && self.left._tag === "Expected"
404
+
405
+ /**
406
+ * @since 3.4.0
407
+ * @experimental
408
+ * @category result
409
+ */
410
+ export const resultIsFailureUnexpected = <A, E>(self: Result<A, E>): self is Either.Left<Failure.Unexpected, A> =>
411
+ resultIsFailure(self) && self.left._tag === "Unexpected"
412
+
413
+ /**
414
+ * @since 3.4.0
415
+ * @experimental
416
+ * @category result
417
+ */
418
+ export const resultVoid: Result<void> = ResultSuccess(void 0)
419
+
420
+ // ----------------------------------------------------------------------------
421
+ // env
422
+ // ----------------------------------------------------------------------------
423
+
424
+ /**
425
+ * @since 3.4.0
426
+ * @experimental
427
+ * @category environment
428
+ */
429
+ export const EnvTypeId = Symbol.for("effect/Micro/Env")
430
+
431
+ /**
432
+ * @since 3.4.0
433
+ * @experimental
434
+ * @category environment
435
+ */
436
+ export type EnvTypeId = typeof EnvTypeId
437
+
438
+ /**
439
+ * @since 3.4.0
440
+ * @experimental
441
+ * @category environment
442
+ */
443
+ export interface Env<R> extends Pipeable {
444
+ readonly [EnvTypeId]: {
445
+ _R: Covariant<R>
446
+ }
447
+ readonly refs: ReadonlyRecord<string, unknown>
448
+ }
449
+
450
+ /**
451
+ * @since 3.4.0
452
+ * @experimental
453
+ * @category environment
454
+ */
455
+ export const EnvRefTypeId: unique symbol = Symbol.for("effect/Micro/EnvRef")
456
+
457
+ /**
458
+ * @since 3.4.0
459
+ * @experimental
460
+ * @category environment
461
+ */
462
+ export type EnvRefTypeId = typeof EnvRefTypeId
463
+
464
+ /**
465
+ * @since 3.4.0
466
+ * @experimental
467
+ * @category environment
468
+ */
469
+ export interface EnvRef<A> {
470
+ readonly [EnvRefTypeId]: EnvRefTypeId
471
+ readonly key: string
472
+ readonly initial: A
473
+ }
474
+
475
+ const EnvProto = {
476
+ [EnvTypeId]: {
477
+ _R: identity
478
+ },
479
+ pipe() {
480
+ return pipeArguments(this, arguments)
481
+ }
482
+ }
483
+
484
+ /**
485
+ * @since 3.4.0
486
+ * @experimental
487
+ * @category environment
488
+ */
489
+ export const envMake = <R = never>(
490
+ refs: Record<string, unknown>
491
+ ): Env<R> => {
492
+ const self = Object.create(EnvProto)
493
+ self.refs = refs
494
+ return self
495
+ }
496
+
497
+ /**
498
+ * @since 3.4.0
499
+ * @experimental
500
+ * @category environment
501
+ */
502
+ export const envUnsafeMakeEmpty = (): Env<never> => {
503
+ const controller = new AbortController()
504
+ const refs = Object.create(null)
505
+ refs[currentAbortController.key] = controller
506
+ refs[currentAbortSignal.key] = controller.signal
507
+ return envMake(refs)
508
+ }
509
+
510
+ /**
511
+ * @since 3.4.0
512
+ * @experimental
513
+ * @category environment
514
+ */
515
+ export const envGet: {
516
+ <A>(ref: EnvRef<A>): <R>(self: Env<R>) => A
517
+ <A, R>(self: Env<R>, ref: EnvRef<A>): A
518
+ } = dual(2, <R, A>(self: Env<R>, ref: EnvRef<A>): A => ref.key in self.refs ? (self.refs[ref.key] as A) : ref.initial)
519
+
520
+ /**
521
+ * @since 3.4.0
522
+ * @experimental
523
+ * @category environment
524
+ */
525
+ export const envSet: {
526
+ <A>(ref: EnvRef<A>, value: A): <R>(self: Env<R>) => Env<R>
527
+ <A, R>(self: Env<R>, ref: EnvRef<A>, value: A): Env<R>
528
+ } = dual(3, <R, A>(self: Env<R>, ref: EnvRef<A>, value: A): Env<R> => {
529
+ const refs = Object.assign(Object.create(null), self.refs)
530
+ refs[ref.key] = value
531
+ return envMake(refs)
532
+ })
533
+
534
+ /**
535
+ * @since 3.4.0
536
+ * @experimental
537
+ * @category environment
538
+ */
539
+ export const envMutate: {
540
+ (f: (map: Record<string, unknown>) => void): <R>(self: Env<R>) => Env<R>
541
+ <R>(self: Env<R>, f: (map: Record<string, unknown>) => void): Env<R>
542
+ } = dual(
543
+ 2,
544
+ <R>(self: Env<R>, f: (map: Record<string, unknown>) => ReadonlyRecord<string, unknown>): Env<R> =>
545
+ envMake(f(Object.assign(Object.create(null), self.refs)))
546
+ )
547
+
548
+ /**
549
+ * Access the given `Context.Tag` from the environment.
550
+ *
551
+ * @since 3.4.0
552
+ * @experimental
553
+ * @category environment
554
+ */
555
+ export const service = <I, S>(tag: Context.Tag<I, S>): Micro<S, never, I> =>
556
+ make(function(env, onResult) {
557
+ onResult(ResultSuccess(Context.get(envGet(env, currentContext) as Context.Context<I>, tag as any) as S))
558
+ })
559
+
560
+ /**
561
+ * Access the given `Context.Tag` from the environment, without tracking the
562
+ * dependency at the type level.
563
+ *
564
+ * It will return an `Option` of the service, depending on whether it is
565
+ * available in the environment or not.
566
+ *
567
+ * @since 3.4.0
568
+ * @experimental
569
+ * @category environment
570
+ */
571
+ export const serviceOption = <I, S>(tag: Context.Tag<I, S>): Micro<Option.Option<S>> =>
572
+ make(function(env, onResult) {
573
+ onResult(ResultSuccess(Context.getOption(envGet(env, currentContext) as Context.Context<I>, tag)))
574
+ })
575
+
576
+ /**
577
+ * Retrieve the current value of the given `EnvRef`.
578
+ *
579
+ * @since 3.4.0
580
+ * @experimental
581
+ * @category environment
582
+ */
583
+ export const getEnvRef = <A>(envRef: EnvRef<A>): Micro<A> =>
584
+ make((env, onResult) => onResult(Either.right(envGet(env, envRef))))
585
+
586
+ /**
587
+ * Set the value of the given `EnvRef` for the duration of the effect.
588
+ *
589
+ * @since 3.4.0
590
+ * @experimental
591
+ * @category environment
592
+ */
593
+ export const locally: {
594
+ <A>(fiberRef: EnvRef<A>, value: A): <XA, E, R>(self: Micro<XA, E, R>) => Micro<XA, E, R>
595
+ <XA, E, R, A>(self: Micro<XA, E, R>, fiberRef: EnvRef<A>, value: A): Micro<XA, E, R>
596
+ } = dual(
597
+ 3,
598
+ <XA, E, R, A>(self: Micro<XA, E, R>, fiberRef: EnvRef<A>, value: A): Micro<XA, E, R> =>
599
+ make((env, onResult) => self[runSymbol](envSet(env, fiberRef, value), onResult))
600
+ )
601
+
602
+ /**
603
+ * Access the current `Context` from the environment.
604
+ *
605
+ * @since 3.4.0
606
+ * @experimental
607
+ * @category environment
608
+ */
609
+ export const context = <R>(): Micro<Context.Context<R>> => getEnvRef(currentContext) as any
610
+
611
+ /**
612
+ * Merge the given `Context` with the current context.
613
+ *
614
+ * @since 3.4.0
615
+ * @experimental
616
+ * @category environment
617
+ */
618
+ export const provideContext: {
619
+ <XR>(context: Context.Context<XR>): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, Exclude<R, XR>>
620
+ <A, E, R, XR>(self: Micro<A, E, R>, context: Context.Context<XR>): Micro<A, E, Exclude<R, XR>>
621
+ } = dual(
622
+ 2,
623
+ <A, E, R, XR>(self: Micro<A, E, R>, provided: Context.Context<XR>): Micro<A, E, Exclude<R, XR>> =>
624
+ make(function(env, onResult) {
625
+ const context = envGet(env, currentContext)
626
+ const nextEnv = envSet(env, currentContext, Context.merge(context, provided))
627
+ self[runSymbol](nextEnv, onResult)
628
+ })
629
+ )
630
+
631
+ /**
632
+ * Add the provided service to the current context.
633
+ *
634
+ * @since 3.4.0
635
+ * @experimental
636
+ * @category environment
637
+ */
638
+ export const provideService: {
639
+ <I, S>(tag: Context.Tag<I, S>, service: S): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, Exclude<R, I>>
640
+ <A, E, R, I, S>(self: Micro<A, E, R>, tag: Context.Tag<I, S>, service: S): Micro<A, E, Exclude<R, I>>
641
+ } = dual(
642
+ 3,
643
+ <A, E, R, I, S>(self: Micro<A, E, R>, tag: Context.Tag<I, S>, service: S): Micro<A, E, Exclude<R, I>> =>
644
+ make(function(env, onResult) {
645
+ const context = envGet(env, currentContext)
646
+ const nextEnv = envSet(env, currentContext, Context.add(context, tag, service))
647
+ self[runSymbol](nextEnv, onResult)
648
+ })
649
+ )
650
+
651
+ /**
652
+ * Create a service using the provided `Micro` effect, and add it to the
653
+ * current context.
654
+ *
655
+ * @since 3.4.0
656
+ * @experimental
657
+ * @category environment
658
+ */
659
+ export const provideServiceMicro: {
660
+ <I, S, E2, R2>(
661
+ tag: Context.Tag<I, S>,
662
+ acquire: Micro<S, E2, R2>
663
+ ): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E | E2, Exclude<R, I> | R2>
664
+ <A, E, R, I, S, E2, R2>(
665
+ self: Micro<A, E, R>,
666
+ tag: Context.Tag<I, S>,
667
+ acquire: Micro<S, E2, R2>
668
+ ): Micro<A, E | E2, Exclude<R, I> | R2>
669
+ } = dual(
670
+ 3,
671
+ <A, E, R, I, S, E2, R2>(
672
+ self: Micro<A, E, R>,
673
+ tag: Context.Tag<I, S>,
674
+ acquire: Micro<S, E2, R2>
675
+ ): Micro<A, E | E2, Exclude<R, I> | R2> => flatMap(acquire, (service) => provideService(self, tag, service))
676
+ )
677
+
678
+ // ========================================================================
679
+ // Env refs
680
+ // ========================================================================
681
+
682
+ const EnvRefProto = {
683
+ [EnvRefTypeId]: EnvRefTypeId
684
+ }
685
+
686
+ /**
687
+ * @since 3.4.0
688
+ * @experimental
689
+ * @category environment refs
690
+ */
691
+ export const envRefMake = <A>(key: string, initial: LazyArg<A>): EnvRef<A> =>
692
+ globalValue(key, () => {
693
+ const self = Object.create(EnvRefProto)
694
+ self.key = key
695
+ self.initial = initial()
696
+ return self
697
+ })
698
+
699
+ /**
700
+ * @since 3.4.0
701
+ * @experimental
702
+ * @category environment refs
703
+ */
704
+ export const currentAbortController: EnvRef<AbortController> = envRefMake(
705
+ "effect/Micro/currentAbortController",
706
+ () => new AbortController()
707
+ )
708
+
709
+ /**
710
+ * @since 3.4.0
711
+ * @experimental
712
+ * @category environment refs
713
+ */
714
+ export const currentAbortSignal: EnvRef<AbortSignal> = envRefMake(
715
+ "effect/Micro/currentAbortSignal",
716
+ () => currentAbortController.initial.signal
717
+ )
718
+
719
+ /**
720
+ * @since 3.4.0
721
+ * @experimental
722
+ * @category environment refs
723
+ */
724
+ export const currentContext: EnvRef<Context.Context<never>> = envRefMake(
725
+ "effect/Micro/currentContext",
726
+ () => Context.empty()
727
+ )
728
+
729
+ /**
730
+ * @since 3.4.0
731
+ * @experimental
732
+ * @category environment refs
733
+ */
734
+ export const currentConcurrency: EnvRef<"unbounded" | number> = envRefMake(
735
+ "effect/Micro/currentConcurrency",
736
+ () => "unbounded"
737
+ )
738
+
739
+ /**
740
+ * @since 3.4.0
741
+ * @experimental
742
+ * @category environment refs
743
+ */
744
+ export const currentMaxDepthBeforeYield: EnvRef<number> = envRefMake(
745
+ "effect/Micro/currentMaxDepthBeforeYield",
746
+ () => 2048
747
+ )
748
+
749
+ const currentInterruptible: EnvRef<boolean> = envRefMake(
750
+ "effect/Micro/currentInterruptible",
751
+ () => true
752
+ )
753
+
754
+ /**
755
+ * If you have a `Micro` that uses `concurrency: "inherit"`, you can use this
756
+ * api to control the concurrency of that `Micro` when it is run.
757
+ *
758
+ * @since 3.4.0
759
+ * @experimental
760
+ * @category environment refs
761
+ * @example
762
+ * import * as Micro from "effect/Micro"
763
+ *
764
+ * Micro.forEach([1, 2, 3], (n) => Micro.succeed(n), {
765
+ * concurrency: "inherit"
766
+ * }).pipe(
767
+ * Micro.withConcurrency(2) // use a concurrency of 2
768
+ * )
769
+ */
770
+ export const withConcurrency: {
771
+ (concurrency: "unbounded" | number): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, R>
772
+ <A, E, R>(self: Micro<A, E, R>, concurrency: "unbounded" | number): Micro<A, E, R>
773
+ } = dual(
774
+ 2,
775
+ <A, E, R>(self: Micro<A, E, R>, concurrency: "unbounded" | number): Micro<A, E, R> =>
776
+ locally(self, currentConcurrency, concurrency)
777
+ )
778
+
779
+ // ----------------------------------------------------------------------------
780
+ // constructors
781
+ // ----------------------------------------------------------------------------
782
+
783
+ const MicroProto = {
784
+ ...Effectable.EffectPrototype,
785
+ _op: "Micro",
786
+ [TypeId]: {
787
+ _A: identity,
788
+ _E: identity,
789
+ _R: identity
790
+ },
791
+ [Symbol.iterator]() {
792
+ return new SingleShotGen(new YieldWrap(this)) as any
793
+ }
794
+ }
795
+
796
+ const microDepthState = globalValue("effect/Micro/microDepthState", () => ({
797
+ depth: 0,
798
+ maxDepthBeforeYield: currentMaxDepthBeforeYield.initial
799
+ }))
800
+
801
+ const unsafeMake = <A, E, R>(
802
+ run: (env: Env<R>, onResult: (result: Result<A, E>) => void) => void
803
+ ): Micro<A, E, R> => {
804
+ const self = Object.create(MicroProto)
805
+ self[runSymbol] = run
806
+ return self
807
+ }
808
+
809
+ const unsafeMakeOptions = <A, E, R>(
810
+ run: (env: Env<R>, onResult: (result: Result<A, E>) => void) => void,
811
+ checkAbort: boolean
812
+ ): Micro<A, E, R> =>
813
+ unsafeMake(function execute(env, onResult) {
814
+ if (
815
+ checkAbort && env.refs[currentInterruptible.key] !== false &&
816
+ (env.refs[currentAbortSignal.key] as AbortSignal).aborted
817
+ ) {
818
+ return onResult(ResultAborted)
819
+ }
820
+ microDepthState.depth++
821
+ if (microDepthState.depth === 1) {
822
+ microDepthState.maxDepthBeforeYield = envGet(env, currentMaxDepthBeforeYield)
823
+ }
824
+ if (microDepthState.depth >= microDepthState.maxDepthBeforeYield) {
825
+ yieldAdd(() => execute(env, onResult))
826
+ } else {
827
+ try {
828
+ run(env, onResult)
829
+ } catch (err) {
830
+ onResult(ResultFailUnexpected(err))
831
+ }
832
+ }
833
+ microDepthState.depth--
834
+ })
835
+
836
+ /**
837
+ * A low-level constructor for creating a `Micro` effect. It takes a function
838
+ * that receives an environment and a callback which should be called with the
839
+ * result of the effect.
840
+ *
841
+ * @since 3.4.0
842
+ * @experimental
843
+ * @category constructors
844
+ */
845
+ export const make = <A, E, R>(
846
+ run: (env: Env<R>, onResult: (result: Result<A, E>) => void) => void
847
+ ): Micro<A, E, R> => unsafeMakeOptions(run, true)
848
+
849
+ /**
850
+ * Converts a `Result` into a `Micro` effect.
851
+ *
852
+ * @since 3.4.0
853
+ * @experimental
854
+ * @category constructors
855
+ */
856
+ export const fromResult = <A, E>(self: Result<A, E>): Micro<A, E> =>
857
+ make(function(_env, onResult) {
858
+ onResult(self)
859
+ })
860
+
861
+ /**
862
+ * Converts a lazy `Result` into a `Micro` effect.
863
+ *
864
+ * @since 3.4.0
865
+ * @experimental
866
+ * @category constructors
867
+ */
868
+ export const fromResultSync = <A, E>(self: LazyArg<Result<A, E>>): Micro<A, E> =>
869
+ make(function(_env, onResult) {
870
+ onResult(self())
871
+ })
872
+
873
+ /**
874
+ * Creates a `Micro` effect that will succeed with the specified constant value.
875
+ *
876
+ * @since 3.4.0
877
+ * @experimental
878
+ * @category constructors
879
+ */
880
+ export const succeed = <A>(a: A): Micro<A> => fromResult(ResultSuccess(a))
881
+
882
+ /**
883
+ * Creates a `Micro` effect that will succeed with `Option.Some` of the value.
884
+ *
885
+ * @since 3.4.0
886
+ * @experimental
887
+ * @category constructors
888
+ */
889
+ export const succeedSome = <A>(a: A): Micro<Option.Option<A>> => succeed(Option.some(a))
890
+
891
+ /**
892
+ * Creates a `Micro` effect that will succeed with `Option.None`.
893
+ *
894
+ * @since 3.4.0
895
+ * @experimental
896
+ * @category constructors
897
+ */
898
+ export const succeedNone: Micro<Option.Option<never>> = succeed(Option.none())
899
+
900
+ /**
901
+ * Creates a `Micro` effect that will fail with the specified error.
902
+ *
903
+ * This will result in a `FailureExpected`, where the error is tracked at the
904
+ * type level.
905
+ *
906
+ * @since 3.4.0
907
+ * @experimental
908
+ * @category constructors
909
+ */
910
+ export const fail = <E>(e: E): Micro<never, E> => fromResult(ResultFail(e))
911
+
912
+ /**
913
+ * Creates a `Micro` effect that will fail with the lazily evaluated error.
914
+ *
915
+ * This will result in a `FailureExpected`, where the error is tracked at the
916
+ * type level.
917
+ *
918
+ * @since 3.4.0
919
+ * @experimental
920
+ * @category constructors
921
+ */
922
+ export const failSync = <E>(e: LazyArg<E>): Micro<never, E> =>
923
+ make(function(_env, onResult) {
924
+ onResult(ResultFail(e()))
925
+ })
926
+
927
+ /**
928
+ * Creates a `Micro` effect that will die with the specified error.
929
+ *
930
+ * This will result in a `FailureUnexpected`, where the error is not tracked at
931
+ * the type level.
932
+ *
933
+ * @since 3.4.0
934
+ * @experimental
935
+ * @category constructors
936
+ */
937
+ export const die = (defect: unknown): Micro<never> => fromResult(ResultFailUnexpected(defect))
938
+
939
+ /**
940
+ * Creates a `Micro` effect that will fail with the specified `Failure`.
941
+ *
942
+ * @since 3.4.0
943
+ * @experimental
944
+ * @category constructors
945
+ */
946
+ export const failWith = <E>(failure: Failure<E>): Micro<never, E> => fromResult(ResultFailWith(failure))
947
+
948
+ /**
949
+ * Creates a `Micro` effect that will fail with the lazily evaluated `Failure`.
950
+ *
951
+ * @since 3.4.0
952
+ * @experimental
953
+ * @category constructors
954
+ */
955
+ export const failWithSync = <E>(failure: LazyArg<Failure<E>>): Micro<never, E> =>
956
+ fromResultSync(() => ResultFailWith(failure()))
957
+
958
+ /**
959
+ * Creates a `Micro` effect that will succeed with the lazily evaluated value.
960
+ *
961
+ * If the evaluation of the value throws an error, the effect will fail with
962
+ * `FailureUnexpected`.
963
+ *
964
+ * @since 3.4.0
965
+ * @experimental
966
+ * @category constructors
967
+ */
968
+ export const sync = <A>(evaluate: LazyArg<A>): Micro<A> =>
969
+ make(function(_env, onResult) {
970
+ onResult(ResultSuccess(evaluate()))
971
+ })
972
+
973
+ /**
974
+ * Converts an `Option` into a `Micro` effect, that will fail with a
975
+ * `Option.None` if the option is `None`. Otherwise, it will succeed with the
976
+ * value of the option.
977
+ *
978
+ * @since 3.4.0
979
+ * @experimental
980
+ * @category constructors
981
+ */
982
+ export const fromOption = <A>(option: Option.Option<A>): Micro<A, Option.None<never>> =>
983
+ make(function(_env, onResult) {
984
+ onResult(option._tag === "Some" ? ResultSuccess(option.value) : ResultFail(Option.none()) as any)
985
+ })
986
+
987
+ /**
988
+ * Converts an `Either` into a `Micro` effect, that will fail with the left side
989
+ * of the either if it is a `Left`. Otherwise, it will succeed with the right
990
+ * side of the either.
991
+ *
992
+ * @since 3.4.0
993
+ * @experimental
994
+ * @category constructors
995
+ */
996
+ export const fromEither = <R, L>(either: Either.Either<R, L>): Micro<R, L> =>
997
+ make(function(_env, onResult) {
998
+ onResult(either._tag === "Right" ? either : ResultFail(either.left) as any)
999
+ })
1000
+
1001
+ /**
1002
+ * Lazily creates a `Micro` effect from the given side-effect.
1003
+ *
1004
+ * @since 3.4.0
1005
+ * @experimental
1006
+ * @category constructors
1007
+ */
1008
+ export const suspend = <A, E, R>(evaluate: LazyArg<Micro<A, E, R>>): Micro<A, E, R> =>
1009
+ make(function(env, onResult) {
1010
+ evaluate()[runSymbol](env, onResult)
1011
+ })
1012
+
1013
+ const void_: Micro<void> = succeed(void 0)
1014
+ export {
1015
+ /**
1016
+ * A `Micro` effect that will succeed with `void` (`undefined`).
1017
+ *
1018
+ * @since 3.4.0
1019
+ * @experimental
1020
+ * @category constructors
1021
+ */
1022
+ void_ as void
1023
+ }
1024
+
1025
+ /**
1026
+ * Create a `Micro` effect from an asynchronous computation.
1027
+ *
1028
+ * You can return a cleanup effect that will be run when the effect is aborted.
1029
+ * It is also passed an `AbortSignal` that is triggered when the effect is
1030
+ * aborted.
1031
+ *
1032
+ * @since 3.4.0
1033
+ * @experimental
1034
+ * @category constructors
1035
+ */
1036
+ export const async = <A, E = never, R = never>(
1037
+ register: (resume: (effect: Micro<A, E, R>) => void, signal: AbortSignal) => void | Micro<void, never, R>
1038
+ ): Micro<A, E, R> =>
1039
+ make(function(env, onResult) {
1040
+ let resumed = false
1041
+ const controller = register.length > 1 ? new AbortController() : undefined
1042
+ const signal = envGet(env, currentAbortSignal)
1043
+ let cleanup: Micro<void, never, R> | void = undefined
1044
+ function onAbort() {
1045
+ if (cleanup) {
1046
+ resume(uninterruptible(andThen(cleanup, fromResult(ResultAborted))))
1047
+ } else {
1048
+ resume(fromResult(ResultAborted))
1049
+ }
1050
+ if (controller !== undefined) {
1051
+ controller.abort()
1052
+ }
1053
+ }
1054
+ function resume(effect: Micro<A, E, R>) {
1055
+ if (resumed) {
1056
+ return
1057
+ }
1058
+ resumed = true
1059
+ signal.removeEventListener("abort", onAbort)
1060
+ effect[runSymbol](env, onResult)
1061
+ }
1062
+ cleanup = controller === undefined
1063
+ ? (register as any)(resume)
1064
+ : register(resume, controller.signal)
1065
+ if (resumed) return
1066
+ signal.addEventListener("abort", onAbort)
1067
+ })
1068
+
1069
+ const try_ = <A, E>(options: {
1070
+ try: LazyArg<A>
1071
+ catch: (error: unknown) => E
1072
+ }): Micro<A, E> =>
1073
+ make(function(_env, onResult) {
1074
+ try {
1075
+ onResult(ResultSuccess(options.try()))
1076
+ } catch (err) {
1077
+ onResult(ResultFail(options.catch(err)))
1078
+ }
1079
+ })
1080
+ export {
1081
+ /**
1082
+ * The `Micro` equivalent of a try / catch block, which allows you to map
1083
+ * thrown errors to a specific error type.
1084
+ *
1085
+ * @since 3.4.0
1086
+ * @experimental
1087
+ * @category constructors
1088
+ * @example
1089
+ * import { Micro } from "effect"
1090
+ *
1091
+ * Micro.try({
1092
+ * try: () => throw new Error("boom"),
1093
+ * catch: (cause) => new Error("caught", { cause })
1094
+ * })
1095
+ */
1096
+ try_ as try
1097
+ }
1098
+
1099
+ /**
1100
+ * Wrap a `Promise` into a `Micro` effect. Any errors will result in a
1101
+ * `FailureUnexpected`.
1102
+ *
1103
+ * @since 3.4.0
1104
+ * @experimental
1105
+ * @category constructors
1106
+ */
1107
+ export const promise = <A>(evaluate: (signal: AbortSignal) => PromiseLike<A>): Micro<A> =>
1108
+ async<A>(function(resume, signal) {
1109
+ evaluate(signal).then(
1110
+ (a) => resume(succeed(a)),
1111
+ (e) => resume(die(e))
1112
+ )
1113
+ })
1114
+
1115
+ /**
1116
+ * Wrap a `Promise` into a `Micro` effect. Any errors will be caught and
1117
+ * converted into a specific error type.
1118
+ *
1119
+ * @since 3.4.0
1120
+ * @experimental
1121
+ * @category constructors
1122
+ * @example
1123
+ * import { Micro } from "effect"
1124
+ *
1125
+ * Micro.tryPromise({
1126
+ * try: () => Promise.resolve("success"),
1127
+ * catch: (cause) => new Error("caught", { cause })
1128
+ * })
1129
+ */
1130
+ export const tryPromise = <A, E>(options: {
1131
+ readonly try: (signal: AbortSignal) => PromiseLike<A>
1132
+ readonly catch: (error: unknown) => E
1133
+ }): Micro<A, E> =>
1134
+ async<A, E>(function(resume, signal) {
1135
+ try {
1136
+ options.try(signal).then(
1137
+ (a) => resume(succeed(a)),
1138
+ (e) => resume(fail(options.catch(e)))
1139
+ )
1140
+ } catch (err) {
1141
+ resume(fail(options.catch(err)))
1142
+ }
1143
+ })
1144
+
1145
+ const yieldState: {
1146
+ tasks: Array<() => void>
1147
+ working: boolean
1148
+ } = globalValue("effect/Micro/yieldState", () => ({
1149
+ tasks: [],
1150
+ working: false
1151
+ }))
1152
+
1153
+ const yieldRunTasks = () => {
1154
+ const tasks = yieldState.tasks
1155
+ yieldState.tasks = []
1156
+ for (let i = 0, len = tasks.length; i < len; i++) {
1157
+ tasks[i]()
1158
+ }
1159
+ }
1160
+
1161
+ const setImmediate = "setImmediate" in globalThis ? globalThis.setImmediate : (f: () => void) => setTimeout(f, 0)
1162
+
1163
+ const yieldAdd = (task: () => void) => {
1164
+ yieldState.tasks.push(task)
1165
+ if (!yieldState.working) {
1166
+ yieldState.working = true
1167
+ setImmediate(() => {
1168
+ yieldState.working = false
1169
+ yieldRunTasks()
1170
+ })
1171
+ }
1172
+ }
1173
+
1174
+ /**
1175
+ * Pause the execution of the current `Micro` effect, and resume it on the next
1176
+ * iteration of the event loop.
1177
+ *
1178
+ * @since 3.4.0
1179
+ * @experimental
1180
+ * @category constructors
1181
+ */
1182
+ export const yieldNow: Micro<void> = make(function(_env, onResult) {
1183
+ yieldAdd(() => onResult(resultVoid))
1184
+ })
1185
+
1186
+ /**
1187
+ * Flush any yielded effects that are waiting to be executed.
1188
+ *
1189
+ * @since 3.4.0
1190
+ * @experimental
1191
+ * @category constructors
1192
+ */
1193
+ export const yieldFlush: Micro<void> = sync(function() {
1194
+ while (yieldState.tasks.length > 0) {
1195
+ yieldRunTasks()
1196
+ }
1197
+ })
1198
+
1199
+ /**
1200
+ * A `Micro` that will never succeed or fail. It wraps `setInterval` to prevent
1201
+ * the Javascript runtime from exiting.
1202
+ *
1203
+ * @since 3.4.0
1204
+ * @experimental
1205
+ * @category constructors
1206
+ */
1207
+ export const never: Micro<never> = async<never>(function() {
1208
+ const interval = setInterval(constVoid, 2147483646)
1209
+ return sync(() => clearInterval(interval))
1210
+ })
1211
+
1212
+ /**
1213
+ * @since 3.4.0
1214
+ * @experimental
1215
+ * @category constructors
1216
+ */
1217
+ export const gen = <Eff extends YieldWrap<Micro<any, any, any>>, AEff>(
1218
+ f: () => Generator<Eff, AEff, never>
1219
+ ): Micro<
1220
+ AEff,
1221
+ [Eff] extends [never] ? never : [Eff] extends [YieldWrap<Micro<infer _A, infer E, infer _R>>] ? E : never,
1222
+ [Eff] extends [never] ? never : [Eff] extends [YieldWrap<Micro<infer _A, infer _E, infer R>>] ? R : never
1223
+ > =>
1224
+ make(function(env, onResult) {
1225
+ const iterator = f() as Iterator<YieldWrap<Micro<any, any, any>>, AEff, any>
1226
+ let running = false
1227
+ let value: any = undefined
1228
+ function run() {
1229
+ running = true
1230
+ try {
1231
+ let shouldContinue = true
1232
+ while (shouldContinue) {
1233
+ const result = iterator.next(value)
1234
+ if (result.done) {
1235
+ return onResult(ResultSuccess(result.value))
1236
+ }
1237
+ shouldContinue = false
1238
+ yieldWrapGet(result.value)[runSymbol](env, function(result) {
1239
+ if (result._tag === "Left") {
1240
+ onResult(result)
1241
+ } else {
1242
+ shouldContinue = true
1243
+ value = result.right
1244
+ if (!running) run()
1245
+ }
1246
+ })
1247
+ }
1248
+ } catch (err) {
1249
+ onResult(ResultFailUnexpected(err))
1250
+ }
1251
+ running = false
1252
+ }
1253
+ run()
1254
+ })
1255
+
1256
+ // ----------------------------------------------------------------------------
1257
+ // mapping & sequencing
1258
+ // ----------------------------------------------------------------------------
1259
+
1260
+ /**
1261
+ * Flattens any nested `Micro` effects, merging the error and requirement types.
1262
+ *
1263
+ * @since 3.4.0
1264
+ * @experimental
1265
+ * @category mapping & sequencing
1266
+ */
1267
+ export const flatten = <A, E, R, E2, R2>(self: Micro<Micro<A, E, R>, E2, R2>): Micro<A, E | E2, R | R2> =>
1268
+ make(function(env, onResult) {
1269
+ self[runSymbol](
1270
+ env,
1271
+ (result) => result._tag === "Left" ? onResult(result as any) : result.right[runSymbol](env, onResult)
1272
+ )
1273
+ })
1274
+
1275
+ /**
1276
+ * Transforms the success value of the `Micro` effect with the specified
1277
+ * function.
1278
+ *
1279
+ * @since 3.4.0
1280
+ * @experimental
1281
+ * @category mapping & sequencing
1282
+ */
1283
+ export const map: {
1284
+ <A, B>(f: (a: A) => B): <E, R>(self: Micro<A, E, R>) => Micro<B, E, R>
1285
+ <A, E, R, B>(self: Micro<A, E, R>, f: (a: A) => B): Micro<B, E, R>
1286
+ } = dual(2, <A, E, R, B>(self: Micro<A, E, R>, f: (a: A) => B): Micro<B, E, R> =>
1287
+ make(function(env, onResult) {
1288
+ self[runSymbol](env, function(result) {
1289
+ onResult(result._tag === "Left" ? result as any : ResultSuccess(f(result.right)))
1290
+ })
1291
+ }))
1292
+
1293
+ /**
1294
+ * Create a `Micro` effect that will replace the success value of the given
1295
+ * effect.
1296
+ *
1297
+ * @since 3.4.0
1298
+ * @experimental
1299
+ * @category mapping & sequencing
1300
+ */
1301
+ export const as: {
1302
+ <A, B>(value: B): <E, R>(self: Micro<A, E, R>) => Micro<B, E, R>
1303
+ <A, E, R, B>(self: Micro<A, E, R>, value: B): Micro<B, E, R>
1304
+ } = dual(2, <A, E, R, B>(self: Micro<A, E, R>, value: B): Micro<B, E, R> => map(self, (_) => value))
1305
+
1306
+ /**
1307
+ * Wrap the success value of this `Micro` effect in an `Option.Some`.
1308
+ *
1309
+ * @since 3.4.0
1310
+ * @experimental
1311
+ * @category mapping & sequencing
1312
+ */
1313
+ export const asSome = <A, E, R>(self: Micro<A, E, R>): Micro<Option.Option<A>, E, R> => map(self, Option.some) as any
1314
+
1315
+ /**
1316
+ * Map the success value of this `Micro` effect to another `Micro` effect, then
1317
+ * flatten the result.
1318
+ *
1319
+ * @since 3.4.0
1320
+ * @experimental
1321
+ * @category mapping & sequencing
1322
+ */
1323
+ export const flatMap: {
1324
+ <A, B, E2, R2>(f: (a: A) => Micro<B, E2, R2>): <E, R>(self: Micro<A, E, R>) => Micro<B, E | E2, R | R2>
1325
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<B, E | E2, R | R2>
1326
+ } = dual(
1327
+ 2,
1328
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<B, E | E2, R | R2> =>
1329
+ make(function(env, onResult) {
1330
+ self[runSymbol](env, function(result) {
1331
+ if (result._tag === "Left") {
1332
+ return onResult(result as any)
1333
+ }
1334
+ f(result.right)[runSymbol](env, onResult)
1335
+ })
1336
+ })
1337
+ )
1338
+
1339
+ /**
1340
+ * Swap the error and success types of the `Micro` effect.
1341
+ *
1342
+ * @since 3.4.0
1343
+ * @experimental
1344
+ * @category mapping & sequencing
1345
+ */
1346
+ export const flip = <A, E, R>(self: Micro<A, E, R>): Micro<E, A, R> =>
1347
+ matchMicro(self, {
1348
+ onFailure: succeed,
1349
+ onSuccess: fail
1350
+ })
1351
+
1352
+ /**
1353
+ * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
1354
+ * a single api.
1355
+ *
1356
+ * It also allows you to pass in a `Micro` effect directly, which will be
1357
+ * executed after the current effect.
1358
+ *
1359
+ * @since 3.4.0
1360
+ * @experimental
1361
+ * @category mapping & sequencing
1362
+ */
1363
+ export const andThen: {
1364
+ <A, X>(
1365
+ f: (a: A) => X
1366
+ ): <E, R>(
1367
+ self: Micro<A, E, R>
1368
+ ) => [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1369
+ : Micro<X, E, R>
1370
+ <X>(
1371
+ f: NotFunction<X>
1372
+ ): <A, E, R>(
1373
+ self: Micro<A, E, R>
1374
+ ) => [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1375
+ : Micro<X, E, R>
1376
+ <A, E, R, X>(
1377
+ self: Micro<A, E, R>,
1378
+ f: (a: A) => X
1379
+ ): [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1380
+ : Micro<X, E, R>
1381
+ <A, E, R, X>(
1382
+ self: Micro<A, E, R>,
1383
+ f: NotFunction<X>
1384
+ ): [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1385
+ : Micro<X, E, R>
1386
+ } = dual(
1387
+ 2,
1388
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: any): Micro<B, E | E2, R | R2> =>
1389
+ make(function(env, onResult) {
1390
+ self[runSymbol](env, function(result) {
1391
+ if (result._tag === "Left") {
1392
+ return onResult(result as any)
1393
+ } else if (envGet(env, currentAbortSignal).aborted) {
1394
+ return onResult(ResultAborted)
1395
+ }
1396
+ const value = isMicro(f) ? f : typeof f === "function" ? f(result.right) : f
1397
+ if (isMicro(value)) {
1398
+ value[runSymbol](env, onResult)
1399
+ } else {
1400
+ onResult(ResultSuccess(value))
1401
+ }
1402
+ })
1403
+ })
1404
+ )
1405
+
1406
+ /**
1407
+ * Execute a side effect from the success value of the `Micro` effect.
1408
+ *
1409
+ * It is similar to the `andThen` api, but the success value is ignored.
1410
+ *
1411
+ * @since 3.4.0
1412
+ * @experimental
1413
+ * @category mapping & sequencing
1414
+ */
1415
+ export const tap: {
1416
+ <A, X>(
1417
+ f: (a: NoInfer<A>) => X
1418
+ ): <E, R>(
1419
+ self: Micro<A, E, R>
1420
+ ) => [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1421
+ : Micro<A, E, R>
1422
+ <X>(
1423
+ f: NotFunction<X>
1424
+ ): <A, E, R>(
1425
+ self: Micro<A, E, R>
1426
+ ) => [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1427
+ : Micro<A, E, R>
1428
+ <A, E, R, X>(
1429
+ self: Micro<A, E, R>,
1430
+ f: (a: NoInfer<A>) => X
1431
+ ): [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1432
+ : Micro<A, E, R>
1433
+ <A, E, R, X>(
1434
+ self: Micro<A, E, R>,
1435
+ f: NotFunction<X>
1436
+ ): [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1437
+ : Micro<A, E, R>
1438
+ } = dual(
1439
+ 2,
1440
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2> =>
1441
+ make(function(env, onResult) {
1442
+ self[runSymbol](env, function(selfResult) {
1443
+ if (selfResult._tag === "Left") {
1444
+ return onResult(selfResult as any)
1445
+ } else if (envGet(env, currentAbortSignal).aborted) {
1446
+ return onResult(ResultAborted)
1447
+ }
1448
+ const value = isMicro(f) ? f : typeof f === "function" ? f(selfResult.right) : f
1449
+ if (isMicro(value)) {
1450
+ value[runSymbol](env, function(tapResult) {
1451
+ if (tapResult._tag === "Left") {
1452
+ return onResult(tapResult)
1453
+ }
1454
+ onResult(selfResult)
1455
+ })
1456
+ } else {
1457
+ onResult(selfResult)
1458
+ }
1459
+ })
1460
+ })
1461
+ )
1462
+
1463
+ /**
1464
+ * Replace the success value of the `Micro` effect with `void`.
1465
+ *
1466
+ * @since 3.4.0
1467
+ * @experimental
1468
+ * @category mapping & sequencing
1469
+ */
1470
+ export const asVoid = <A, E, R>(self: Micro<A, E, R>): Micro<void, E, R> => map(self, (_) => void 0)
1471
+
1472
+ /**
1473
+ * Access the `Result` of the given `Micro` effect.
1474
+ *
1475
+ * @since 3.4.0
1476
+ * @experimental
1477
+ * @category mapping & sequencing
1478
+ */
1479
+ export const asResult = <A, E, R>(self: Micro<A, E, R>): Micro<Result<A, E>, never, R> =>
1480
+ make(function(env, onResult) {
1481
+ self[runSymbol](env, function(result) {
1482
+ onResult(ResultSuccess(result))
1483
+ })
1484
+ })
1485
+
1486
+ /**
1487
+ * Replace the error type of the given `Micro` with the full `Failure` object.
1488
+ *
1489
+ * @since 3.4.0
1490
+ * @experimental
1491
+ * @category mapping & sequencing
1492
+ */
1493
+ export const sandbox = <A, E, R>(self: Micro<A, E, R>): Micro<A, Failure<E>, R> =>
1494
+ catchFailure(self, (failure) => fail(failure))
1495
+
1496
+ function forkSignal(env: Env<any>) {
1497
+ const controller = new AbortController()
1498
+ const parentSignal = envGet(env, currentAbortSignal)
1499
+ function onAbort() {
1500
+ controller.abort()
1501
+ parentSignal.removeEventListener("abort", onAbort)
1502
+ }
1503
+ parentSignal.addEventListener("abort", onAbort)
1504
+ const envWithSignal = envMutate(env, function(refs) {
1505
+ refs[currentAbortController.key] = controller
1506
+ refs[currentAbortSignal.key] = controller.signal
1507
+ return refs
1508
+ })
1509
+ return [envWithSignal, onAbort] as const
1510
+ }
1511
+
1512
+ /**
1513
+ * Returns an effect that races all the specified effects,
1514
+ * yielding the value of the first effect to succeed with a value. Losers of
1515
+ * the race will be interrupted immediately
1516
+ *
1517
+ * @since 3.4.0
1518
+ * @experimental
1519
+ * @category sequencing
1520
+ */
1521
+ export const raceAll = <Eff extends Micro<any, any, any>>(
1522
+ all: Iterable<Eff>
1523
+ ): Micro<Micro.Success<Eff>, Micro.Error<Eff>, Micro.Context<Eff>> =>
1524
+ make(function(env, onResult) {
1525
+ const [envWithSignal, onAbort] = forkSignal(env)
1526
+
1527
+ const effects = Array.from(all)
1528
+ let len = effects.length
1529
+ let index = 0
1530
+ let done = 0
1531
+ let result: Result<any, any> | undefined = undefined
1532
+ const failures: Array<Failure<any>> = []
1533
+ function onDone(result_: Result<any, any>) {
1534
+ done++
1535
+ if (result_._tag === "Right" && result === undefined) {
1536
+ len = index
1537
+ result = result_
1538
+ onAbort()
1539
+ } else if (result_._tag === "Left") {
1540
+ failures.push(result_.left)
1541
+ }
1542
+ if (done >= len) {
1543
+ onResult(result ?? Either.left(failures[0]))
1544
+ }
1545
+ }
1546
+
1547
+ for (; index < len; index++) {
1548
+ effects[index][runSymbol](envWithSignal, onDone)
1549
+ }
1550
+ })
1551
+
1552
+ /**
1553
+ * Returns an effect that races all the specified effects,
1554
+ * yielding the value of the first effect to succeed or fail. Losers of
1555
+ * the race will be interrupted immediately
1556
+ *
1557
+ * @since 3.4.0
1558
+ * @experimental
1559
+ * @category sequencing
1560
+ */
1561
+ export const raceAllFirst = <Eff extends Micro<any, any, any>>(
1562
+ all: Iterable<Eff>
1563
+ ): Micro<Micro.Success<Eff>, Micro.Error<Eff>, Micro.Context<Eff>> =>
1564
+ make(function(env, onResult) {
1565
+ const [envWithSignal, onAbort] = forkSignal(env)
1566
+
1567
+ const effects = Array.from(all)
1568
+ let len = effects.length
1569
+ let index = 0
1570
+ let done = 0
1571
+ let result: Result<any, any> | undefined = undefined
1572
+ const failures: Array<Failure<any>> = []
1573
+ function onDone(result_: Result<any, any>) {
1574
+ done++
1575
+ if (result === undefined) {
1576
+ len = index
1577
+ result = result_
1578
+ onAbort()
1579
+ }
1580
+ if (done >= len) {
1581
+ onResult(result ?? Either.left(failures[0]))
1582
+ }
1583
+ }
1584
+
1585
+ for (; index < len; index++) {
1586
+ effects[index][runSymbol](envWithSignal, onDone)
1587
+ }
1588
+ })
1589
+
1590
+ /**
1591
+ * Returns an effect that races two effects, yielding the value of the first
1592
+ * effect to succeed. Losers of the race will be interrupted immediately
1593
+ *
1594
+ * @since 3.4.0
1595
+ * @experimental
1596
+ * @category sequencing
1597
+ */
1598
+ export const race: {
1599
+ <A2, E2, R2>(that: Micro<A2, E2, R2>): <A, E, R>(self: Micro<A, E, R>) => Micro<A | A2, E | E2, R | R2>
1600
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2>
1601
+ } = dual(
1602
+ 2,
1603
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2> =>
1604
+ raceAll([self, that])
1605
+ )
1606
+
1607
+ /**
1608
+ * Returns an effect that races two effects, yielding the value of the first
1609
+ * effect to succeed *or* fail. Losers of the race will be interrupted immediately
1610
+ *
1611
+ * @since 3.4.0
1612
+ * @experimental
1613
+ * @category sequencing
1614
+ */
1615
+ export const raceFirst: {
1616
+ <A2, E2, R2>(that: Micro<A2, E2, R2>): <A, E, R>(self: Micro<A, E, R>) => Micro<A | A2, E | E2, R | R2>
1617
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2>
1618
+ } = dual(
1619
+ 2,
1620
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2> =>
1621
+ raceAllFirst([self, that])
1622
+ )
1623
+
1624
+ // ----------------------------------------------------------------------------
1625
+ // zipping
1626
+ // ----------------------------------------------------------------------------
1627
+
1628
+ /**
1629
+ * Combine two `Micro` effects into a single effect that produces a tuple of
1630
+ * their results.
1631
+ *
1632
+ * @since 3.4.0
1633
+ * @experimental
1634
+ * @category zipping
1635
+ */
1636
+ export const zip: {
1637
+ <A2, E2, R2>(
1638
+ that: Micro<A2, E2, R2>,
1639
+ options?:
1640
+ | { readonly concurrent?: boolean | undefined }
1641
+ | undefined
1642
+ ): <A, E, R>(self: Micro<A, E, R>) => Micro<[A, A2], E2 | E, R2 | R>
1643
+ <A, E, R, A2, E2, R2>(
1644
+ self: Micro<A, E, R>,
1645
+ that: Micro<A2, E2, R2>,
1646
+ options?:
1647
+ | { readonly concurrent?: boolean | undefined }
1648
+ | undefined
1649
+ ): Micro<[A, A2], E | E2, R | R2>
1650
+ } = dual((args) => isMicro(args[1]), <A, E, R, A2, E2, R2>(
1651
+ self: Micro<A, E, R>,
1652
+ that: Micro<A2, E2, R2>,
1653
+ options?:
1654
+ | { readonly concurrent?: boolean | undefined }
1655
+ | undefined
1656
+ ): Micro<[A, A2], E | E2, R | R2> => {
1657
+ if (options?.concurrent) {
1658
+ return all([self, that], { concurrency: "unbounded" })
1659
+ }
1660
+ return flatMap(self, (a) => map(that, (a2) => [a, a2]))
1661
+ })
1662
+
1663
+ // ----------------------------------------------------------------------------
1664
+ // filtering & conditionals
1665
+ // ----------------------------------------------------------------------------
1666
+
1667
+ /**
1668
+ * Filter the specified effect with the provided function, failing with specified
1669
+ * `Failure` if the predicate fails.
1670
+ *
1671
+ * In addition to the filtering capabilities discussed earlier, you have the option to further
1672
+ * refine and narrow down the type of the success channel by providing a
1673
+ *
1674
+ * @since 3.4.0
1675
+ * @experimental
1676
+ * @category filtering & conditionals
1677
+ */
1678
+ export const filterOrFailWith: {
1679
+ <A, B extends A, E2>(
1680
+ refinement: Refinement<A, B>,
1681
+ orFailWith: (a: NoInfer<A>) => Failure<E2>
1682
+ ): <E, R>(self: Micro<A, E, R>) => Micro<B, E2 | E, R>
1683
+ <A, E2>(
1684
+ predicate: Predicate<NoInfer<A>>,
1685
+ orFailWith: (a: NoInfer<A>) => Failure<E2>
1686
+ ): <E, R>(self: Micro<A, E, R>) => Micro<A, E2 | E, R>
1687
+ <A, E, R, B extends A, E2>(
1688
+ self: Micro<A, E, R>,
1689
+ refinement: Refinement<A, B>,
1690
+ orFailWith: (a: A) => Failure<E2>
1691
+ ): Micro<B, E | E2, R>
1692
+ <A, E, R, E2>(self: Micro<A, E, R>, predicate: Predicate<A>, orFailWith: (a: A) => Failure<E2>): Micro<A, E | E2, R>
1693
+ } = dual((args) => isMicro(args[0]), <A, E, R, B extends A, E2>(
1694
+ self: Micro<A, E, R>,
1695
+ refinement: Refinement<A, B>,
1696
+ orFailWith: (a: A) => Failure<E2>
1697
+ ): Micro<B, E | E2, R> => flatMap(self, (a) => refinement(a) ? succeed(a as any) : failWith(orFailWith(a))))
1698
+
1699
+ /**
1700
+ * Filter the specified effect with the provided function, failing with specified
1701
+ * error if the predicate fails.
1702
+ *
1703
+ * In addition to the filtering capabilities discussed earlier, you have the option to further
1704
+ * refine and narrow down the type of the success channel by providing a
1705
+ *
1706
+ * @since 3.4.0
1707
+ * @experimental
1708
+ * @category filtering & conditionals
1709
+ */
1710
+ export const filterOrFail: {
1711
+ <A, B extends A, E2>(
1712
+ refinement: Refinement<A, B>,
1713
+ orFailWith: (a: NoInfer<A>) => E2
1714
+ ): <E, R>(self: Micro<A, E, R>) => Micro<B, E2 | E, R>
1715
+ <A, E2>(
1716
+ predicate: Predicate<NoInfer<A>>,
1717
+ orFailWith: (a: NoInfer<A>) => E2
1718
+ ): <E, R>(self: Micro<A, E, R>) => Micro<A, E2 | E, R>
1719
+ <A, E, R, B extends A, E2>(
1720
+ self: Micro<A, E, R>,
1721
+ refinement: Refinement<A, B>,
1722
+ orFailWith: (a: A) => E2
1723
+ ): Micro<B, E | E2, R>
1724
+ <A, E, R, E2>(self: Micro<A, E, R>, predicate: Predicate<A>, orFailWith: (a: A) => E2): Micro<A, E | E2, R>
1725
+ } = dual((args) => isMicro(args[0]), <A, E, R, B extends A, E2>(
1726
+ self: Micro<A, E, R>,
1727
+ refinement: Refinement<A, B>,
1728
+ orFailWith: (a: A) => E2
1729
+ ): Micro<B, E | E2, R> => flatMap(self, (a) => refinement(a) ? succeed(a as any) : fail(orFailWith(a))))
1730
+
1731
+ /**
1732
+ * The moral equivalent of `if (p) exp`.
1733
+ *
1734
+ * @since 3.4.0
1735
+ * @experimental
1736
+ * @category filtering & conditionals
1737
+ */
1738
+ export const when: {
1739
+ <E2 = never, R2 = never>(
1740
+ condition: LazyArg<boolean> | Micro<boolean, E2, R2>
1741
+ ): <A, E, R>(self: Micro<A, E, R>) => Micro<Option.Option<A>, E | E2, R | R2>
1742
+ <A, E, R, E2 = never, R2 = never>(
1743
+ self: Micro<A, E, R>,
1744
+ condition: LazyArg<boolean> | Micro<boolean, E2, R2>
1745
+ ): Micro<Option.Option<A>, E | E2, R | R2>
1746
+ } = dual(
1747
+ 2,
1748
+ <A, E, R, E2 = never, R2 = never>(
1749
+ self: Micro<A, E, R>,
1750
+ condition: LazyArg<boolean> | Micro<boolean, E2, R2>
1751
+ ): Micro<Option.Option<A>, E | E2, R | R2> =>
1752
+ flatMap(isMicro(condition) ? condition : sync(condition), (pass) => pass ? asSome(self) : succeed(Option.none()))
1753
+ )
1754
+
1755
+ // ----------------------------------------------------------------------------
1756
+ // repetition
1757
+ // ----------------------------------------------------------------------------
1758
+
1759
+ /**
1760
+ * Repeat the given `Micro` using the provided options.
1761
+ *
1762
+ * The `while` predicate will be checked after each iteration, and can use the
1763
+ * fall `Result` of the effect to determine if the repetition should continue.
1764
+ *
1765
+ * @since 3.4.0
1766
+ * @experimental
1767
+ * @category repetition
1768
+ */
1769
+ export const repeatResult: {
1770
+ <A, E>(options: {
1771
+ while: Predicate<Result<A, E>>
1772
+ times?: number | undefined
1773
+ delay?: DelayFn | undefined
1774
+ }): <R>(self: Micro<A, E, R>) => Micro<A, E, R>
1775
+ <A, E, R>(self: Micro<A, E, R>, options: {
1776
+ while: Predicate<Result<A, E>>
1777
+ times?: number | undefined
1778
+ delay?: DelayFn | undefined
1779
+ }): Micro<A, E, R>
1780
+ } = dual(2, <A, E, R>(self: Micro<A, E, R>, options: {
1781
+ while: Predicate<Result<A, E>>
1782
+ times?: number | undefined
1783
+ delay?: DelayFn | undefined
1784
+ }): Micro<A, E, R> =>
1785
+ make(function(env, onResult) {
1786
+ const startedAt = options.delay ? Date.now() : 0
1787
+ let attempt = 0
1788
+ self[runSymbol](env, function loop(result) {
1789
+ if (options.while !== undefined && !options.while(result)) {
1790
+ return onResult(result)
1791
+ } else if (options.times !== undefined && attempt >= options.times) {
1792
+ return onResult(result)
1793
+ }
1794
+ attempt++
1795
+ let delayEffect = yieldNow
1796
+ if (options.delay !== undefined) {
1797
+ const elapsed = Date.now() - startedAt
1798
+ const duration = options.delay(attempt, elapsed)
1799
+ if (Option.isNone(duration)) {
1800
+ return onResult(result)
1801
+ }
1802
+ delayEffect = sleep(duration.value)
1803
+ }
1804
+ delayEffect[runSymbol](env, function(result) {
1805
+ if (result._tag === "Left") {
1806
+ return onResult(result as any)
1807
+ }
1808
+ self[runSymbol](env, loop)
1809
+ })
1810
+ })
1811
+ }))
1812
+
1813
+ /**
1814
+ * Repeat the given `Micro` effect using the provided options. Only successful
1815
+ * results will be repeated.
1816
+ *
1817
+ * @since 3.4.0
1818
+ * @experimental
1819
+ * @category repetition
1820
+ */
1821
+ export const repeat: {
1822
+ <A, E>(
1823
+ options?: {
1824
+ while?: Predicate<A> | undefined
1825
+ times?: number | undefined
1826
+ delay?: DelayFn | undefined
1827
+ } | undefined
1828
+ ): <R>(self: Micro<A, E, R>) => Micro<A, E, R>
1829
+ <A, E, R>(
1830
+ self: Micro<A, E, R>,
1831
+ options?: {
1832
+ while?: Predicate<A> | undefined
1833
+ times?: number | undefined
1834
+ delay?: DelayFn | undefined
1835
+ } | undefined
1836
+ ): Micro<A, E, R>
1837
+ } = dual((args) => isMicro(args[0]), <A, E, R>(
1838
+ self: Micro<A, E, R>,
1839
+ options?: {
1840
+ while?: Predicate<A> | undefined
1841
+ times?: number | undefined
1842
+ delay?: DelayFn | undefined
1843
+ } | undefined
1844
+ ): Micro<A, E, R> =>
1845
+ repeatResult(self, {
1846
+ ...options,
1847
+ while: (result) => result._tag === "Right" && (options?.while === undefined || options.while(result.right))
1848
+ }))
1849
+
1850
+ /**
1851
+ * Repeat the given `Micro` effect forever, only stopping if the effect fails.
1852
+ *
1853
+ * @since 3.4.0
1854
+ * @experimental
1855
+ * @category repetition
1856
+ */
1857
+ export const forever = <A, E, R>(self: Micro<A, E, R>): Micro<never, E, R> => repeat(self) as any
1858
+
1859
+ // ----------------------------------------------------------------------------
1860
+ // delay fn
1861
+ // ----------------------------------------------------------------------------
1862
+
1863
+ /**
1864
+ * Represents a function that can be used to calculate the delay between
1865
+ * repeats.
1866
+ *
1867
+ * The function takes the current attempt number and the elapsed time since
1868
+ * the first attempt, and returns the delay for the next attempt. If the
1869
+ * function returns `None`, the repetition will stop.
1870
+ *
1871
+ * @since 3.4.0
1872
+ * @experimental
1873
+ * @category delay fn
1874
+ */
1875
+ export type DelayFn = (attempt: number, elapsed: number) => Option.Option<number>
1876
+
1877
+ /**
1878
+ * Create a `DelayFn` that will generate a duration with an exponential backoff.
1879
+ *
1880
+ * @since 3.4.0
1881
+ * @experimental
1882
+ * @category delay fn
1883
+ */
1884
+ export const delayExponential = (baseMillis: number, factor = 2): DelayFn => (attempt) =>
1885
+ Option.some(attempt ** factor * baseMillis)
1886
+
1887
+ /**
1888
+ * Create a `DelayFn` that will generate a duration with fixed intervals.
1889
+ *
1890
+ * @since 3.4.0
1891
+ * @experimental
1892
+ * @category delay fn
1893
+ */
1894
+ export const delaySpaced = (millis: number): DelayFn => (_) => Option.some(millis)
1895
+
1896
+ /**
1897
+ * Transform a `DelayFn` to one that will have a duration that will never exceed
1898
+ * the specified maximum.
1899
+ *
1900
+ * @since 3.4.0
1901
+ * @experimental
1902
+ * @category delay fn
1903
+ */
1904
+ export const delayWithMax: {
1905
+ (max: number): (self: DelayFn) => DelayFn
1906
+ (self: DelayFn, max: number): DelayFn
1907
+ } = dual(
1908
+ 2,
1909
+ (self: DelayFn, max: number): DelayFn => (attempt, elapsed) =>
1910
+ Option.map(self(attempt, elapsed), (duration) => Math.min(duration, max))
1911
+ )
1912
+
1913
+ /**
1914
+ * Transform a `DelayFn` to one that will stop repeating after the specified
1915
+ * amount of time.
1916
+ *
1917
+ * @since 3.4.0
1918
+ * @experimental
1919
+ * @category delay fn
1920
+ */
1921
+ export const delayWithMaxElapsed: {
1922
+ (max: number): (self: DelayFn) => DelayFn
1923
+ (self: DelayFn, max: number): DelayFn
1924
+ } = dual(
1925
+ 2,
1926
+ (self: DelayFn, max: number): DelayFn => (attempt, elapsed) => elapsed < max ? self(attempt, elapsed) : Option.none()
1927
+ )
1928
+
1929
+ /**
1930
+ * Transform a `DelayFn` to one that will stop repeating after the specified
1931
+ * number of attempts.
1932
+ *
1933
+ * @since 3.4.0
1934
+ * @experimental
1935
+ * @category delay fn
1936
+ */
1937
+ export const delayWithRecurs: {
1938
+ (n: number): (self: DelayFn) => DelayFn
1939
+ (self: DelayFn, n: number): DelayFn
1940
+ } = dual(
1941
+ 2,
1942
+ (self: DelayFn, n: number): DelayFn => (attempt, elapsed) => Option.filter(self(attempt, elapsed), () => attempt <= n)
1943
+ )
1944
+
1945
+ // ----------------------------------------------------------------------------
1946
+ // error handling
1947
+ // ----------------------------------------------------------------------------
1948
+
1949
+ /**
1950
+ * Catch the full `Failure` object of the given `Micro` effect, allowing you to
1951
+ * recover from any kind of failure.
1952
+ *
1953
+ * @since 3.4.0
1954
+ * @experimental
1955
+ * @category error handling
1956
+ */
1957
+ export const catchFailure: {
1958
+ <E, B, E2, R2>(
1959
+ f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
1960
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
1961
+ <A, E, R, B, E2, R2>(
1962
+ self: Micro<A, E, R>,
1963
+ f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
1964
+ ): Micro<A | B, E2, R | R2>
1965
+ } = dual(
1966
+ 2,
1967
+ <A, E, R, B, E2, R2>(
1968
+ self: Micro<A, E, R>,
1969
+ f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
1970
+ ): Micro<A | B, E2, R | R2> => catchFailureIf(self, constTrue, f)
1971
+ )
1972
+
1973
+ /**
1974
+ * Selectively catch a `Failure` object of the given `Micro` effect,
1975
+ * using the provided predicate to determine if the failure should be caught.
1976
+ *
1977
+ * @since 3.4.0
1978
+ * @experimental
1979
+ * @category error handling
1980
+ */
1981
+ export const catchFailureIf: {
1982
+ <E, B, E2, R2, EB extends Failure<E>>(
1983
+ refinement: Refinement<Failure<E>, EB>,
1984
+ f: (failure: EB) => Micro<B, E2, R2>
1985
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
1986
+ <E, B, E2, R2>(
1987
+ predicate: Predicate<Failure<NoInfer<E>>>,
1988
+ f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
1989
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
1990
+ <A, E, R, B, E2, R2, EB extends Failure<E>>(
1991
+ self: Micro<A, E, R>,
1992
+ refinement: Refinement<Failure<E>, EB>,
1993
+ f: (failure: EB) => Micro<B, E2, R2>
1994
+ ): Micro<A | B, E2, R | R2>
1995
+ <A, E, R, B, E2, R2>(
1996
+ self: Micro<A, E, R>,
1997
+ predicate: Predicate<Failure<NoInfer<E>>>,
1998
+ f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
1999
+ ): Micro<A | B, E2, R | R2>
2000
+ } = dual(3, <A, E, R, B, E2, R2, EB extends Failure<E>>(
2001
+ self: Micro<A, E, R>,
2002
+ refinement: Refinement<Failure<E>, EB>,
2003
+ f: (failure: EB) => Micro<B, E2, R2>
2004
+ ): Micro<A | B, E2, R | R2> =>
2005
+ make(function(env, onResult) {
2006
+ self[runSymbol](env, function(result) {
2007
+ if (result._tag === "Right" || !refinement(result.left)) {
2008
+ return onResult(result as any)
2009
+ }
2010
+ f(result.left)[runSymbol](env, onResult)
2011
+ })
2012
+ }))
2013
+
2014
+ /**
2015
+ * Catch the error of the given `Micro` effect, allowing you to recover from it.
2016
+ *
2017
+ * It only catches expected (`FailureExpected`) errors.
2018
+ *
2019
+ * @since 3.4.0
2020
+ * @experimental
2021
+ * @category error handling
2022
+ */
2023
+ export const catchExpected: {
2024
+ <E, B, E2, R2>(
2025
+ f: (e: NoInfer<E>) => Micro<B, E2, R2>
2026
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
2027
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (e: NoInfer<E>) => Micro<B, E2, R2>): Micro<A | B, E2, R | R2>
2028
+ } = dual(
2029
+ 2,
2030
+ <A, E, R, B, E2, R2>(
2031
+ self: Micro<A, E, R>,
2032
+ f: (a: NoInfer<E>) => Micro<B, E2, R2>
2033
+ ): Micro<A | B, E2, R | R2> => catchFailureIf(self, failureIsExpected, (failure) => f(failure.error))
2034
+ )
2035
+
2036
+ /**
2037
+ * Catch any unexpected errors of the given `Micro` effect, allowing you to recover from them.
2038
+ *
2039
+ * @since 3.4.0
2040
+ * @experimental
2041
+ * @category error handling
2042
+ */
2043
+ export const catchUnexpected: {
2044
+ <E, B, E2, R2>(
2045
+ f: (defect: unknown) => Micro<B, E2, R2>
2046
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E | E2, R | R2>
2047
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (defect: unknown) => Micro<B, E2, R2>): Micro<A | B, E | E2, R | R2>
2048
+ } = dual(
2049
+ 2,
2050
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (defect: unknown) => Micro<B, E2, R2>): Micro<A | B, E | E2, R | R2> =>
2051
+ catchFailureIf(self, failureIsUnexpected, (failure) => f(failure.defect))
2052
+ )
2053
+
2054
+ /**
2055
+ * Perform a side effect using the full `Failure` object of the given `Micro`.
2056
+ *
2057
+ * @since 3.4.0
2058
+ * @experimental
2059
+ * @category error handling
2060
+ */
2061
+ export const tapFailure: {
2062
+ <E, B, E2, R2>(
2063
+ f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>
2064
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
2065
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2>
2066
+ } = dual(
2067
+ 2,
2068
+ <A, E, R, B, E2, R2>(
2069
+ self: Micro<A, E, R>,
2070
+ f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>
2071
+ ): Micro<A, E | E2, R | R2> => tapFailureIf(self, constTrue, f)
2072
+ )
2073
+
2074
+ /**
2075
+ * Perform a side effect using if a `Failure` object matches the specified
2076
+ * predicate.
2077
+ *
2078
+ * @since 3.4.0
2079
+ * @experimental
2080
+ * @category error handling
2081
+ */
2082
+ export const tapFailureIf: {
2083
+ <E, B, E2, R2, EB extends Failure<E>>(
2084
+ refinement: Refinement<Failure<E>, EB>,
2085
+ f: (a: EB) => Micro<B, E2, R2>
2086
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
2087
+ <E, B, E2, R2>(
2088
+ predicate: (failure: NoInfer<Failure<E>>) => boolean,
2089
+ f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>
2090
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
2091
+ <A, E, R, B, E2, R2, EB extends Failure<E>>(
2092
+ self: Micro<A, E, R>,
2093
+ refinement: Refinement<Failure<E>, EB>,
2094
+ f: (a: EB) => Micro<B, E2, R2>
2095
+ ): Micro<A, E | E2, R | R2>
2096
+ <A, E, R, B, E2, R2>(
2097
+ self: Micro<A, E, R>,
2098
+ predicate: (failure: NoInfer<Failure<E>>) => boolean,
2099
+ f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>
2100
+ ): Micro<A, E | E2, R | R2>
2101
+ } = dual(
2102
+ 3,
2103
+ <A, E, R, B, E2, R2, EB extends Failure<E>>(
2104
+ self: Micro<A, E, R>,
2105
+ refinement: Refinement<Failure<E>, EB>,
2106
+ f: (a: EB) => Micro<B, E2, R2>
2107
+ ): Micro<A, E | E2, R | R2> =>
2108
+ catchFailureIf(self, refinement, (failure) => andThen(f(failure as any), failWith(failure)))
2109
+ )
2110
+
2111
+ /**
2112
+ * Perform a side effect from expected errors of the given `Micro`.
2113
+ *
2114
+ * @since 3.4.0
2115
+ * @experimental
2116
+ * @category error handling
2117
+ */
2118
+ export const tapExpected: {
2119
+ <E, B, E2, R2>(
2120
+ f: (a: NoInfer<E>) => Micro<B, E2, R2>
2121
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
2122
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: NoInfer<E>) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2>
2123
+ } = dual(
2124
+ 2,
2125
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: NoInfer<E>) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2> =>
2126
+ tapFailureIf(self, failureIsExpected, (failure) => f(failure.error))
2127
+ )
2128
+
2129
+ /**
2130
+ * Perform a side effect from unexpected errors of the given `Micro`.
2131
+ *
2132
+ * @since 3.4.0
2133
+ * @experimental
2134
+ * @category error handling
2135
+ */
2136
+ export const tapUnexpected: {
2137
+ <E, B, E2, R2>(
2138
+ f: (defect: unknown) => Micro<B, E2, R2>
2139
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
2140
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (defect: unknown) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2>
2141
+ } = dual(
2142
+ 2,
2143
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (defect: unknown) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2> =>
2144
+ tapFailureIf(self, failureIsUnexpected, (failure) => f(failure.defect))
2145
+ )
2146
+
2147
+ /**
2148
+ * Catch any expected errors that match the specified predicate.
2149
+ *
2150
+ * @since 3.4.0
2151
+ * @experimental
2152
+ * @category error handling
2153
+ */
2154
+ export const catchIf: {
2155
+ <E, EB extends E, B, E2, R2>(
2156
+ pred: Refinement<E, EB>,
2157
+ f: (a: NoInfer<EB>) => Micro<B, E2, R2>
2158
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
2159
+ <E, B, E2, R2>(
2160
+ pred: Predicate<NoInfer<E>>,
2161
+ f: (a: NoInfer<E>) => Micro<B, E2, R2>
2162
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
2163
+ <A, E, R, EB extends E, B, E2, R2>(
2164
+ self: Micro<A, E, R>,
2165
+ pred: Refinement<E, EB>,
2166
+ f: (a: NoInfer<EB>) => Micro<B, E2, R2>
2167
+ ): Micro<A | B, E2, R | R2>
2168
+ <A, E, R, B, E2, R2>(
2169
+ self: Micro<A, E, R>,
2170
+ pred: Predicate<NoInfer<E>>,
2171
+ f: (a: NoInfer<E>) => Micro<B, E2, R2>
2172
+ ): Micro<A | B, E2, R | R2>
2173
+ } = dual(
2174
+ 3,
2175
+ <A, E, R, EB extends E, B, E2, R2>(
2176
+ self: Micro<A, E, R>,
2177
+ pred: Refinement<E, EB>,
2178
+ f: (a: NoInfer<EB>) => Micro<B, E2, R2>
2179
+ ): Micro<A | B, E2, R | R2> =>
2180
+ catchFailureIf(
2181
+ self,
2182
+ (f): f is Failure.Expected<EB> => failureIsExpected(f) && pred(f.error),
2183
+ (failure) => f(failure.error)
2184
+ )
2185
+ )
2186
+
2187
+ /**
2188
+ * Recovers from the specified tagged error.
2189
+ *
2190
+ * @since 3.4.0
2191
+ * @experimental
2192
+ * @category error handling
2193
+ */
2194
+ export const catchTag: {
2195
+ <K extends E extends { _tag: string } ? E["_tag"] : never, E, A1, E1, R1>(
2196
+ k: K,
2197
+ f: (e: Extract<E, { _tag: K }>) => Micro<A1, E1, R1>
2198
+ ): <A, R>(self: Micro<A, E, R>) => Micro<A1 | A, E1 | Exclude<E, { _tag: K }>, R1 | R>
2199
+ <A, E, R, K extends E extends { _tag: string } ? E["_tag"] : never, R1, E1, A1>(
2200
+ self: Micro<A, E, R>,
2201
+ k: K,
2202
+ f: (e: Extract<E, { _tag: K }>) => Micro<A1, E1, R1>
2203
+ ): Micro<A | A1, E1 | Exclude<E, { _tag: K }>, R | R1>
2204
+ } = dual(3, <A, E, R, K extends E extends { _tag: string } ? E["_tag"] : never, R1, E1, A1>(
2205
+ self: Micro<A, E, R>,
2206
+ k: K,
2207
+ f: (e: Extract<E, { _tag: K }>) => Micro<A1, E1, R1>
2208
+ ): Micro<A | A1, E1 | Exclude<E, { _tag: K }>, R | R1> => catchIf(self, (error) => isTagged(error, k), f as any))
2209
+
2210
+ /**
2211
+ * Transform the full `Failure` object of the given `Micro` effect.
2212
+ *
2213
+ * @since 3.4.0
2214
+ * @experimental
2215
+ * @category error handling
2216
+ */
2217
+ export const mapFailure: {
2218
+ <E, E2>(f: (a: Failure<E>) => Failure<E2>): <A, R>(self: Micro<A, E, R>) => Micro<A, E2, R>
2219
+ <A, E, R, E2>(self: Micro<A, E, R>, f: (a: Failure<E>) => Failure<E2>): Micro<A, E2, R>
2220
+ } = dual(
2221
+ 2,
2222
+ <A, E, R, E2>(self: Micro<A, E, R>, f: (a: Failure<E>) => Failure<E2>): Micro<A, E2, R> =>
2223
+ catchFailure(self, (failure) => failWith(f(failure)))
2224
+ )
2225
+
2226
+ /**
2227
+ * Transform any expected errors of the given `Micro` effect.
2228
+ *
2229
+ * @since 3.4.0
2230
+ * @experimental
2231
+ * @category error handling
2232
+ */
2233
+ export const mapError: {
2234
+ <E, E2>(f: (a: E) => E2): <A, R>(self: Micro<A, E, R>) => Micro<A, E2, R>
2235
+ <A, E, R, E2>(self: Micro<A, E, R>, f: (a: E) => E2): Micro<A, E2, R>
2236
+ } = dual(
2237
+ 2,
2238
+ <A, E, R, E2>(self: Micro<A, E, R>, f: (a: E) => E2): Micro<A, E2, R> =>
2239
+ catchExpected(self, (error) => fail(f(error)))
2240
+ )
2241
+
2242
+ /**
2243
+ * Elevate any expected errors of the given `Micro` effect to unexpected errors,
2244
+ * resulting in an error type of `never`.
2245
+ *
2246
+ * @since 3.4.0
2247
+ * @experimental
2248
+ * @category error handling
2249
+ */
2250
+ export const orDie = <A, E, R>(self: Micro<A, E, R>): Micro<A, never, R> => catchExpected(self, die)
2251
+
2252
+ /**
2253
+ * Recover from all errors by succeeding with the given value.
2254
+ *
2255
+ * @since 3.4.0
2256
+ * @experimental
2257
+ * @category error handling
2258
+ */
2259
+ export const orElseSucceed: {
2260
+ <B>(f: LazyArg<B>): <A, E, R>(self: Micro<A, E, R>) => Micro<A | B, never, R>
2261
+ <A, E, R, B>(self: Micro<A, E, R>, f: LazyArg<B>): Micro<A | B, never, R>
2262
+ } = dual(
2263
+ 2,
2264
+ <A, E, R, B>(self: Micro<A, E, R>, f: LazyArg<B>): Micro<A | B, never, R> => catchExpected(self, (_) => sync(f))
2265
+ )
2266
+
2267
+ /**
2268
+ * Ignore any expected errors of the given `Micro` effect, returning `void`.
2269
+ *
2270
+ * @since 3.4.0
2271
+ * @experimental
2272
+ * @category error handling
2273
+ */
2274
+ export const ignore = <A, E, R>(self: Micro<A, E, R>): Micro<void, never, R> =>
2275
+ matchMicro(self, { onFailure: (_) => void_, onSuccess: (_) => void_ })
2276
+
2277
+ /**
2278
+ * Ignore any expected errors of the given `Micro` effect, returning `void`.
2279
+ *
2280
+ * @since 3.4.0
2281
+ * @experimental
2282
+ * @category error handling
2283
+ */
2284
+ export const ignoreLogged = <A, E, R>(self: Micro<A, E, R>): Micro<void, never, R> =>
2285
+ matchMicro(self, {
2286
+ onFailure: (failure) => sync(() => console.error(failure)),
2287
+ onSuccess: (_) => void_
2288
+ })
2289
+
2290
+ /**
2291
+ * Replace the success value of the given `Micro` effect with an `Option`,
2292
+ * wrapping the success value in `Some` and returning `None` if the effect fails
2293
+ * with an expected error.
2294
+ *
2295
+ * @since 3.4.0
2296
+ * @experimental
2297
+ * @category error handling
2298
+ */
2299
+ export const option = <A, E, R>(self: Micro<A, E, R>): Micro<Option.Option<A>, never, R> =>
2300
+ match(self, { onFailure: (_) => Option.none(), onSuccess: Option.some })
2301
+
2302
+ /**
2303
+ * Replace the success value of the given `Micro` effect with an `Either`,
2304
+ * wrapping the success value in `Right` and wrapping any expected errors with
2305
+ * a `Left`.
2306
+ *
2307
+ * @since 3.4.0
2308
+ * @experimental
2309
+ * @category error handling
2310
+ */
2311
+ export const either = <A, E, R>(self: Micro<A, E, R>): Micro<Either.Either<A, E>, never, R> =>
2312
+ match(self, { onFailure: Either.left, onSuccess: Either.right })
2313
+
2314
+ /**
2315
+ * Retry the given `Micro` effect using the provided options.
2316
+ *
2317
+ * @since 3.4.0
2318
+ * @experimental
2319
+ * @category error handling
2320
+ */
2321
+ export const retry: {
2322
+ <A, E>(
2323
+ options?: {
2324
+ while?: Predicate<E> | undefined
2325
+ times?: number | undefined
2326
+ delay?: DelayFn | undefined
2327
+ } | undefined
2328
+ ): <R>(self: Micro<A, E, R>) => Micro<A, E, R>
2329
+ <A, E, R>(
2330
+ self: Micro<A, E, R>,
2331
+ options?: {
2332
+ while?: Predicate<E> | undefined
2333
+ times?: number | undefined
2334
+ delay?: DelayFn | undefined
2335
+ } | undefined
2336
+ ): Micro<A, E, R>
2337
+ } = dual((args) => isMicro(args[0]), <A, E, R>(
2338
+ self: Micro<A, E, R>,
2339
+ options?: {
2340
+ while?: Predicate<E> | undefined
2341
+ times?: number | undefined
2342
+ delay?: DelayFn | undefined
2343
+ } | undefined
2344
+ ): Micro<A, E, R> =>
2345
+ repeatResult(self, {
2346
+ ...options,
2347
+ while: (result) =>
2348
+ result._tag === "Left" && result.left._tag === "Expected" &&
2349
+ (options?.while === undefined || options.while(result.left.error))
2350
+ }))
2351
+
2352
+ /**
2353
+ * Add a stack trace to any failures that occur in the effect. The trace will be
2354
+ * added to the `traces` field of the `Failure` object.
2355
+ *
2356
+ * @since 3.4.0
2357
+ * @experimental
2358
+ * @category error handling
2359
+ */
2360
+ export const withTrace: {
2361
+ (name: string): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, R>
2362
+ <A, E, R>(self: Micro<A, E, R>, name: string): Micro<A, E, R>
2363
+ } = function() {
2364
+ const prevLimit = globalThis.Error.stackTraceLimit
2365
+ globalThis.Error.stackTraceLimit = 2
2366
+ const error = new globalThis.Error()
2367
+ globalThis.Error.stackTraceLimit = prevLimit
2368
+ function generate(name: string, failure: Failure<any>) {
2369
+ const stack = error.stack
2370
+ if (!stack) {
2371
+ return failure
2372
+ }
2373
+ const line = stack.split("\n")[2]?.trim().replace(/^at /, "")
2374
+ if (!line) {
2375
+ return failure
2376
+ }
2377
+ const lineMatch = line.match(/\((.*)\)$/)
2378
+ return failureWithTrace(failure, `at ${name} (${lineMatch ? lineMatch[1] : line})`)
2379
+ }
2380
+ const f = (name: string) => (self: Micro<any, any, any>) =>
2381
+ unsafeMakeOptions(function(env, onResult) {
2382
+ self[runSymbol](env, function(result) {
2383
+ onResult(result._tag === "Left" ? Either.left(generate(name, result.left)) : result)
2384
+ })
2385
+ }, false)
2386
+ if (arguments.length === 2) {
2387
+ return f(arguments[1])(arguments[0])
2388
+ }
2389
+ return f(arguments[0])
2390
+ } as any
2391
+
2392
+ // ----------------------------------------------------------------------------
2393
+ // pattern matching
2394
+ // ----------------------------------------------------------------------------
2395
+
2396
+ /**
2397
+ * @since 3.4.0
2398
+ * @experimental
2399
+ * @category pattern matching
2400
+ */
2401
+ export const matchFailureMicro: {
2402
+ <E, A2, E2, R2, A, A3, E3, R3>(
2403
+ options: {
2404
+ readonly onFailure: (failure: Failure<E>) => Micro<A2, E2, R2>
2405
+ readonly onSuccess: (a: A) => Micro<A3, E3, R3>
2406
+ }
2407
+ ): <R>(self: Micro<A, E, R>) => Micro<A2 | A3, E2 | E3, R2 | R3 | R>
2408
+ <A, E, R, A2, E2, R2, A3, E3, R3>(
2409
+ self: Micro<A, E, R>,
2410
+ options: {
2411
+ readonly onFailure: (failure: Failure<E>) => Micro<A2, E2, R2>
2412
+ readonly onSuccess: (a: A) => Micro<A3, E3, R3>
2413
+ }
2414
+ ): Micro<A2 | A3, E2 | E3, R2 | R3 | R>
2415
+ } = dual(
2416
+ 2,
2417
+ <A, E, R, A2, E2, R2, A3, E3, R3>(
2418
+ self: Micro<A, E, R>,
2419
+ options: {
2420
+ readonly onFailure: (failure: Failure<E>) => Micro<A2, E2, R2>
2421
+ readonly onSuccess: (a: A) => Micro<A3, E3, R3>
2422
+ }
2423
+ ): Micro<A2 | A3, E2 | E3, R2 | R3 | R> =>
2424
+ make(function(env, onResult) {
2425
+ self[runSymbol](env, function(result) {
2426
+ try {
2427
+ const next = result._tag === "Left" ? options.onFailure(result.left) : options.onSuccess(result.right)
2428
+ next[runSymbol](env, onResult)
2429
+ } catch (err) {
2430
+ onResult(ResultFailUnexpected(err))
2431
+ }
2432
+ })
2433
+ })
2434
+ )
2435
+
2436
+ /**
2437
+ * @since 3.4.0
2438
+ * @experimental
2439
+ * @category pattern matching
2440
+ */
2441
+ export const matchFailure: {
2442
+ <E, A2, A, A3>(
2443
+ options: {
2444
+ readonly onFailure: (failure: Failure<E>) => A2
2445
+ readonly onSuccess: (a: A) => A3
2446
+ }
2447
+ ): <R>(self: Micro<A, E, R>) => Micro<A2 | A3, never, R>
2448
+ <A, E, R, A2, A3>(
2449
+ self: Micro<A, E, R>,
2450
+ options: {
2451
+ readonly onFailure: (failure: Failure<E>) => A2
2452
+ readonly onSuccess: (a: A) => A3
2453
+ }
2454
+ ): Micro<A2 | A3, never, R>
2455
+ } = dual(
2456
+ 2,
2457
+ <A, E, R, A2, A3>(
2458
+ self: Micro<A, E, R>,
2459
+ options: {
2460
+ readonly onFailure: (failure: Failure<E>) => A2
2461
+ readonly onSuccess: (a: A) => A3
2462
+ }
2463
+ ): Micro<A2 | A3, never, R> =>
2464
+ matchFailureMicro(self, {
2465
+ onFailure: (failure) => sync(() => options.onFailure(failure)),
2466
+ onSuccess: (value) => sync(() => options.onSuccess(value))
2467
+ })
2468
+ )
2469
+
2470
+ /**
2471
+ * @since 3.4.0
2472
+ * @experimental
2473
+ * @category pattern matching
2474
+ */
2475
+ export const matchMicro: {
2476
+ <E, A2, E2, R2, A, A3, E3, R3>(
2477
+ options: {
2478
+ readonly onFailure: (e: E) => Micro<A2, E2, R2>
2479
+ readonly onSuccess: (a: A) => Micro<A3, E3, R3>
2480
+ }
2481
+ ): <R>(self: Micro<A, E, R>) => Micro<A2 | A3, E2 | E3, R2 | R3 | R>
2482
+ <A, E, R, A2, E2, R2, A3, E3, R3>(
2483
+ self: Micro<A, E, R>,
2484
+ options: {
2485
+ readonly onFailure: (e: E) => Micro<A2, E2, R2>
2486
+ readonly onSuccess: (a: A) => Micro<A3, E3, R3>
2487
+ }
2488
+ ): Micro<A2 | A3, E2 | E3, R2 | R3 | R>
2489
+ } = dual(
2490
+ 2,
2491
+ <A, E, R, A2, E2, R2, A3, E3, R3>(
2492
+ self: Micro<A, E, R>,
2493
+ options: {
2494
+ readonly onFailure: (e: E) => Micro<A2, E2, R2>
2495
+ readonly onSuccess: (a: A) => Micro<A3, E3, R3>
2496
+ }
2497
+ ): Micro<A2 | A3, E2 | E3, R2 | R3 | R> =>
2498
+ matchFailureMicro(self, {
2499
+ onFailure: (failure) => failure._tag === "Expected" ? options.onFailure(failure.error) : failWith(failure),
2500
+ onSuccess: options.onSuccess
2501
+ })
2502
+ )
2503
+
2504
+ /**
2505
+ * @since 3.4.0
2506
+ * @experimental
2507
+ * @category pattern matching
2508
+ */
2509
+ export const match: {
2510
+ <E, A2, A, A3>(
2511
+ options: {
2512
+ readonly onFailure: (error: E) => A2
2513
+ readonly onSuccess: (value: A) => A3
2514
+ }
2515
+ ): <R>(self: Micro<A, E, R>) => Micro<A2 | A3, never, R>
2516
+ <A, E, R, A2, A3>(
2517
+ self: Micro<A, E, R>,
2518
+ options: {
2519
+ readonly onFailure: (error: E) => A2
2520
+ readonly onSuccess: (value: A) => A3
2521
+ }
2522
+ ): Micro<A2 | A3, never, R>
2523
+ } = dual(
2524
+ 2,
2525
+ <A, E, R, A2, A3>(
2526
+ self: Micro<A, E, R>,
2527
+ options: {
2528
+ readonly onFailure: (error: E) => A2
2529
+ readonly onSuccess: (value: A) => A3
2530
+ }
2531
+ ): Micro<A2 | A3, never, R> =>
2532
+ matchMicro(self, {
2533
+ onFailure: (error) => sync(() => options.onFailure(error)),
2534
+ onSuccess: (value) => sync(() => options.onSuccess(value))
2535
+ })
2536
+ )
2537
+
2538
+ // ----------------------------------------------------------------------------
2539
+ // delays & timeouts
2540
+ // ----------------------------------------------------------------------------
2541
+
2542
+ /**
2543
+ * Create a `Micro` effect that will sleep for the specified duration.
2544
+ *
2545
+ * @since 3.4.0
2546
+ * @experimental
2547
+ * @category delays & timeouts
2548
+ */
2549
+ export const sleep = (millis: number): Micro<void> =>
2550
+ async(function(resume) {
2551
+ const timeout = setTimeout(function() {
2552
+ resume(void_)
2553
+ }, millis)
2554
+ return sync(() => {
2555
+ return clearTimeout(timeout)
2556
+ })
2557
+ })
2558
+
2559
+ /**
2560
+ * Returns an effect that will delay the execution of this effect by the
2561
+ * specified duration.
2562
+ *
2563
+ * @since 3.4.0
2564
+ * @experimental
2565
+ * @category delays & timeouts
2566
+ */
2567
+ export const delay: {
2568
+ (millis: number): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, R>
2569
+ <A, E, R>(self: Micro<A, E, R>, millis: number): Micro<A, E, R>
2570
+ } = dual(
2571
+ 2,
2572
+ <A, E, R>(self: Micro<A, E, R>, millis: number): Micro<A, E, R> => andThen(sleep(millis), self)
2573
+ )
2574
+
2575
+ /**
2576
+ * Returns an effect that will timeout this effect, that will execute the
2577
+ * fallback effect if the timeout elapses before the effect has produced a value.
2578
+ *
2579
+ * If the timeout elapses, the running effect will be safely interrupted.
2580
+ *
2581
+ * @since 3.4.0
2582
+ * @experimental
2583
+ * @category delays & timeouts
2584
+ */
2585
+ export const timeoutOrElse: {
2586
+ <A2, E2, R2>(options: {
2587
+ readonly duration: number
2588
+ readonly onTimeout: LazyArg<Micro<A2, E2, R2>>
2589
+ }): <A, E, R>(self: Micro<A, E, R>) => Micro<A | A2, E | E2, R | R2>
2590
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, options: {
2591
+ readonly duration: number
2592
+ readonly onTimeout: LazyArg<Micro<A2, E2, R2>>
2593
+ }): Micro<A | A2, E | E2, R | R2>
2594
+ } = dual(
2595
+ 2,
2596
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, options: {
2597
+ readonly duration: number
2598
+ readonly onTimeout: LazyArg<Micro<A2, E2, R2>>
2599
+ }): Micro<A | A2, E | E2, R | R2> =>
2600
+ raceFirst(self, andThen(interruptible(sleep(options.duration)), options.onTimeout))
2601
+ )
2602
+
2603
+ /**
2604
+ * Returns an effect that will timeout this effect, succeeding with a `None`
2605
+ * if the timeout elapses before the effect has produced a value; and `Some` of
2606
+ * the produced value otherwise.
2607
+ *
2608
+ * If the timeout elapses, the running effect will be safely interrupted.
2609
+ *
2610
+ * @since 3.4.0
2611
+ * @experimental
2612
+ * @category delays & timeouts
2613
+ */
2614
+ export const timeout: {
2615
+ (millis: number): <A, E, R>(self: Micro<A, E, R>) => Micro<Option.Option<A>, E, R>
2616
+ <A, E, R>(self: Micro<A, E, R>, millis: number): Micro<Option.Option<A>, E, R>
2617
+ } = dual(
2618
+ 2,
2619
+ <A, E, R>(self: Micro<A, E, R>, millis: number): Micro<Option.Option<A>, E, R> =>
2620
+ raceFirst(
2621
+ asSome(self),
2622
+ as(interruptible(sleep(millis)), Option.none())
2623
+ )
2624
+ )
2625
+
2626
+ // ----------------------------------------------------------------------------
2627
+ // resources & finalization
2628
+ // ----------------------------------------------------------------------------
2629
+
2630
+ /**
2631
+ * @since 3.4.0
2632
+ * @experimental
2633
+ * @category resources & finalization
2634
+ */
2635
+ export const MicroScopeTypeId: unique symbol = Symbol.for("effect/Micro/MicroScope")
2636
+
2637
+ /**
2638
+ * @since 3.4.0
2639
+ * @experimental
2640
+ * @category resources & finalization
2641
+ */
2642
+ export type MicroScopeTypeId = typeof MicroScopeTypeId
2643
+
2644
+ /**
2645
+ * @since 3.4.0
2646
+ * @experimental
2647
+ * @category resources & finalization
2648
+ */
2649
+ export interface MicroScope {
2650
+ readonly [MicroScopeTypeId]: MicroScopeTypeId
2651
+ readonly addFinalizer: (finalizer: (result: Result<unknown, unknown>) => Micro<void>) => Micro<void>
2652
+ readonly fork: Micro<MicroScope.Closeable>
2653
+ }
2654
+
2655
+ /**
2656
+ * @since 3.4.0
2657
+ * @experimental
2658
+ * @category resources & finalization
2659
+ */
2660
+ export declare namespace MicroScope {
2661
+ /**
2662
+ * @since 3.4.0
2663
+ * @experimental
2664
+ * @category resources & finalization
2665
+ */
2666
+ export interface Closeable extends MicroScope {
2667
+ readonly close: (result: Result<any, any>) => Micro<void>
2668
+ }
2669
+ }
2670
+
2671
+ /**
2672
+ * @since 3.4.0
2673
+ * @experimental
2674
+ * @category resources & finalization
2675
+ */
2676
+ export const MicroScope: Context.Tag<MicroScope, MicroScope> = Context.GenericTag<MicroScope>("effect/Micro/MicroScope")
2677
+
2678
+ class ScopeImpl implements MicroScope.Closeable {
2679
+ readonly [MicroScopeTypeId]: MicroScopeTypeId
2680
+ state: {
2681
+ readonly _tag: "Open"
2682
+ readonly finalizers: Set<(result: Result<any, any>) => Micro<void>>
2683
+ } | {
2684
+ readonly _tag: "Closed"
2685
+ readonly result: Result<any, any>
2686
+ } = { _tag: "Open", finalizers: new Set() }
2687
+
2688
+ constructor() {
2689
+ this[MicroScopeTypeId] = MicroScopeTypeId
2690
+ }
2691
+
2692
+ unsafeAddFinalizer(finalizer: (result: Result<any, any>) => Micro<void>): void {
2693
+ if (this.state._tag === "Open") {
2694
+ this.state.finalizers.add(finalizer)
2695
+ }
2696
+ }
2697
+ addFinalizer(finalizer: (result: Result<any, any>) => Micro<void>): Micro<void> {
2698
+ return suspend(() => {
2699
+ if (this.state._tag === "Open") {
2700
+ this.state.finalizers.add(finalizer)
2701
+ return void_
2702
+ }
2703
+ return finalizer(this.state.result)
2704
+ })
2705
+ }
2706
+ unsafeRemoveFinalizer(finalizer: (result: Result<any, any>) => Micro<void>): void {
2707
+ if (this.state._tag === "Open") {
2708
+ this.state.finalizers.delete(finalizer)
2709
+ }
2710
+ }
2711
+ close(result: Result<any, any>): Micro<void> {
2712
+ return suspend(() => {
2713
+ if (this.state._tag === "Open") {
2714
+ const finalizers = Array.from(this.state.finalizers).reverse()
2715
+ this.state = { _tag: "Closed", result }
2716
+ return flatMap(
2717
+ forEach(finalizers, (finalizer) => asResult(finalizer(result))),
2718
+ (results) => asVoid(fromResult(Either.all(results)))
2719
+ )
2720
+ }
2721
+ return void_
2722
+ })
2723
+ }
2724
+ get fork() {
2725
+ return sync(() => {
2726
+ const newScope = new ScopeImpl()
2727
+ if (this.state._tag === "Closed") {
2728
+ newScope.state = this.state
2729
+ return newScope
2730
+ }
2731
+ function fin(result: Result<any, any>) {
2732
+ return newScope.close(result)
2733
+ }
2734
+ this.state.finalizers.add(fin)
2735
+ newScope.unsafeAddFinalizer((_) => sync(() => this.unsafeRemoveFinalizer(fin)))
2736
+ return newScope
2737
+ })
2738
+ }
2739
+ }
2740
+
2741
+ /**
2742
+ * @since 3.4.0
2743
+ * @experimental
2744
+ * @category resources & finalization
2745
+ */
2746
+ export const scopeMake: Micro<MicroScope.Closeable> = sync(() => new ScopeImpl())
2747
+
2748
+ /**
2749
+ * @since 3.4.0
2750
+ * @experimental
2751
+ * @category resources & finalization
2752
+ */
2753
+ export const scopeUnsafeMake = (): MicroScope.Closeable => new ScopeImpl()
2754
+
2755
+ /**
2756
+ * Access the current `MicroScope`.
2757
+ *
2758
+ * @since 3.4.0
2759
+ * @experimental
2760
+ * @category resources & finalization
2761
+ */
2762
+ export const scope: Micro<MicroScope, never, MicroScope> = service(MicroScope)
2763
+
2764
+ /**
2765
+ * Provide a `MicroScope` to an effect.
2766
+ *
2767
+ * @since 3.4.0
2768
+ * @experimental
2769
+ * @category resources & finalization
2770
+ */
2771
+ export const provideScope: {
2772
+ (scope: MicroScope): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, Exclude<R, MicroScope>>
2773
+ <A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<A, E, Exclude<R, MicroScope>>
2774
+ } = dual(
2775
+ 2,
2776
+ <A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<A, E, Exclude<R, MicroScope>> =>
2777
+ provideService(self, MicroScope, scope)
2778
+ )
2779
+
2780
+ /**
2781
+ * Provide a `MicroScope` to the given effect, closing it after the effect has
2782
+ * finished executing.
2783
+ *
2784
+ * @since 3.4.0
2785
+ * @experimental
2786
+ * @category resources & finalization
2787
+ */
2788
+ export const scoped = <A, E, R>(self: Micro<A, E, R>): Micro<A, E, Exclude<R, MicroScope>> =>
2789
+ suspend(function() {
2790
+ const scope = new ScopeImpl()
2791
+ return onResult(provideService(self, MicroScope, scope), (result) => scope.close(result))
2792
+ })
2793
+
2794
+ /**
2795
+ * Create a resource with a cleanup `Micro` effect, ensuring the cleanup is
2796
+ * executed when the `MicroScope` is closed.
2797
+ *
2798
+ * @since 3.4.0
2799
+ * @experimental
2800
+ * @category resources & finalization
2801
+ */
2802
+ export const acquireRelease = <A, E, R>(
2803
+ acquire: Micro<A, E, R>,
2804
+ release: (a: A, result: Result<unknown, unknown>) => Micro<void>
2805
+ ): Micro<A, E, R | MicroScope> =>
2806
+ uninterruptible(flatMap(
2807
+ scope,
2808
+ (scope) => tap(acquire, (a) => scope.addFinalizer((result) => release(a, result)))
2809
+ ))
2810
+
2811
+ /**
2812
+ * Add a finalizer to the current `MicroScope`.
2813
+ *
2814
+ * @since 3.4.0
2815
+ * @experimental
2816
+ * @category resources & finalization
2817
+ */
2818
+ export const addFinalizer = (
2819
+ finalizer: (result: Result<unknown, unknown>) => Micro<void>
2820
+ ): Micro<void, never, MicroScope> => flatMap(scope, (scope) => scope.addFinalizer(finalizer))
2821
+
2822
+ /**
2823
+ * When the `Micro` effect is completed, run the given finalizer effect with the
2824
+ * `Result` of the executed effect.
2825
+ *
2826
+ * @since 3.4.0
2827
+ * @experimental
2828
+ * @category resources & finalization
2829
+ */
2830
+ export const onResult: {
2831
+ <A, E, XE, XR>(
2832
+ f: (result: Result<A, E>) => Micro<void, XE, XR>
2833
+ ): <R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
2834
+ <A, E, R, XE, XR>(self: Micro<A, E, R>, f: (result: Result<A, E>) => Micro<void, XE, XR>): Micro<A, E | XE, R | XR>
2835
+ } = dual(
2836
+ 2,
2837
+ <A, E, R, XE, XR>(self: Micro<A, E, R>, f: (result: Result<A, E>) => Micro<void, XE, XR>): Micro<A, E | XE, R | XR> =>
2838
+ onResultIf(self, constTrue, f)
2839
+ )
2840
+
2841
+ /**
2842
+ * When the `Micro` effect is completed, run the given finalizer effect if it
2843
+ * matches the specified predicate.
2844
+ *
2845
+ * @since 3.4.0
2846
+ * @experimental
2847
+ * @category resources & finalization
2848
+ */
2849
+ export const onResultIf: {
2850
+ <A, E, XE, XR, B extends Result<A, E>>(
2851
+ refinement: Refinement<Result<A, E>, B>,
2852
+ f: (result: B) => Micro<void, XE, XR>
2853
+ ): <R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
2854
+ <A, E, XE, XR>(
2855
+ predicate: Predicate<Result<NoInfer<A>, NoInfer<E>>>,
2856
+ f: (result: Result<NoInfer<A>, NoInfer<E>>) => Micro<void, XE, XR>
2857
+ ): <R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
2858
+ <A, E, R, XE, XR, B extends Result<A, E>>(
2859
+ self: Micro<A, E, R>,
2860
+ refinement: Refinement<Result<A, E>, B>,
2861
+ f: (result: B) => Micro<void, XE, XR>
2862
+ ): Micro<A, E | XE, R | XR>
2863
+ <A, E, R, XE, XR>(
2864
+ self: Micro<A, E, R>,
2865
+ predicate: Predicate<Result<NoInfer<A>, NoInfer<E>>>,
2866
+ f: (result: Result<NoInfer<A>, NoInfer<E>>) => Micro<void, XE, XR>
2867
+ ): Micro<A, E | XE, R | XR>
2868
+ } = dual(
2869
+ 3,
2870
+ <A, E, R, XE, XR, B extends Result<A, E>>(
2871
+ self: Micro<A, E, R>,
2872
+ refinement: Refinement<Result<A, E>, B>,
2873
+ f: (result: B) => Micro<void, XE, XR>
2874
+ ): Micro<A, E | XE, R | XR> =>
2875
+ uninterruptibleMask((restore) =>
2876
+ make(function(env, onResult) {
2877
+ restore(self)[runSymbol](env, function(result) {
2878
+ if (!refinement(result)) {
2879
+ return onResult(result)
2880
+ }
2881
+ f(result)[runSymbol](env, function(finalizerResult) {
2882
+ if (finalizerResult._tag === "Left") {
2883
+ return onResult(finalizerResult as any)
2884
+ }
2885
+ onResult(result)
2886
+ })
2887
+ })
2888
+ })
2889
+ )
2890
+ )
2891
+
2892
+ /**
2893
+ * Regardless of the result of the this `Micro` effect, run the finalizer effect.
2894
+ *
2895
+ * @since 3.4.0
2896
+ * @experimental
2897
+ * @category resources & finalization
2898
+ */
2899
+ export const ensuring: {
2900
+ <XE, XR>(
2901
+ finalizer: Micro<void, XE, XR>
2902
+ ): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
2903
+ <A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR>
2904
+ } = dual(
2905
+ 2,
2906
+ <A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR> =>
2907
+ onResult(self, (_) => finalizer)
2908
+ )
2909
+
2910
+ /**
2911
+ * When the `Micro` effect fails, run the given finalizer effect with the
2912
+ * `Failure` of the executed effect.
2913
+ *
2914
+ * @since 3.4.0
2915
+ * @experimental
2916
+ * @category resources & finalization
2917
+ */
2918
+ export const onFailure: {
2919
+ <A, E, XE, XR>(
2920
+ f: (failure: Failure<NoInfer<E>>) => Micro<void, XE, XR>
2921
+ ): <R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
2922
+ <A, E, R, XE, XR>(
2923
+ self: Micro<A, E, R>,
2924
+ f: (failure: Failure<NoInfer<E>>) => Micro<void, XE, XR>
2925
+ ): Micro<A, E | XE, R | XR>
2926
+ } = dual(
2927
+ 2,
2928
+ <A, E, R, XE, XR>(
2929
+ self: Micro<A, E, R>,
2930
+ f: (failure: Failure<NoInfer<E>>) => Micro<void, XE, XR>
2931
+ ): Micro<A, E | XE, R | XR> => onResultIf(self, resultIsFailure, (result) => f(result.left))
2932
+ )
2933
+
2934
+ /**
2935
+ * If this `Micro` effect is aborted, run the finalizer effect.
2936
+ *
2937
+ * @since 3.4.0
2938
+ * @experimental
2939
+ * @category resources & finalization
2940
+ */
2941
+ export const onAbort: {
2942
+ <XE, XR>(
2943
+ finalizer: Micro<void, XE, XR>
2944
+ ): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
2945
+ <A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR>
2946
+ } = dual(
2947
+ 2,
2948
+ <A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR> =>
2949
+ onResultIf(self, resultIsAborted, (_) => finalizer)
2950
+ )
2951
+
2952
+ /**
2953
+ * Acquire a resource, use it, and then release the resource when the `use`
2954
+ * effect has completed.
2955
+ *
2956
+ * @since 3.4.0
2957
+ * @experimental
2958
+ * @category resources & finalization
2959
+ */
2960
+ export const acquireUseRelease = <Resource, E, R, A, E2, R2, E3, R3>(
2961
+ acquire: Micro<Resource, E, R>,
2962
+ use: (a: Resource) => Micro<A, E2, R2>,
2963
+ release: (a: Resource, result: Result<A, E2>) => Micro<void, E3, R3>
2964
+ ): Micro<A, E | E2 | E3, R | R2 | R3> =>
2965
+ uninterruptibleMask((restore) =>
2966
+ flatMap(
2967
+ acquire,
2968
+ (a) =>
2969
+ flatMap(
2970
+ asResult(restore(use(a))),
2971
+ (result) => andThen(release(a, result), fromResult(result))
2972
+ )
2973
+ )
2974
+ )
2975
+
2976
+ // ----------------------------------------------------------------------------
2977
+ // interruption
2978
+ // ----------------------------------------------------------------------------
2979
+
2980
+ /**
2981
+ * Abort the current `Micro` effect.
2982
+ *
2983
+ * @since 3.4.0
2984
+ * @experimental
2985
+ * @category interruption
2986
+ */
2987
+ export const abort: Micro<never> = make(function(env, onResult) {
2988
+ const controller = envGet(env, currentAbortController)
2989
+ controller.abort()
2990
+ onResult(ResultAborted)
2991
+ })
2992
+
2993
+ /**
2994
+ * Wrap the given `Micro` effect in an uninterruptible region, preventing the
2995
+ * effect from being aborted.
2996
+ *
2997
+ * @since 3.4.0
2998
+ * @experimental
2999
+ * @category interruption
3000
+ */
3001
+ export const uninterruptible = <A, E, R>(self: Micro<A, E, R>): Micro<A, E, R> =>
3002
+ unsafeMakeOptions(function(env, onResult) {
3003
+ const nextEnv = envMutate(env, function(env) {
3004
+ env[currentInterruptible.key] = false
3005
+ env[currentAbortSignal.key] = new AbortController().signal
3006
+ return env
3007
+ })
3008
+ self[runSymbol](nextEnv, onResult)
3009
+ }, false)
3010
+
3011
+ /**
3012
+ * Wrap the given `Micro` effect in an uninterruptible region, preventing the
3013
+ * effect from being aborted.
3014
+ *
3015
+ * You can use the `restore` function to restore a `Micro` effect to the
3016
+ * interruptibility state before the `uninterruptibleMask` was applied.
3017
+ *
3018
+ * @since 3.4.0
3019
+ * @experimental
3020
+ * @category interruption
3021
+ * @example
3022
+ * import * as Micro from "effect/Micro"
3023
+ *
3024
+ * Micro.uninterruptibleMask((restore) =>
3025
+ * Micro.sleep(1000).pipe( // uninterruptible
3026
+ * Micro.andThen(restore(Micro.sleep(1000))) // interruptible
3027
+ * )
3028
+ * )
3029
+ */
3030
+ export const uninterruptibleMask = <A, E, R>(
3031
+ f: (restore: <A, E, R>(effect: Micro<A, E, R>) => Micro<A, E, R>) => Micro<A, E, R>
3032
+ ): Micro<A, E, R> =>
3033
+ unsafeMakeOptions((env, onResult) => {
3034
+ const isInterruptible = envGet(env, currentInterruptible)
3035
+ const effect = isInterruptible ? f(interruptible) : f(identity)
3036
+ const nextEnv = isInterruptible ?
3037
+ envMutate(env, function(env) {
3038
+ env[currentInterruptible.key] = false
3039
+ env[currentAbortSignal.key] = new AbortController().signal
3040
+ return env
3041
+ }) :
3042
+ env
3043
+ effect[runSymbol](nextEnv, onResult)
3044
+ }, false)
3045
+
3046
+ /**
3047
+ * Wrap the given `Micro` effect in an interruptible region, allowing the effect
3048
+ * to be aborted.
3049
+ *
3050
+ * @since 3.4.0
3051
+ * @experimental
3052
+ * @category interruption
3053
+ */
3054
+ export const interruptible = <A, E, R>(self: Micro<A, E, R>): Micro<A, E, R> =>
3055
+ make((env, onResult) => {
3056
+ const isInterruptible = envGet(env, currentInterruptible)
3057
+ let newEnv = env
3058
+ if (!isInterruptible) {
3059
+ const controller = envGet(env, currentAbortController)
3060
+ newEnv = envMutate(env, function(env) {
3061
+ env[currentInterruptible.key] = true
3062
+ env[currentAbortSignal.key] = controller.signal
3063
+ return env
3064
+ })
3065
+ }
3066
+ self[runSymbol](newEnv, onResult)
3067
+ })
3068
+
3069
+ // ========================================================================
3070
+ // collecting & elements
3071
+ // ========================================================================
3072
+
3073
+ /**
3074
+ * @since 3.4.0
3075
+ * @experimental
3076
+ */
3077
+ export declare namespace All {
3078
+ /**
3079
+ * @since 3.4.0
3080
+ * @experimental
3081
+ */
3082
+ export type MicroAny = Micro<any, any, any>
3083
+
3084
+ /**
3085
+ * @since 3.4.0
3086
+ * @experimental
3087
+ */
3088
+ export type ReturnIterable<T extends Iterable<MicroAny>, Discard extends boolean> = [T] extends
3089
+ [Iterable<Micro<infer A, infer E, infer R>>] ? Micro<
3090
+ Discard extends true ? void : Array<A>,
3091
+ E,
3092
+ R
3093
+ >
3094
+ : never
3095
+
3096
+ /**
3097
+ * @since 3.4.0
3098
+ * @experimental
3099
+ */
3100
+ export type ReturnTuple<T extends ReadonlyArray<unknown>, Discard extends boolean> = Micro<
3101
+ Discard extends true ? void
3102
+ : T[number] extends never ? []
3103
+ : { -readonly [K in keyof T]: T[K] extends Micro<infer _A, infer _E, infer _R> ? _A : never },
3104
+ T[number] extends never ? never
3105
+ : T[number] extends Micro<infer _A, infer _E, infer _R> ? _E
3106
+ : never,
3107
+ T[number] extends never ? never
3108
+ : T[number] extends Micro<infer _A, infer _E, infer _R> ? _R
3109
+ : never
3110
+ > extends infer X ? X : never
3111
+
3112
+ /**
3113
+ * @since 3.4.0
3114
+ * @experimental
3115
+ */
3116
+ export type ReturnObject<T, Discard extends boolean> = [T] extends [{ [K: string]: MicroAny }] ? Micro<
3117
+ Discard extends true ? void :
3118
+ { -readonly [K in keyof T]: [T[K]] extends [Micro<infer _A, infer _E, infer _R>] ? _A : never },
3119
+ keyof T extends never ? never
3120
+ : T[keyof T] extends Micro<infer _A, infer _E, infer _R> ? _E
3121
+ : never,
3122
+ keyof T extends never ? never
3123
+ : T[keyof T] extends Micro<infer _A, infer _E, infer _R> ? _R
3124
+ : never
3125
+ >
3126
+ : never
3127
+
3128
+ /**
3129
+ * @since 3.4.0
3130
+ * @experimental
3131
+ */
3132
+ export type IsDiscard<A> = [Extract<A, { readonly discard: true }>] extends [never] ? false : true
3133
+
3134
+ /**
3135
+ * @since 3.4.0
3136
+ * @experimental
3137
+ */
3138
+ export type Return<
3139
+ Arg extends Iterable<MicroAny> | Record<string, MicroAny>,
3140
+ O extends {
3141
+ readonly concurrency?: Concurrency | undefined
3142
+ readonly discard?: boolean | undefined
3143
+ }
3144
+ > = [Arg] extends [ReadonlyArray<MicroAny>] ? ReturnTuple<Arg, IsDiscard<O>>
3145
+ : [Arg] extends [Iterable<MicroAny>] ? ReturnIterable<Arg, IsDiscard<O>>
3146
+ : [Arg] extends [Record<string, MicroAny>] ? ReturnObject<Arg, IsDiscard<O>>
3147
+ : never
3148
+ }
3149
+
3150
+ /**
3151
+ * Runs all the provided effects in sequence respecting the structure provided in input.
3152
+ *
3153
+ * Supports multiple arguments, a single argument tuple / array or record / struct.
3154
+ *
3155
+ * @since 3.4.0
3156
+ * @experimental
3157
+ * @category collecting & elements
3158
+ */
3159
+ export const all = <
3160
+ const Arg extends Iterable<Micro<any, any, any>> | Record<string, Micro<any, any, any>>,
3161
+ O extends {
3162
+ readonly concurrency?: Concurrency | undefined
3163
+ readonly discard?: boolean | undefined
3164
+ }
3165
+ >(arg: Arg, options?: O): All.Return<Arg, O> => {
3166
+ if (Array.isArray(arg) || isIterable(arg)) {
3167
+ return (forEach as any)(arg, identity, options)
3168
+ } else if (options?.discard) {
3169
+ return (forEach as any)(Object.values(arg), identity, options)
3170
+ }
3171
+ return suspend(() => {
3172
+ const out: Record<string, unknown> = {}
3173
+ return as(
3174
+ forEach(Object.entries(arg), ([key, effect]) =>
3175
+ map(effect, (value) => {
3176
+ out[key] = value
3177
+ }), {
3178
+ discard: true,
3179
+ concurrency: options?.concurrency
3180
+ }),
3181
+ out
3182
+ )
3183
+ }) as any
3184
+ }
3185
+
3186
+ /**
3187
+ * For each element of the provided iterable, run the effect and collect the results.
3188
+ *
3189
+ * If the `discard` option is set to `true`, the results will be discarded and
3190
+ * the effect will return `void`.
3191
+ *
3192
+ * The `concurrency` option can be set to control how many effects are run in
3193
+ * parallel. By default, the effects are run sequentially.
3194
+ *
3195
+ * @since 3.4.0
3196
+ * @experimental
3197
+ * @category collecting & elements
3198
+ */
3199
+ export const forEach: {
3200
+ <A, B, E, R>(iterable: Iterable<A>, f: (a: A, index: number) => Micro<B, E, R>, options?: {
3201
+ readonly concurrency?: Concurrency | undefined
3202
+ readonly discard?: false | undefined
3203
+ }): Micro<Array<B>, E, R>
3204
+ <A, B, E, R>(iterable: Iterable<A>, f: (a: A, index: number) => Micro<B, E, R>, options: {
3205
+ readonly concurrency?: Concurrency | undefined
3206
+ readonly discard: true
3207
+ }): Micro<void, E, R>
3208
+ } = <
3209
+ A,
3210
+ B,
3211
+ E,
3212
+ R
3213
+ >(iterable: Iterable<A>, f: (a: A, index: number) => Micro<B, E, R>, options?: {
3214
+ readonly concurrency?: Concurrency | undefined
3215
+ readonly discard?: boolean | undefined
3216
+ }): Micro<any, E, R> =>
3217
+ make(function(env, onResult) {
3218
+ const concurrencyOption = options?.concurrency === "inherit"
3219
+ ? envGet(env, currentConcurrency)
3220
+ : options?.concurrency ?? 1
3221
+ const concurrency = concurrencyOption === "unbounded"
3222
+ ? Number.POSITIVE_INFINITY
3223
+ : Math.max(1, concurrencyOption)
3224
+
3225
+ // abort
3226
+ const [envWithSignal, onAbort] = forkSignal(env)
3227
+
3228
+ // iterate
3229
+ let failure: Result<any, any> | undefined = undefined
3230
+ const items = Array.from(iterable)
3231
+ let length = items.length
3232
+ const out: Array<B> | undefined = options?.discard ? undefined : new Array(length)
3233
+ let index = 0
3234
+ let inProgress = 0
3235
+ let doneCount = 0
3236
+ let pumping = false
3237
+ function pump() {
3238
+ pumping = true
3239
+ while (inProgress < concurrency && index < length) {
3240
+ const currentIndex = index
3241
+ const item = items[currentIndex]
3242
+ index++
3243
+ inProgress++
3244
+ try {
3245
+ f(item, currentIndex)[runSymbol](envWithSignal, function(result) {
3246
+ if (result._tag === "Left") {
3247
+ if (failure === undefined) {
3248
+ failure = result
3249
+ length = index
3250
+ onAbort()
3251
+ }
3252
+ } else if (out !== undefined) {
3253
+ out[currentIndex] = result.right
3254
+ }
3255
+ doneCount++
3256
+ inProgress--
3257
+ if (doneCount === length) {
3258
+ onResult(failure ?? Either.right(out))
3259
+ } else if (!pumping && inProgress < concurrency) {
3260
+ pump()
3261
+ }
3262
+ })
3263
+ } catch (err) {
3264
+ failure = ResultFailUnexpected(err)
3265
+ length = index
3266
+ onAbort()
3267
+ }
3268
+ }
3269
+ pumping = false
3270
+ }
3271
+ pump()
3272
+ })
3273
+
3274
+ /**
3275
+ * Effectfully filter the elements of the provided iterable.
3276
+ *
3277
+ * Use the `concurrency` option to control how many elements are processed in parallel.
3278
+ *
3279
+ * @since 3.4.0
3280
+ * @experimental
3281
+ * @category collecting & elements
3282
+ */
3283
+ export const filter = <A, E, R>(iterable: Iterable<A>, f: (a: NoInfer<A>) => Micro<boolean, E, R>, options?: {
3284
+ readonly concurrency?: Concurrency | undefined
3285
+ readonly negate?: boolean | undefined
3286
+ }): Micro<Array<A>, E, R> =>
3287
+ filterMap(iterable, (a) =>
3288
+ map(f(a), (pass) => {
3289
+ pass = options?.negate ? !pass : pass
3290
+ return pass ? Option.some(a) : Option.none()
3291
+ }))
3292
+
3293
+ /**
3294
+ * Effectfully filter the elements of the provided iterable.
3295
+ *
3296
+ * Use the `concurrency` option to control how many elements are processed in parallel.
3297
+ *
3298
+ * @since 3.4.0
3299
+ * @experimental
3300
+ * @category collecting & elements
3301
+ */
3302
+ export const filterMap = <A, B, E, R>(
3303
+ iterable: Iterable<A>,
3304
+ f: (a: NoInfer<A>) => Micro<Option.Option<B>, E, R>,
3305
+ options?: {
3306
+ readonly concurrency?: Concurrency | undefined
3307
+ }
3308
+ ): Micro<Array<B>, E, R> =>
3309
+ suspend(() => {
3310
+ const out: Array<B> = []
3311
+ return as(
3312
+ forEach(iterable, (a) =>
3313
+ map(f(a), (o) => {
3314
+ if (o._tag === "Some") {
3315
+ out.push(o.value)
3316
+ }
3317
+ }), {
3318
+ discard: true,
3319
+ concurrency: options?.concurrency
3320
+ }),
3321
+ out
3322
+ )
3323
+ })
3324
+
3325
+ // ----------------------------------------------------------------------------
3326
+ // do notation
3327
+ // ----------------------------------------------------------------------------
3328
+
3329
+ /**
3330
+ * Start a do notation block.
3331
+ *
3332
+ * @since 3.4.0
3333
+ * @experimental
3334
+ * @category do notation
3335
+ */
3336
+ export const Do: Micro<{}> = succeed({})
3337
+
3338
+ /**
3339
+ * Bind the success value of this `Micro` effect to the provided name.
3340
+ *
3341
+ * @since 3.4.0
3342
+ * @experimental
3343
+ * @category do notation
3344
+ */
3345
+ export const bindTo: {
3346
+ <N extends string>(name: N): <A, E, R>(self: Micro<A, E, R>) => Micro<{ [K in N]: A }, E, R>
3347
+ <A, E, R, N extends string>(self: Micro<A, E, R>, name: N): Micro<{ [K in N]: A }, E, R>
3348
+ } = dual(2, <A, E, R, N extends string>(self: Micro<A, E, R>, name: N): Micro<{ [K in N]: A }, E, R> =>
3349
+ map(
3350
+ self,
3351
+ (f) => ({ [name]: f } as any)
3352
+ ))
3353
+
3354
+ /**
3355
+ * Bind the success value of this `Micro` effect to the provided name.
3356
+ *
3357
+ * @since 3.4.0
3358
+ * @experimental
3359
+ * @category do notation
3360
+ */
3361
+ export const bind: {
3362
+ <N extends string, A extends Record<string, any>, B, E2, R2>(
3363
+ name: N,
3364
+ f: (a: A) => Micro<B, E2, R2>
3365
+ ): <E, R>(self: Micro<A, E, R>) => Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E | E2, R | R2>
3366
+ <A extends Record<string, any>, E, R, B, E2, R2, N extends string>(
3367
+ self: Micro<A, E, R>,
3368
+ name: N,
3369
+ f: (a: A) => Micro<B, E2, R2>
3370
+ ): Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E | E2, R | R2>
3371
+ } = dual(3, <A extends Record<string, any>, E, R, B, E2, R2, N extends string>(
3372
+ self: Micro<A, E, R>,
3373
+ name: N,
3374
+ f: (a: A) => Micro<B, E2, R2>
3375
+ ): Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E | E2, R | R2> =>
3376
+ flatMap(
3377
+ self,
3378
+ (a) => map(f(a), (b) => ({ ...a, [name]: b } as any))
3379
+ ))
3380
+
3381
+ const let_: {
3382
+ <N extends string, A extends Record<string, any>, B>(
3383
+ name: N,
3384
+ f: (a: A) => B
3385
+ ): <E, R>(self: Micro<A, E, R>) => Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E, R>
3386
+ <A extends Record<string, any>, E, R, B, N extends string>(
3387
+ self: Micro<A, E, R>,
3388
+ name: N,
3389
+ f: (a: A) => B
3390
+ ): Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E, R>
3391
+ } = dual(3, <A extends Record<string, any>, E, R, B, N extends string>(
3392
+ self: Micro<A, E, R>,
3393
+ name: N,
3394
+ f: (a: A) => B
3395
+ ): Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E, R> =>
3396
+ map(
3397
+ self,
3398
+ (a) => ({ ...a, [name]: f(a) } as any)
3399
+ ))
3400
+ export {
3401
+ /**
3402
+ * Bind the result of a synchronous computation to the given name.
3403
+ *
3404
+ * @since 3.4.0
3405
+ * @experimental
3406
+ * @category do notation
3407
+ */
3408
+ let_ as let
3409
+ }
3410
+
3411
+ // ----------------------------------------------------------------------------
3412
+ // handle & forking
3413
+ // ----------------------------------------------------------------------------
3414
+
3415
+ /**
3416
+ * @since 3.4.0
3417
+ * @experimental
3418
+ * @category handle & forking
3419
+ */
3420
+ export const HandleTypeId: unique symbol = Symbol.for("effect/Micro/Handle")
3421
+
3422
+ /**
3423
+ * @since 3.4.0
3424
+ * @experimental
3425
+ * @category handle & forking
3426
+ */
3427
+ export type HandleTypeId = typeof HandleTypeId
3428
+
3429
+ /**
3430
+ * @since 3.4.0
3431
+ * @experimental
3432
+ * @category handle & forking
3433
+ */
3434
+ export interface Handle<A, E = never> {
3435
+ readonly [HandleTypeId]: HandleTypeId
3436
+ readonly await: Micro<Result<A, E>>
3437
+ readonly join: Micro<A, E>
3438
+ readonly abort: Micro<Result<A, E>>
3439
+ readonly unsafeAbort: () => void
3440
+ readonly addObserver: (observer: (result: Result<A, E>) => void) => void
3441
+ readonly removeObserver: (observer: (result: Result<A, E>) => void) => void
3442
+ readonly unsafePoll: () => Result<A, E> | null
3443
+ }
3444
+
3445
+ /**
3446
+ * @since 3.4.0
3447
+ * @experimental
3448
+ * @category handle & forking
3449
+ */
3450
+ export const isHandle = (u: unknown): u is Handle<unknown, unknown> =>
3451
+ typeof u === "object" && u !== null && HandleTypeId in u
3452
+
3453
+ class HandleImpl<A, E> implements Handle<A, E> {
3454
+ readonly [HandleTypeId]: HandleTypeId
3455
+
3456
+ readonly observers: Set<(result: Result<A, E>) => void> = new Set()
3457
+ private _result: Result<A, E> | undefined = undefined
3458
+ _controller: AbortController
3459
+ readonly isRoot: boolean
3460
+
3461
+ constructor(readonly parentSignal: AbortSignal, controller?: AbortController) {
3462
+ this[HandleTypeId] = HandleTypeId
3463
+ this.isRoot = controller !== undefined
3464
+ this._controller = controller ?? new AbortController()
3465
+ if (!this.isRoot) {
3466
+ parentSignal.addEventListener("abort", this.unsafeAbort)
3467
+ }
3468
+ }
3469
+
3470
+ unsafePoll(): Result<A, E> | null {
3471
+ return this._result ?? null
3472
+ }
3473
+
3474
+ unsafeAbort = () => {
3475
+ this._controller.abort()
3476
+ }
3477
+
3478
+ emit(result: Result<A, E>): void {
3479
+ if (this._result) {
3480
+ return
3481
+ }
3482
+ this._result = result
3483
+ if (!this.isRoot) {
3484
+ this.parentSignal.removeEventListener("abort", this.unsafeAbort)
3485
+ }
3486
+ this.observers.forEach((observer) => observer(result))
3487
+ this.observers.clear()
3488
+ }
3489
+
3490
+ addObserver(observer: (result: Result<A, E>) => void): void {
3491
+ if (this._result) {
3492
+ return observer(this._result)
3493
+ }
3494
+ this.observers.add(observer)
3495
+ }
3496
+
3497
+ removeObserver(observer: (result: Result<A, E>) => void): void {
3498
+ this.observers.delete(observer)
3499
+ }
3500
+
3501
+ get await(): Micro<Result<A, E>> {
3502
+ return suspend(() => {
3503
+ if (this._result) {
3504
+ return succeed(this._result)
3505
+ }
3506
+ return async((resume) => {
3507
+ function observer(result: Result<A, E>) {
3508
+ resume(succeed(result))
3509
+ }
3510
+ this.addObserver(observer)
3511
+ return sync(() => {
3512
+ this.removeObserver(observer)
3513
+ })
3514
+ })
3515
+ })
3516
+ }
3517
+
3518
+ get join(): Micro<A, E> {
3519
+ return flatMap(this.await, fromResult)
3520
+ }
3521
+
3522
+ get abort(): Micro<Result<A, E>> {
3523
+ return suspend(() => {
3524
+ this.unsafeAbort()
3525
+ return this.await
3526
+ })
3527
+ }
3528
+ }
3529
+
3530
+ /**
3531
+ * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
3532
+ * aborted.
3533
+ *
3534
+ * When the parent `Micro` finishes, this `Micro` will be aborted.
3535
+ *
3536
+ * @since 3.4.0
3537
+ * @experimental
3538
+ * @category handle & forking
3539
+ */
3540
+ export const fork = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never, R> =>
3541
+ make(function(env, onResult) {
3542
+ const signal = envGet(env, currentAbortSignal)
3543
+ const handle = new HandleImpl<A, E>(signal)
3544
+ const nextEnv = envMutate(env, (map) => {
3545
+ map[currentAbortController.key] = handle._controller
3546
+ map[currentAbortSignal.key] = handle._controller.signal
3547
+ return map
3548
+ })
3549
+ yieldAdd(() => {
3550
+ self[runSymbol](nextEnv, (result) => {
3551
+ handle.emit(result)
3552
+ })
3553
+ })
3554
+ onResult(Either.right(handle))
3555
+ })
3556
+
3557
+ /**
3558
+ * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
3559
+ * aborted.
3560
+ *
3561
+ * It will not be aborted when the parent `Micro` finishes.
3562
+ *
3563
+ * @since 3.4.0
3564
+ * @experimental
3565
+ * @category handle & forking
3566
+ */
3567
+ export const forkDaemon = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never, R> =>
3568
+ make(function(env, onResult) {
3569
+ const controller = new AbortController()
3570
+ const handle = new HandleImpl<A, E>(controller.signal, controller)
3571
+ const nextEnv = envMutate(env, (map) => {
3572
+ map[currentAbortController.key] = controller
3573
+ map[currentAbortSignal.key] = controller.signal
3574
+ return map
3575
+ })
3576
+ yieldAdd(() => {
3577
+ self[runSymbol](nextEnv, (result) => {
3578
+ handle.emit(result)
3579
+ })
3580
+ })
3581
+ onResult(Either.right(handle))
3582
+ })
3583
+
3584
+ /**
3585
+ * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
3586
+ * aborted.
3587
+ *
3588
+ * The lifetime of the handle will be attached to the provided `MicroScope`.
3589
+ *
3590
+ * @since 3.4.0
3591
+ * @experimental
3592
+ * @category handle & forking
3593
+ */
3594
+ export const forkIn: {
3595
+ (scope: MicroScope): <A, E, R>(self: Micro<A, E, R>) => Micro<Handle<A, E>, never, R>
3596
+ <A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<Handle<A, E>, never, R>
3597
+ } = dual(
3598
+ 2,
3599
+ <A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<Handle<A, E>, never, R> =>
3600
+ uninterruptibleMask((restore) =>
3601
+ flatMap(scope.fork, (scope) =>
3602
+ tap(
3603
+ restore(forkDaemon(onResult(self, (result) => scope.close(result)))),
3604
+ (fiber) => scope.addFinalizer((_) => asVoid(fiber.abort))
3605
+ ))
3606
+ )
3607
+ )
3608
+
3609
+ /**
3610
+ * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
3611
+ * aborted.
3612
+ *
3613
+ * The lifetime of the handle will be attached to the current `MicroScope`.
3614
+ *
3615
+ * @since 3.4.0
3616
+ * @experimental
3617
+ * @category handle & forking
3618
+ */
3619
+ export const forkScoped = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never, R | MicroScope> =>
3620
+ flatMap(scope, (scope) => forkIn(self, scope))
3621
+
3622
+ // ----------------------------------------------------------------------------
3623
+ // execution
3624
+ // ----------------------------------------------------------------------------
3625
+
3626
+ /**
3627
+ * Execute the `Micro` effect and return a `Handle` that can be awaited, joined,
3628
+ * or aborted.
3629
+ *
3630
+ * You can listen for the result by adding an observer using the handle's
3631
+ * `addObserver` method.
3632
+ *
3633
+ * @since 3.4.0
3634
+ * @experimental
3635
+ * @category execution
3636
+ * @example
3637
+ * import * as Micro from "effect/Micro"
3638
+ *
3639
+ * const handle = Micro.succeed(42).pipe(
3640
+ * Micro.delay(1000),
3641
+ * Micro.runFork
3642
+ * )
3643
+ *
3644
+ * handle.addObserver((result) => {
3645
+ * console.log(result)
3646
+ * })
3647
+ */
3648
+ export const runFork = <A, E>(
3649
+ effect: Micro<A, E>,
3650
+ options?: {
3651
+ readonly signal?: AbortSignal | undefined
3652
+ } | undefined
3653
+ ): Handle<A, E> => {
3654
+ const controller = new AbortController()
3655
+ const refs = Object.create(null)
3656
+ refs[currentAbortController.key] = controller
3657
+ refs[currentAbortSignal.key] = controller.signal
3658
+ const env = envMake(refs)
3659
+ const handle = new HandleImpl<A, E>(controller.signal, controller)
3660
+ effect[runSymbol](envSet(env, currentAbortSignal, handle._controller.signal), (result) => {
3661
+ handle.emit(result)
3662
+ })
3663
+ if (options?.signal) {
3664
+ if (options.signal.aborted) {
3665
+ handle.unsafeAbort()
3666
+ } else {
3667
+ options.signal.addEventListener("abort", () => handle.unsafeAbort())
3668
+ }
3669
+ }
3670
+ return handle
3671
+ }
3672
+
3673
+ /**
3674
+ * Execute the `Micro` effect and return a `Promise` that resolves with the
3675
+ * `Result` of the computation.
3676
+ *
3677
+ * @since 3.4.0
3678
+ * @experimental
3679
+ * @category execution
3680
+ */
3681
+ export const runPromiseResult = <A, E>(
3682
+ effect: Micro<A, E>,
3683
+ options?: {
3684
+ readonly signal?: AbortSignal | undefined
3685
+ } | undefined
3686
+ ): Promise<Result<A, E>> =>
3687
+ new Promise((resolve, _reject) => {
3688
+ const handle = runFork(effect, options)
3689
+ handle.addObserver(resolve)
3690
+ })
3691
+
3692
+ /**
3693
+ * Execute the `Micro` effect and return a `Promise` that resolves with the
3694
+ * successful value of the computation.
3695
+ *
3696
+ * @since 3.4.0
3697
+ * @experimental
3698
+ * @category execution
3699
+ */
3700
+ export const runPromise = <A, E>(
3701
+ effect: Micro<A, E>,
3702
+ options?: {
3703
+ readonly signal?: AbortSignal | undefined
3704
+ } | undefined
3705
+ ): Promise<A> =>
3706
+ runPromiseResult(effect, options).then((result) => {
3707
+ if (result._tag === "Left") {
3708
+ throw result.left
3709
+ }
3710
+ return result.right
3711
+ })
3712
+
3713
+ /**
3714
+ * Attempt to execute the `Micro` effect synchronously and return the `Result`.
3715
+ *
3716
+ * If any asynchronous effects are encountered, the function will return a
3717
+ * FailureUnexpected containing the `Handle`.
3718
+ *
3719
+ * @since 3.4.0
3720
+ * @experimental
3721
+ * @category execution
3722
+ */
3723
+ export const runSyncResult = <A, E>(effect: Micro<A, E>): Result<A, E> => {
3724
+ const handle = runFork(effect)
3725
+ while (yieldState.tasks.length > 0) {
3726
+ yieldRunTasks()
3727
+ }
3728
+ const result = handle.unsafePoll()
3729
+ if (result === null) {
3730
+ return ResultFailUnexpected(handle)
3731
+ }
3732
+ return result
3733
+ }
3734
+
3735
+ /**
3736
+ * Attempt to execute the `Micro` effect synchronously and return the success
3737
+ * value.
3738
+ *
3739
+ * @since 3.4.0
3740
+ * @experimental
3741
+ * @category execution
3742
+ */
3743
+ export const runSync = <A, E>(effect: Micro<A, E>): A => {
3744
+ const result = runSyncResult(effect)
3745
+ if (result._tag === "Left") {
3746
+ throw result.left
3747
+ }
3748
+ return result.right
3749
+ }
3750
+
3751
+ // ----------------------------------------------------------------------------
3752
+ // Errors
3753
+ // ----------------------------------------------------------------------------
3754
+
3755
+ /**
3756
+ * @since 3.4.0
3757
+ * @experimental
3758
+ * @category errors
3759
+ */
3760
+ export interface YieldableError extends Pipeable, Inspectable, Readonly<Error> {
3761
+ readonly [EffectTypeId]: Effect.VarianceStruct<never, this, never>
3762
+ readonly [StreamTypeId]: Stream.VarianceStruct<never, this, never>
3763
+ readonly [SinkTypeId]: Sink.VarianceStruct<never, unknown, never, this, never>
3764
+ readonly [ChannelTypeId]: Channel.VarianceStruct<never, unknown, this, unknown, never, unknown, never>
3765
+ readonly [TypeId]: Micro.Variance<never, this, never>
3766
+ readonly [runSymbol]: (env: Env<any>, onResult: (result: Result<never, this>) => void) => void
3767
+ [Symbol.iterator](): MicroIterator<Micro<never, this, never>>
3768
+ }
3769
+
3770
+ const YieldableError: new(message?: string) => YieldableError = (function() {
3771
+ class YieldableError extends globalThis.Error {
3772
+ [runSymbol](_env: any, onResult: any) {
3773
+ onResult(ResultFail(this))
3774
+ }
3775
+ toString() {
3776
+ return this.message ? `${this.name}: ${this.message}` : this.name
3777
+ }
3778
+ toJSON() {
3779
+ return { ...this }
3780
+ }
3781
+ [NodeInspectSymbol](): string {
3782
+ const stack = this.stack
3783
+ if (stack) {
3784
+ return `${this.toString()}\n${stack.split("\n").slice(1).join("\n")}`
3785
+ }
3786
+ return this.toString()
3787
+ }
3788
+ }
3789
+ Object.assign(YieldableError.prototype, MicroProto, StructuralPrototype)
3790
+ return YieldableError as any
3791
+ })()
3792
+
3793
+ /**
3794
+ * @since 3.4.0
3795
+ * @experimental
3796
+ * @category errors
3797
+ */
3798
+ export const Error: new<A extends Record<string, any> = {}>(
3799
+ args: Equals<A, {}> extends true ? void
3800
+ : { readonly [P in keyof A]: A[P] }
3801
+ ) => YieldableError & Readonly<A> = (function() {
3802
+ return class extends YieldableError {
3803
+ constructor(args: any) {
3804
+ super()
3805
+ if (args) {
3806
+ Object.assign(this, args)
3807
+ }
3808
+ }
3809
+ } as any
3810
+ })()
3811
+
3812
+ /**
3813
+ * @since 3.4.0
3814
+ * @experimental
3815
+ * @category errors
3816
+ */
3817
+ export const TaggedError = <Tag extends string>(tag: Tag): new<A extends Record<string, any> = {}>(
3818
+ args: Equals<A, {}> extends true ? void
3819
+ : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }
3820
+ ) => YieldableError & { readonly _tag: Tag } & Readonly<A> => {
3821
+ class Base extends Error<{}> {
3822
+ readonly _tag = tag
3823
+ }
3824
+ ;(Base.prototype as any).name = tag
3825
+ return Base as any
3826
+ }