effect 3.10.19 → 3.11.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 (167) hide show
  1. package/dist/cjs/BigDecimal.js +125 -24
  2. package/dist/cjs/BigDecimal.js.map +1 -1
  3. package/dist/cjs/Channel.js +44 -4
  4. package/dist/cjs/Channel.js.map +1 -1
  5. package/dist/cjs/Config.js +8 -1
  6. package/dist/cjs/Config.js.map +1 -1
  7. package/dist/cjs/Context.js +26 -1
  8. package/dist/cjs/Context.js.map +1 -1
  9. package/dist/cjs/Cron.js +75 -67
  10. package/dist/cjs/Cron.js.map +1 -1
  11. package/dist/cjs/DateTime.js +114 -664
  12. package/dist/cjs/DateTime.js.map +1 -1
  13. package/dist/cjs/Effect.js +82 -4
  14. package/dist/cjs/Effect.js.map +1 -1
  15. package/dist/cjs/Inspectable.js +8 -4
  16. package/dist/cjs/Inspectable.js.map +1 -1
  17. package/dist/cjs/JSONSchema.js.map +1 -1
  18. package/dist/cjs/Micro.js +1099 -1072
  19. package/dist/cjs/Micro.js.map +1 -1
  20. package/dist/cjs/STM.js.map +1 -1
  21. package/dist/cjs/Schema.js +57 -8
  22. package/dist/cjs/Schema.js.map +1 -1
  23. package/dist/cjs/Sink.js +9 -1
  24. package/dist/cjs/Sink.js.map +1 -1
  25. package/dist/cjs/Stream.js +25 -7
  26. package/dist/cjs/Stream.js.map +1 -1
  27. package/dist/cjs/Utils.js +7 -1
  28. package/dist/cjs/Utils.js.map +1 -1
  29. package/dist/cjs/internal/channel/channelExecutor.js +5 -9
  30. package/dist/cjs/internal/channel/channelExecutor.js.map +1 -1
  31. package/dist/cjs/internal/channel.js +156 -130
  32. package/dist/cjs/internal/channel.js.map +1 -1
  33. package/dist/cjs/internal/config.js +13 -4
  34. package/dist/cjs/internal/config.js.map +1 -1
  35. package/dist/cjs/internal/context.js +46 -3
  36. package/dist/cjs/internal/context.js.map +1 -1
  37. package/dist/cjs/internal/dateTime.js +747 -0
  38. package/dist/cjs/internal/dateTime.js.map +1 -0
  39. package/dist/cjs/internal/fiberRuntime.js +34 -11
  40. package/dist/cjs/internal/fiberRuntime.js.map +1 -1
  41. package/dist/cjs/internal/groupBy.js +9 -3
  42. package/dist/cjs/internal/groupBy.js.map +1 -1
  43. package/dist/cjs/internal/layer.js +1 -1
  44. package/dist/cjs/internal/layer.js.map +1 -1
  45. package/dist/cjs/internal/mailbox.js +1 -1
  46. package/dist/cjs/internal/mailbox.js.map +1 -1
  47. package/dist/cjs/internal/sink.js +25 -21
  48. package/dist/cjs/internal/sink.js.map +1 -1
  49. package/dist/cjs/internal/stream.js +70 -71
  50. package/dist/cjs/internal/stream.js.map +1 -1
  51. package/dist/cjs/internal/version.js +1 -1
  52. package/dist/cjs/internal/version.js.map +1 -1
  53. package/dist/dts/BigDecimal.d.ts +56 -1
  54. package/dist/dts/BigDecimal.d.ts.map +1 -1
  55. package/dist/dts/Channel.d.ts +66 -5
  56. package/dist/dts/Channel.d.ts.map +1 -1
  57. package/dist/dts/Config.d.ts +23 -1
  58. package/dist/dts/Config.d.ts.map +1 -1
  59. package/dist/dts/Context.d.ts +111 -0
  60. package/dist/dts/Context.d.ts.map +1 -1
  61. package/dist/dts/Cron.d.ts +15 -6
  62. package/dist/dts/Cron.d.ts.map +1 -1
  63. package/dist/dts/DateTime.d.ts +40 -49
  64. package/dist/dts/DateTime.d.ts.map +1 -1
  65. package/dist/dts/Effect.d.ts +88 -1
  66. package/dist/dts/Effect.d.ts.map +1 -1
  67. package/dist/dts/Inspectable.d.ts.map +1 -1
  68. package/dist/dts/JSONSchema.d.ts +1 -0
  69. package/dist/dts/JSONSchema.d.ts.map +1 -1
  70. package/dist/dts/Micro.d.ts +875 -872
  71. package/dist/dts/Micro.d.ts.map +1 -1
  72. package/dist/dts/STM.d.ts +2 -0
  73. package/dist/dts/STM.d.ts.map +1 -1
  74. package/dist/dts/Schema.d.ts +32 -0
  75. package/dist/dts/Schema.d.ts.map +1 -1
  76. package/dist/dts/Sink.d.ts +8 -0
  77. package/dist/dts/Sink.d.ts.map +1 -1
  78. package/dist/dts/Stream.d.ts +50 -32
  79. package/dist/dts/Stream.d.ts.map +1 -1
  80. package/dist/dts/Utils.d.ts +4 -0
  81. package/dist/dts/Utils.d.ts.map +1 -1
  82. package/dist/dts/internal/context.d.ts +1 -1
  83. package/dist/dts/internal/context.d.ts.map +1 -1
  84. package/dist/dts/internal/dateTime.d.ts +2 -0
  85. package/dist/dts/internal/dateTime.d.ts.map +1 -0
  86. package/dist/dts/internal/fiberRuntime.d.ts.map +1 -1
  87. package/dist/dts/internal/stream.d.ts.map +1 -1
  88. package/dist/esm/BigDecimal.js +119 -20
  89. package/dist/esm/BigDecimal.js.map +1 -1
  90. package/dist/esm/Channel.js +42 -2
  91. package/dist/esm/Channel.js.map +1 -1
  92. package/dist/esm/Config.js +7 -0
  93. package/dist/esm/Config.js.map +1 -1
  94. package/dist/esm/Context.js +25 -0
  95. package/dist/esm/Context.js.map +1 -1
  96. package/dist/esm/Cron.js +75 -67
  97. package/dist/esm/Cron.js.map +1 -1
  98. package/dist/esm/DateTime.js +112 -627
  99. package/dist/esm/DateTime.js.map +1 -1
  100. package/dist/esm/Effect.js +77 -0
  101. package/dist/esm/Effect.js.map +1 -1
  102. package/dist/esm/Inspectable.js +8 -4
  103. package/dist/esm/Inspectable.js.map +1 -1
  104. package/dist/esm/JSONSchema.js.map +1 -1
  105. package/dist/esm/Micro.js +1077 -1047
  106. package/dist/esm/Micro.js.map +1 -1
  107. package/dist/esm/STM.js.map +1 -1
  108. package/dist/esm/Schema.js +54 -0
  109. package/dist/esm/Schema.js.map +1 -1
  110. package/dist/esm/Sink.js +8 -0
  111. package/dist/esm/Sink.js.map +1 -1
  112. package/dist/esm/Stream.js +23 -5
  113. package/dist/esm/Stream.js.map +1 -1
  114. package/dist/esm/Utils.js +5 -0
  115. package/dist/esm/Utils.js.map +1 -1
  116. package/dist/esm/internal/channel/channelExecutor.js +5 -7
  117. package/dist/esm/internal/channel/channelExecutor.js.map +1 -1
  118. package/dist/esm/internal/channel.js +152 -129
  119. package/dist/esm/internal/channel.js.map +1 -1
  120. package/dist/esm/internal/config.js +11 -3
  121. package/dist/esm/internal/config.js.map +1 -1
  122. package/dist/esm/internal/context.js +42 -2
  123. package/dist/esm/internal/context.js.map +1 -1
  124. package/dist/esm/internal/dateTime.js +704 -0
  125. package/dist/esm/internal/dateTime.js.map +1 -0
  126. package/dist/esm/internal/fiberRuntime.js +31 -9
  127. package/dist/esm/internal/fiberRuntime.js.map +1 -1
  128. package/dist/esm/internal/groupBy.js +9 -3
  129. package/dist/esm/internal/groupBy.js.map +1 -1
  130. package/dist/esm/internal/layer.js +1 -1
  131. package/dist/esm/internal/layer.js.map +1 -1
  132. package/dist/esm/internal/mailbox.js +1 -1
  133. package/dist/esm/internal/mailbox.js.map +1 -1
  134. package/dist/esm/internal/sink.js +23 -20
  135. package/dist/esm/internal/sink.js.map +1 -1
  136. package/dist/esm/internal/stream.js +66 -69
  137. package/dist/esm/internal/stream.js.map +1 -1
  138. package/dist/esm/internal/version.js +1 -1
  139. package/dist/esm/internal/version.js.map +1 -1
  140. package/package.json +1 -1
  141. package/src/BigDecimal.ts +131 -21
  142. package/src/Channel.ts +81 -5
  143. package/src/Config.ts +24 -1
  144. package/src/Context.ts +119 -0
  145. package/src/Cron.ts +85 -68
  146. package/src/DateTime.ts +155 -757
  147. package/src/Effect.ts +340 -1
  148. package/src/Inspectable.ts +11 -7
  149. package/src/JSONSchema.ts +1 -0
  150. package/src/Micro.ts +2005 -1757
  151. package/src/STM.ts +2 -0
  152. package/src/Schema.ts +60 -0
  153. package/src/Sink.ts +11 -0
  154. package/src/Stream.ts +55 -44
  155. package/src/Utils.ts +8 -0
  156. package/src/internal/channel/channelExecutor.ts +37 -33
  157. package/src/internal/channel.ts +504 -467
  158. package/src/internal/config.ts +18 -6
  159. package/src/internal/context.ts +56 -4
  160. package/src/internal/dateTime.ts +1126 -0
  161. package/src/internal/fiberRuntime.ts +35 -16
  162. package/src/internal/groupBy.ts +13 -22
  163. package/src/internal/layer.ts +5 -8
  164. package/src/internal/mailbox.ts +6 -4
  165. package/src/internal/sink.ts +55 -35
  166. package/src/internal/stream.ts +299 -299
  167. package/src/internal/version.ts +1 -1
package/src/Micro.ts CHANGED
@@ -4,28 +4,33 @@
4
4
  * @since 3.4.0
5
5
  * @experimental
6
6
  */
7
- import type { Channel, ChannelTypeId } from "./Channel.js"
7
+ import * as Arr from "effect/Array"
8
+ import type { Channel } from "./Channel.js"
8
9
  import * as Context from "./Context.js"
9
- import type { Effect, EffectTypeId, EffectUnify, EffectUnifyIgnore } from "./Effect.js"
10
+ import type { Effect, EffectUnify, EffectUnifyIgnore } from "./Effect.js"
10
11
  import * as Effectable from "./Effectable.js"
11
12
  import * as Either from "./Either.js"
12
- import { constTrue, constVoid, dual, identity, type LazyArg } from "./Function.js"
13
+ import * as Equal from "./Equal.js"
14
+ import type { LazyArg } from "./Function.js"
15
+ import { constTrue, constVoid, dual, identity } from "./Function.js"
13
16
  import { globalValue } from "./GlobalValue.js"
17
+ import * as Hash from "./Hash.js"
14
18
  import type { TypeLambda } from "./HKT.js"
15
19
  import type { Inspectable } from "./Inspectable.js"
16
- import { NodeInspectSymbol, toStringUnknown } from "./Inspectable.js"
20
+ import { format, NodeInspectSymbol, toStringUnknown } from "./Inspectable.js"
21
+ import * as InternalContext from "./internal/context.js"
17
22
  import * as doNotation from "./internal/doNotation.js"
18
23
  import { StructuralPrototype } from "./internal/effectable.js"
19
- import { SingleShotGen } from "./internal/singleShotGen.js"
20
24
  import * as Option from "./Option.js"
21
- import { type Pipeable, pipeArguments } from "./Pipeable.js"
22
- import { hasProperty, isIterable, isTagged, type Predicate, type Refinement } from "./Predicate.js"
23
- import type { ReadonlyRecord } from "./Record.js"
24
- import type { Sink, SinkTypeId } from "./Sink.js"
25
- import type { Stream, StreamTypeId } from "./Stream.js"
26
- import type { Concurrency, Covariant, Equals, NoInfer, NotFunction, Simplify } from "./Types.js"
25
+ import type { Pipeable } from "./Pipeable.js"
26
+ import { pipeArguments } from "./Pipeable.js"
27
+ import type { Predicate, Refinement } from "./Predicate.js"
28
+ import { hasProperty, isIterable, isTagged } from "./Predicate.js"
29
+ import type { Sink } from "./Sink.js"
30
+ import type { Stream } from "./Stream.js"
31
+ import type { Concurrency, Covariant, Equals, NotFunction, Simplify } from "./Types.js"
27
32
  import type * as Unify from "./Unify.js"
28
- import { YieldWrap, yieldWrapGet } from "./Utils.js"
33
+ import { SingleShotGen, YieldWrap, yieldWrapGet } from "./Utils.js"
29
34
 
30
35
  /**
31
36
  * @since 3.4.0
@@ -44,16 +49,18 @@ export type TypeId = typeof TypeId
44
49
  /**
45
50
  * @since 3.4.0
46
51
  * @experimental
47
- * @category symbols
52
+ * @category MicroExit
48
53
  */
49
- export const runSymbol: unique symbol = Symbol.for("effect/Micro/runSymbol")
54
+ export const MicroExitTypeId: unique symbol = Symbol.for(
55
+ "effect/Micro/MicroExit"
56
+ )
50
57
 
51
58
  /**
52
59
  * @since 3.4.0
53
60
  * @experimental
54
- * @category symbols
61
+ * @category MicroExit
55
62
  */
56
- export type runSymbol = typeof runSymbol
63
+ export type MicroExitTypeId = typeof TypeId
57
64
 
58
65
  /**
59
66
  * A lightweight alternative to the `Effect` data type, with a subset of the functionality.
@@ -64,7 +71,6 @@ export type runSymbol = typeof runSymbol
64
71
  */
65
72
  export interface Micro<out A, out E = never, out R = never> extends Effect<A, E, R> {
66
73
  readonly [TypeId]: Micro.Variance<A, E, R>
67
- [runSymbol](env: Env<any>, onExit: (exit: MicroExit<A, E>) => void): void
68
74
  [Symbol.iterator](): MicroIterator<Micro<A, E, R>>
69
75
  [Unify.typeSymbol]?: unknown
70
76
  [Unify.unifySymbol]?: MicroUnify<this>
@@ -144,58 +150,6 @@ export interface MicroIterator<T extends Micro<any, any, any>> {
144
150
  next(...args: ReadonlyArray<any>): IteratorResult<YieldWrap<T>, Micro.Success<T>>
145
151
  }
146
152
 
147
- /**
148
- * @since 3.8.4
149
- * @experimental
150
- * @category models
151
- */
152
- export interface MicroClass {
153
- new<A, E = never, R = never>(): Micro<A, E, R>
154
- }
155
-
156
- // ----------------------------------------------------------------------------
157
- // Microable
158
- // ----------------------------------------------------------------------------
159
-
160
- const MicroProto = {
161
- ...Effectable.EffectPrototype,
162
- _op: "Micro",
163
- [TypeId]: {
164
- _A: identity,
165
- _E: identity,
166
- _R: identity
167
- },
168
- [Symbol.iterator]() {
169
- return new SingleShotGen(new YieldWrap(this)) as any
170
- }
171
- }
172
-
173
- const MicroBase: MicroClass = (function() {
174
- function Base() {}
175
- Base.prototype = MicroProto
176
- return Base as any
177
- })()
178
-
179
- /**
180
- * @since 3.8.4
181
- * @experimental
182
- * @category constructors
183
- */
184
- export abstract class Class<out A, out E = never, out R = never> extends MicroBase<A, E, R> {
185
- /**
186
- * @since 3.8.4
187
- * @experimental
188
- */
189
- abstract asMicro(): Micro<A, E, R>
190
- /**
191
- * @since 3.8.4
192
- * @experimental
193
- */
194
- [runSymbol](env: Env<any>, onExit: (exit: MicroExit<A, E>) => void): void {
195
- this.asMicro()[runSymbol](env, onExit)
196
- }
197
- }
198
-
199
153
  // ----------------------------------------------------------------------------
200
154
  // MicroCause
201
155
  // ----------------------------------------------------------------------------
@@ -221,7 +175,10 @@ export type MicroCauseTypeId = typeof MicroCauseTypeId
221
175
  * @experimental
222
176
  * @category MicroCause
223
177
  */
224
- export type MicroCause<E> = MicroCause.Die | MicroCause.Fail<E> | MicroCause.Interrupt
178
+ export type MicroCause<E> =
179
+ | MicroCause.Die
180
+ | MicroCause.Fail<E>
181
+ | MicroCause.Interrupt
225
182
 
226
183
  /**
227
184
  * @since 3.6.6
@@ -302,7 +259,12 @@ abstract class MicroCauseImpl<Tag extends string, E> extends globalThis.Error im
302
259
  message = originalError.message as string
303
260
  const messageLines = message.split("\n").length
304
261
  stack = originalError.stack
305
- ? `(${causeName}) ${originalError.stack.split("\n").slice(0, messageLines + 3).join("\n")}`
262
+ ? `(${causeName}) ${
263
+ originalError.stack
264
+ .split("\n")
265
+ .slice(0, messageLines + 3)
266
+ .join("\n")
267
+ }`
306
268
  : `${name}: ${message}`
307
269
  } else {
308
270
  name = causeName
@@ -329,7 +291,10 @@ abstract class MicroCauseImpl<Tag extends string, E> extends globalThis.Error im
329
291
  }
330
292
 
331
293
  class FailImpl<E> extends MicroCauseImpl<"Fail", E> implements MicroCause.Fail<E> {
332
- constructor(readonly error: E, traces: ReadonlyArray<string> = []) {
294
+ constructor(
295
+ readonly error: E,
296
+ traces: ReadonlyArray<string> = []
297
+ ) {
333
298
  super("Fail", error, traces)
334
299
  }
335
300
  }
@@ -339,10 +304,16 @@ class FailImpl<E> extends MicroCauseImpl<"Fail", E> implements MicroCause.Fail<E
339
304
  * @experimental
340
305
  * @category MicroCause
341
306
  */
342
- export const causeFail = <E>(error: E, traces: ReadonlyArray<string> = []): MicroCause<E> => new FailImpl(error, traces)
307
+ export const causeFail = <E>(
308
+ error: E,
309
+ traces: ReadonlyArray<string> = []
310
+ ): MicroCause<E> => new FailImpl(error, traces)
343
311
 
344
312
  class DieImpl extends MicroCauseImpl<"Die", never> implements MicroCause.Die {
345
- constructor(readonly defect: unknown, traces: ReadonlyArray<string> = []) {
313
+ constructor(
314
+ readonly defect: unknown,
315
+ traces: ReadonlyArray<string> = []
316
+ ) {
346
317
  super("Die", defect, traces)
347
318
  }
348
319
  }
@@ -352,8 +323,10 @@ class DieImpl extends MicroCauseImpl<"Die", never> implements MicroCause.Die {
352
323
  * @experimental
353
324
  * @category MicroCause
354
325
  */
355
- export const causeDie = (defect: unknown, traces: ReadonlyArray<string> = []): MicroCause<never> =>
356
- new DieImpl(defect, traces)
326
+ export const causeDie = (
327
+ defect: unknown,
328
+ traces: ReadonlyArray<string> = []
329
+ ): MicroCause<never> => new DieImpl(defect, traces)
357
330
 
358
331
  class InterruptImpl extends MicroCauseImpl<"Interrupt", never> implements MicroCause.Interrupt {
359
332
  constructor(traces: ReadonlyArray<string> = []) {
@@ -366,14 +339,18 @@ class InterruptImpl extends MicroCauseImpl<"Interrupt", never> implements MicroC
366
339
  * @experimental
367
340
  * @category MicroCause
368
341
  */
369
- export const causeInterrupt = (traces: ReadonlyArray<string> = []): MicroCause<never> => new InterruptImpl(traces)
342
+ export const causeInterrupt = (
343
+ traces: ReadonlyArray<string> = []
344
+ ): MicroCause<never> => new InterruptImpl(traces)
370
345
 
371
346
  /**
372
347
  * @since 3.4.6
373
348
  * @experimental
374
349
  * @category MicroCause
375
350
  */
376
- export const causeIsFail = <E>(self: MicroCause<E>): self is MicroCause.Fail<E> => self._tag === "Fail"
351
+ export const causeIsFail = <E>(
352
+ self: MicroCause<E>
353
+ ): self is MicroCause.Fail<E> => self._tag === "Fail"
377
354
 
378
355
  /**
379
356
  * @since 3.4.6
@@ -387,7 +364,9 @@ export const causeIsDie = <E>(self: MicroCause<E>): self is MicroCause.Die => se
387
364
  * @experimental
388
365
  * @category MicroCause
389
366
  */
390
- export const causeIsInterrupt = <E>(self: MicroCause<E>): self is MicroCause.Interrupt => self._tag === "Interrupt"
367
+ export const causeIsInterrupt = <E>(
368
+ self: MicroCause<E>
369
+ ): self is MicroCause.Interrupt => self._tag === "Interrupt"
391
370
 
392
371
  /**
393
372
  * @since 3.4.6
@@ -428,1690 +407,1963 @@ export const causeWithTrace: {
428
407
  })
429
408
 
430
409
  // ----------------------------------------------------------------------------
431
- // MicroExit
410
+ // Fiber
432
411
  // ----------------------------------------------------------------------------
433
412
 
434
413
  /**
435
- * @since 3.4.6
414
+ * @since 3.11.0
436
415
  * @experimental
437
- * @category MicroExit
416
+ * @category Fiber
438
417
  */
439
- export declare namespace MicroExit {
440
- /**
441
- * @since 3.4.6
442
- * @experimental
443
- * @category MicroExit
444
- */
445
- export type Success<A, E = never> = Either.Right<MicroCause<E>, A>
446
-
447
- /**
448
- * @since 3.4.6
449
- * @experimental
450
- * @category MicroExit
451
- */
452
- export type Failure<A, E = never> = Either.Left<MicroCause<E>, A>
453
- }
418
+ export const FiberTypeId = Symbol.for("effect/Micro/Fiber")
454
419
 
455
420
  /**
456
- * The MicroExit type is a data type that represents the result of a Micro
457
- * computation.
458
- *
459
- * It uses the `Either` data type to represent the success and failure cases.
460
- *
461
- * @since 3.4.6
421
+ * @since 3.11.0
462
422
  * @experimental
463
- * @category MicroExit
423
+ * @category Fiber
464
424
  */
465
- export type MicroExit<A, E = never> = MicroExit.Success<A, E> | MicroExit.Failure<A, E>
425
+ export type FiberTypeId = typeof FiberTypeId
466
426
 
467
427
  /**
468
- * @since 3.4.6
428
+ * @since 3.11.0
469
429
  * @experimental
470
- * @category MicroExit
430
+ * @category Fiber
471
431
  */
472
- export const exitInterrupt: MicroExit<never> = Either.left(causeInterrupt())
432
+ export interface Fiber<out A, out E = never> {
433
+ readonly [FiberTypeId]: Fiber.Variance<A, E>
473
434
 
474
- /**
475
- * @since 3.4.6
476
- * @experimental
477
- * @category MicroExit
478
- */
479
- export const exitSucceed: <A>(a: A) => MicroExit<A, never> = Either.right
435
+ readonly currentOpCount: number
436
+ readonly getRef: <I, A>(ref: Context.Reference<I, A>) => A
437
+ readonly context: Context.Context<never>
438
+ readonly addObserver: (cb: (exit: MicroExit<A, E>) => void) => () => void
439
+ readonly unsafeInterrupt: () => void
440
+ readonly unsafePoll: () => MicroExit<A, E> | undefined
441
+ }
480
442
 
481
443
  /**
482
- * @since 3.4.6
444
+ * @since 3.11.0
483
445
  * @experimental
484
- * @category MicroExit
446
+ * @category Fiber
485
447
  */
486
- export const exitFail = <E>(e: E): MicroExit<never, E> => Either.left(causeFail(e))
448
+ export declare namespace Fiber {
449
+ /**
450
+ * @since 3.11.0
451
+ * @experimental
452
+ * @category Fiber
453
+ */
454
+ export interface Variance<out A, out E = never> {
455
+ readonly _A: Covariant<A>
456
+ readonly _E: Covariant<E>
457
+ }
458
+ }
459
+
460
+ const fiberVariance = {
461
+ _A: identity,
462
+ _E: identity
463
+ }
464
+
465
+ class FiberImpl<in out A = any, in out E = any> implements Fiber<A, E> {
466
+ readonly [FiberTypeId]: Fiber.Variance<A, E>
467
+
468
+ readonly _stack: Array<Primitive> = []
469
+ readonly _observers: Array<(exit: MicroExit<A, E>) => void> = []
470
+ _exit: MicroExit<A, E> | undefined
471
+ public _children: Set<FiberImpl<any, any>> | undefined
472
+
473
+ public currentOpCount = 0
474
+
475
+ constructor(
476
+ public context: Context.Context<never>,
477
+ public interruptible = true
478
+ ) {
479
+ this[FiberTypeId] = fiberVariance
480
+ }
481
+
482
+ getRef<I, A>(ref: Context.Reference<I, A>): A {
483
+ return InternalContext.unsafeGetReference(this.context, ref)
484
+ }
485
+
486
+ addObserver(cb: (exit: MicroExit<A, E>) => void): () => void {
487
+ if (this._exit) {
488
+ cb(this._exit)
489
+ return constVoid
490
+ }
491
+ this._observers.push(cb)
492
+ return () => {
493
+ const index = this._observers.indexOf(cb)
494
+ if (index >= 0) {
495
+ this._observers.splice(index, 1)
496
+ }
497
+ }
498
+ }
499
+
500
+ _interrupted = false
501
+ unsafeInterrupt(): void {
502
+ if (this._exit) {
503
+ return
504
+ }
505
+ this._interrupted = true
506
+ if (this.interruptible) {
507
+ this.evaluate(exitInterrupt as any)
508
+ }
509
+ }
510
+
511
+ unsafePoll(): MicroExit<A, E> | undefined {
512
+ return this._exit
513
+ }
514
+
515
+ evaluate(effect: Primitive): void {
516
+ if (this._exit) {
517
+ return
518
+ } else if (this._yielded !== undefined) {
519
+ const yielded = this._yielded as () => void
520
+ this._yielded = undefined
521
+ yielded()
522
+ }
523
+ const exit = this.runLoop(effect)
524
+ if (exit === Yield) {
525
+ return
526
+ }
527
+
528
+ // the interruptChildren middlware is added in Micro.fork, so it can be
529
+ // tree-shaken if not used
530
+ const interruptChildren = fiberMiddleware.interruptChildren && fiberMiddleware.interruptChildren(this)
531
+ if (interruptChildren !== undefined) {
532
+ return this.evaluate(flatMap(interruptChildren, () => exit) as any)
533
+ }
534
+
535
+ this._exit = exit
536
+ for (let i = 0; i < this._observers.length; i++) {
537
+ this._observers[i](exit)
538
+ }
539
+ this._observers.length = 0
540
+ }
541
+
542
+ runLoop(effect: Primitive): MicroExit<A, E> | Yield {
543
+ let yielding = false
544
+ let current: Primitive | Yield = effect
545
+ this.currentOpCount = 0
546
+ try {
547
+ while (true) {
548
+ this.currentOpCount++
549
+ if (!yielding && this.getRef(CurrentScheduler).shouldYield(this as any)) {
550
+ yielding = true
551
+ const prev = current
552
+ current = flatMap(yieldNow, () => prev as any) as any
553
+ }
554
+ current = (current as any)[evaluate](this)
555
+ if (current === Yield) {
556
+ const yielded = this._yielded!
557
+ if (MicroExitTypeId in yielded) {
558
+ this._yielded = undefined
559
+ return yielded
560
+ }
561
+ return Yield
562
+ }
563
+ }
564
+ } catch (error) {
565
+ if (!hasProperty(current, evaluate)) {
566
+ return exitDie(`Micro/Fiber.runLoop: Not a valid effect: ${String(current)}`)
567
+ }
568
+ return exitDie(error)
569
+ }
570
+ }
571
+
572
+ getCont<S extends successCont | failureCont>(
573
+ symbol: S
574
+ ): Primitive & Record<S, (value: any, fiber: FiberImpl) => Primitive> | undefined {
575
+ while (true) {
576
+ const op = this._stack.pop()
577
+ if (!op) return undefined
578
+ const cont = op[ensureCont] && op[ensureCont](this)
579
+ if (cont) return { [symbol]: cont } as any
580
+ if (op[symbol]) return op as any
581
+ }
582
+ }
583
+
584
+ // cancel the yielded operation, or for the yielded exit value
585
+ _yielded: MicroExit<any, any> | (() => void) | undefined = undefined
586
+ yieldWith(value: MicroExit<any, any> | (() => void)): Yield {
587
+ this._yielded = value
588
+ return Yield
589
+ }
590
+
591
+ children(): Set<Fiber<any, any>> {
592
+ return this._children ??= new Set()
593
+ }
594
+ }
595
+
596
+ const fiberMiddleware = globalValue("effect/Micro/fiberMiddleware", () => ({
597
+ interruptChildren: undefined as ((fiber: FiberImpl) => Micro<void> | undefined) | undefined
598
+ }))
599
+
600
+ const fiberInterruptChildren = (fiber: FiberImpl) => {
601
+ if (fiber._children === undefined || fiber._children.size === 0) {
602
+ return undefined
603
+ }
604
+ return fiberInterruptAll(fiber._children)
605
+ }
487
606
 
488
607
  /**
489
- * @since 3.4.6
608
+ * @since 3.11.0
490
609
  * @experimental
491
- * @category MicroExit
610
+ * @category Fiber
492
611
  */
493
- export const exitDie = (defect: unknown): MicroExit<never> => Either.left(causeDie(defect))
612
+ export const fiberAwait = <A, E>(self: Fiber<A, E>): Micro<MicroExit<A, E>> =>
613
+ async((resume) => sync(self.addObserver((exit) => resume(succeed(exit)))))
494
614
 
495
615
  /**
496
- * @since 3.4.6
616
+ * @since 3.11.0
497
617
  * @experimental
498
- * @category MicroExit
618
+ * @category Fiber
499
619
  */
500
- export const exitFailCause: <E>(cause: MicroCause<E>) => MicroExit<never, E> = Either.left
620
+ export const fiberInterrupt = <A, E>(self: Fiber<A, E>): Micro<void> =>
621
+ suspend(() => {
622
+ self.unsafeInterrupt()
623
+ return asVoid(fiberAwait(self))
624
+ })
501
625
 
502
626
  /**
503
- * @since 3.4.6
627
+ * @since 3.11.0
504
628
  * @experimental
505
- * @category MicroExit
629
+ * @category Fiber
506
630
  */
507
- export const exitIsSuccess: <A, E>(self: MicroExit<A, E>) => self is MicroExit.Success<A, E> = Either.isRight
631
+ export const fiberInterruptAll = <A extends Iterable<Fiber<any, any>>>(fibers: A): Micro<void> =>
632
+ suspend(() => {
633
+ for (const fiber of fibers) fiber.unsafeInterrupt()
634
+ const iter = fibers[Symbol.iterator]()
635
+ const wait: Micro<void> = suspend(() => {
636
+ let result = iter.next()
637
+ while (!result.done) {
638
+ if (result.value.unsafePoll()) {
639
+ result = iter.next()
640
+ continue
641
+ }
642
+ const fiber = result.value
643
+ return async((resume) => {
644
+ fiber.addObserver((_) => {
645
+ resume(wait)
646
+ })
647
+ })
648
+ }
649
+ return exitVoid
650
+ })
651
+ return wait
652
+ })
653
+
654
+ const identifier = Symbol.for("effect/Micro/identifier")
655
+ type identifier = typeof identifier
656
+
657
+ const args = Symbol.for("effect/Micro/args")
658
+ type args = typeof args
659
+
660
+ const evaluate = Symbol.for("effect/Micro/evaluate")
661
+ type evaluate = typeof evaluate
662
+
663
+ const successCont = Symbol.for("effect/Micro/successCont")
664
+ type successCont = typeof successCont
665
+
666
+ const failureCont = Symbol.for("effect/Micro/failureCont")
667
+ type failureCont = typeof failureCont
668
+
669
+ const ensureCont = Symbol.for("effect/Micro/ensureCont")
670
+ type ensureCont = typeof ensureCont
671
+
672
+ const Yield = Symbol.for("effect/Micro/Yield")
673
+ type Yield = typeof Yield
674
+
675
+ interface Primitive {
676
+ readonly [identifier]: string
677
+ readonly [successCont]: ((value: unknown, fiber: FiberImpl) => Primitive | Yield) | undefined
678
+ readonly [failureCont]:
679
+ | ((cause: MicroCause<unknown>, fiber: FiberImpl) => Primitive | Yield)
680
+ | undefined
681
+ readonly [ensureCont]:
682
+ | ((fiber: FiberImpl) =>
683
+ | ((value: unknown, fiber: FiberImpl) => Primitive | Yield)
684
+ | undefined)
685
+ | undefined
686
+ [evaluate](fiber: FiberImpl): Primitive | Yield
687
+ }
688
+
689
+ const microVariance = {
690
+ _A: identity,
691
+ _E: identity,
692
+ _R: identity
693
+ }
694
+
695
+ const MicroProto = {
696
+ ...Effectable.EffectPrototype,
697
+ _op: "Micro",
698
+ [TypeId]: microVariance,
699
+ pipe() {
700
+ return pipeArguments(this, arguments)
701
+ },
702
+ [Symbol.iterator]() {
703
+ return new SingleShotGen(new YieldWrap(this)) as any
704
+ },
705
+ toJSON(this: Primitive) {
706
+ return {
707
+ _id: "effect/Micro",
708
+ op: this[identifier],
709
+ ...(args in this ? { args: this[args] } : undefined)
710
+ }
711
+ },
712
+ toString() {
713
+ return format(this)
714
+ },
715
+ [NodeInspectSymbol]() {
716
+ return format(this)
717
+ }
718
+ }
719
+
720
+ function defaultEvaluate(_fiber: FiberImpl): Primitive | Yield {
721
+ return exitDie(`Micro.evaluate: Not implemented`) as any
722
+ }
723
+
724
+ const makePrimitiveProto = <Op extends string>(options: {
725
+ readonly op: Op
726
+ readonly eval?: (fiber: FiberImpl) => Primitive | Micro<any, any, any> | Yield
727
+ readonly contA?: (this: Primitive, value: any, fiber: FiberImpl) => Primitive | Micro<any, any, any> | Yield
728
+ readonly contE?: (
729
+ this: Primitive,
730
+ cause: MicroCause<any>,
731
+ fiber: FiberImpl
732
+ ) => Primitive | Micro<any, any, any> | Yield
733
+ readonly ensure?: (this: Primitive, fiber: FiberImpl) => void | ((value: any, fiber: FiberImpl) => void)
734
+ }): Primitive => ({
735
+ ...MicroProto,
736
+ [identifier]: options.op,
737
+ [evaluate]: options.eval ?? defaultEvaluate,
738
+ [successCont]: options.contA,
739
+ [failureCont]: options.contE,
740
+ [ensureCont]: options.ensure
741
+ } as any)
742
+
743
+ const makePrimitive = <Fn extends (...args: Array<any>) => any, Single extends boolean = true>(options: {
744
+ readonly op: string
745
+ readonly single?: Single
746
+ readonly eval?: (
747
+ this: Primitive & { readonly [args]: Single extends true ? Parameters<Fn>[0] : Parameters<Fn> },
748
+ fiber: FiberImpl
749
+ ) => Primitive | Micro<any, any, any> | Yield
750
+ readonly contA?: (
751
+ this: Primitive & { readonly [args]: Single extends true ? Parameters<Fn>[0] : Parameters<Fn> },
752
+ value: any,
753
+ fiber: FiberImpl
754
+ ) => Primitive | Micro<any, any, any> | Yield
755
+ readonly contE?: (
756
+ this: Primitive & { readonly [args]: Single extends true ? Parameters<Fn>[0] : Parameters<Fn> },
757
+ cause: MicroCause<any>,
758
+ fiber: FiberImpl
759
+ ) => Primitive | Micro<any, any, any> | Yield
760
+ readonly ensure?: (
761
+ this: Primitive & { readonly [args]: Single extends true ? Parameters<Fn>[0] : Parameters<Fn> },
762
+ fiber: FiberImpl
763
+ ) => void | ((value: any, fiber: FiberImpl) => void)
764
+ }): Fn => {
765
+ const Proto = makePrimitiveProto(options as any)
766
+ return function() {
767
+ const self = Object.create(Proto)
768
+ self[args] = options.single === false ? arguments : arguments[0]
769
+ return self
770
+ } as Fn
771
+ }
772
+
773
+ const makeExit = <Fn extends (...args: Array<any>) => any, Prop extends string>(options: {
774
+ readonly op: "Success" | "Failure"
775
+ readonly prop: Prop
776
+ readonly eval: (
777
+ this:
778
+ & MicroExit<unknown, unknown>
779
+ & { [args]: Parameters<Fn>[0] },
780
+ fiber: FiberImpl<unknown, unknown>
781
+ ) => Primitive | Yield
782
+ }): Fn => {
783
+ const Proto = {
784
+ ...makePrimitiveProto(options),
785
+ [MicroExitTypeId]: MicroExitTypeId,
786
+ _tag: options.op,
787
+ get [options.prop](): any {
788
+ return (this as any)[args]
789
+ },
790
+ toJSON(this: any) {
791
+ return {
792
+ _id: "effect/Micro/Exit",
793
+ _tag: options.op,
794
+ [options.prop]: this[args]
795
+ }
796
+ },
797
+ [Equal.symbol](this: any, that: any): boolean {
798
+ return isMicroExit(that) && that._tag === options.op &&
799
+ Equal.equals(this[args], (that as any)[args])
800
+ },
801
+ [Hash.symbol](this: any): number {
802
+ return Hash.cached(this, Hash.combine(Hash.string(options.op))(Hash.hash(this[args])))
803
+ }
804
+ }
805
+ return function(value: unknown) {
806
+ const self = Object.create(Proto)
807
+ self[args] = value
808
+ self[successCont] = undefined
809
+ self[failureCont] = undefined
810
+ self[ensureCont] = undefined
811
+ return self
812
+ } as Fn
813
+ }
508
814
 
509
815
  /**
510
- * @since 3.4.6
816
+ * Creates a `Micro` effect that will succeed with the specified constant value.
817
+ *
818
+ * @since 3.4.0
511
819
  * @experimental
512
- * @category MicroExit
820
+ * @category constructors
513
821
  */
514
- export const exitIsFailure: <A, E>(self: MicroExit<A, E>) => self is MicroExit.Failure<A, E> = Either.isLeft
822
+ export const succeed: <A>(value: A) => Micro<A> = makeExit({
823
+ op: "Success",
824
+ prop: "value",
825
+ eval(fiber) {
826
+ const cont = fiber.getCont(successCont)
827
+ return cont ? cont[successCont](this[args], fiber) : fiber.yieldWith(this)
828
+ }
829
+ })
515
830
 
516
831
  /**
832
+ * Creates a `Micro` effect that will fail with the specified `MicroCause`.
833
+ *
517
834
  * @since 3.4.6
518
835
  * @experimental
519
- * @category MicroExit
836
+ * @category constructors
520
837
  */
521
- export const exitIsInterrupt = <A, E>(self: MicroExit<A, E>): self is Either.Left<MicroCause.Interrupt, A> =>
522
- exitIsFailure(self) && self.left._tag === "Interrupt"
838
+ export const failCause: <E>(cause: MicroCause<E>) => Micro<never, E> = makeExit({
839
+ op: "Failure",
840
+ prop: "cause",
841
+ eval(fiber) {
842
+ let cont = fiber.getCont(failureCont)
843
+ while (causeIsInterrupt(this[args]) && cont && fiber.interruptible) {
844
+ cont = fiber.getCont(failureCont)
845
+ }
846
+ return cont ? cont[failureCont](this[args], fiber) : fiber.yieldWith(this)
847
+ }
848
+ })
523
849
 
524
850
  /**
525
- * @since 3.4.6
851
+ * Creates a `Micro` effect that will fail with the specified error.
852
+ *
853
+ * This will result in a `CauseFail`, where the error is tracked at the
854
+ * type level.
855
+ *
856
+ * @since 3.4.0
526
857
  * @experimental
527
- * @category MicroExit
858
+ * @category constructors
528
859
  */
529
- export const exitIsFail = <A, E>(self: MicroExit<A, E>): self is Either.Left<MicroCause.Fail<E>, A> =>
530
- exitIsFailure(self) && self.left._tag === "Fail"
860
+ export const fail = <E>(error: E): Micro<never, E> => failCause(causeFail(error))
531
861
 
532
862
  /**
533
- * @since 3.4.6
863
+ * Creates a `Micro` effect that will succeed with the lazily evaluated value.
864
+ *
865
+ * If the evaluation of the value throws an error, the effect will fail with
866
+ * `CauseDie`.
867
+ *
868
+ * @since 3.4.0
534
869
  * @experimental
535
- * @category MicroExit
870
+ * @category constructors
536
871
  */
537
- export const exitIsDie = <A, E>(self: MicroExit<A, E>): self is Either.Left<MicroCause.Die, A> =>
538
- exitIsFailure(self) && self.left._tag === "Die"
872
+ export const sync: <A>(evaluate: LazyArg<A>) => Micro<A> = makePrimitive({
873
+ op: "Sync",
874
+ eval(fiber): Primitive | Yield {
875
+ const value = this[args]()
876
+ const cont = fiber.getCont(successCont)
877
+ return cont ? cont[successCont](value, fiber) : fiber.yieldWith(exitSucceed(value))
878
+ }
879
+ })
539
880
 
540
881
  /**
541
- * @since 3.4.6
882
+ * Lazily creates a `Micro` effect from the given side-effect.
883
+ *
884
+ * @since 3.4.0
542
885
  * @experimental
543
- * @category MicroExit
886
+ * @category constructors
544
887
  */
545
- export const exitVoid: MicroExit<void> = exitSucceed(void 0)
546
-
547
- // ----------------------------------------------------------------------------
548
- // env
549
- // ----------------------------------------------------------------------------
888
+ export const suspend: <A, E, R>(evaluate: LazyArg<Micro<A, E, R>>) => Micro<A, E, R> = makePrimitive({
889
+ op: "Suspend",
890
+ eval(_fiber) {
891
+ return this[args]()
892
+ }
893
+ })
550
894
 
551
895
  /**
896
+ * Pause the execution of the current `Micro` effect, and resume it on the next
897
+ * scheduler tick.
898
+ *
552
899
  * @since 3.4.0
553
900
  * @experimental
554
- * @category environment
901
+ * @category constructors
555
902
  */
556
- export const EnvTypeId = Symbol.for("effect/Micro/Env")
903
+ export const yieldNowWith: (priority?: number) => Micro<void> = makePrimitive({
904
+ op: "Yield",
905
+ eval(fiber) {
906
+ let resumed = false
907
+ fiber.getRef(CurrentScheduler).scheduleTask(() => {
908
+ if (resumed) return
909
+ fiber.evaluate(exitVoid as any)
910
+ }, this[args] ?? 0)
911
+ return fiber.yieldWith(() => {
912
+ resumed = true
913
+ })
914
+ }
915
+ })
557
916
 
558
917
  /**
918
+ * Pause the execution of the current `Micro` effect, and resume it on the next
919
+ * scheduler tick.
920
+ *
559
921
  * @since 3.4.0
560
922
  * @experimental
561
- * @category environment
923
+ * @category constructors
562
924
  */
563
- export type EnvTypeId = typeof EnvTypeId
925
+ export const yieldNow: Micro<void> = yieldNowWith(0)
564
926
 
565
927
  /**
566
- * @since 3.4.0
928
+ * Creates a `Micro` effect that will succeed with `Option.Some` of the value.
929
+ *
930
+ * @since 3.4.0
567
931
  * @experimental
568
- * @category environment
932
+ * @category constructors
569
933
  */
570
- export interface Env<R> extends Pipeable {
571
- readonly [EnvTypeId]: {
572
- _R: Covariant<R>
573
- }
574
- readonly refs: ReadonlyRecord<string, unknown>
575
- }
576
-
577
- const EnvProto = {
578
- [EnvTypeId]: {
579
- _R: identity
580
- },
581
- pipe() {
582
- return pipeArguments(this, arguments)
583
- }
584
- }
934
+ export const succeedSome = <A>(a: A): Micro<Option.Option<A>> => succeed(Option.some(a))
585
935
 
586
936
  /**
937
+ * Creates a `Micro` effect that will succeed with `Option.None`.
938
+ *
587
939
  * @since 3.4.0
588
940
  * @experimental
589
- * @category environment
941
+ * @category constructors
590
942
  */
591
- export const envMake = <R = never>(
592
- refs: Record<string, unknown>
593
- ): Env<R> => {
594
- const self = Object.create(EnvProto)
595
- self.refs = refs
596
- return self
597
- }
943
+ export const succeedNone: Micro<Option.Option<never>> = succeed(Option.none())
598
944
 
599
945
  /**
946
+ * Creates a `Micro` effect that will fail with the lazily evaluated `MicroCause`.
947
+ *
600
948
  * @since 3.4.0
601
949
  * @experimental
602
- * @category environment
950
+ * @category constructors
603
951
  */
604
- export const envUnsafeMakeEmpty = (): Env<never> => {
605
- const controller = new AbortController()
606
- const refs = Object.create(null)
607
- refs[currentAbortController.key] = controller
608
- refs[currentAbortSignal.key] = controller.signal
609
- refs[currentScheduler.key] = new MicroSchedulerDefault()
610
- return envMake(refs)
611
- }
952
+ export const failCauseSync = <E>(evaluate: LazyArg<MicroCause<E>>): Micro<never, E> =>
953
+ suspend(() => failCause(evaluate()))
612
954
 
613
955
  /**
956
+ * Creates a `Micro` effect that will die with the specified error.
957
+ *
958
+ * This will result in a `CauseDie`, where the error is not tracked at
959
+ * the type level.
960
+ *
614
961
  * @since 3.4.0
615
962
  * @experimental
616
- * @category environment
963
+ * @category constructors
617
964
  */
618
- export const envGet: {
619
- /**
620
- * @since 3.4.0
621
- * @experimental
622
- * @category environment
623
- */
624
- <A>(ref: EnvRef<A>): <R>(self: Env<R>) => A
625
- /**
626
- * @since 3.4.0
627
- * @experimental
628
- * @category environment
629
- */
630
- <A, R>(self: Env<R>, ref: EnvRef<A>): A
631
- } = dual(2, <R, A>(self: Env<R>, ref: EnvRef<A>): A => ref.key in self.refs ? (self.refs[ref.key] as A) : ref.initial)
965
+ export const die = (defect: unknown): Micro<never> => exitDie(defect)
966
+
967
+ /**
968
+ * Creates a `Micro` effect that will fail with the lazily evaluated error.
969
+ *
970
+ * This will result in a `CauseFail`, where the error is tracked at the
971
+ * type level.
972
+ *
973
+ * @since 3.4.6
974
+ * @experimental
975
+ * @category constructors
976
+ */
977
+ export const failSync = <E>(error: LazyArg<E>): Micro<never, E> => suspend(() => fail(error()))
632
978
 
633
979
  /**
980
+ * Converts an `Option` into a `Micro` effect, that will fail with
981
+ * `NoSuchElementException` if the option is `None`. Otherwise, it will succeed with the
982
+ * value of the option.
983
+ *
634
984
  * @since 3.4.0
635
985
  * @experimental
636
- * @category environment
986
+ * @category constructors
637
987
  */
638
- export const envSet: {
639
- /**
640
- * @since 3.4.0
641
- * @experimental
642
- * @category environment
643
- */
644
- <A>(ref: EnvRef<A>, value: A): <R>(self: Env<R>) => Env<R>
645
- /**
646
- * @since 3.4.0
647
- * @experimental
648
- * @category environment
649
- */
650
- <A, R>(self: Env<R>, ref: EnvRef<A>, value: A): Env<R>
651
- } = dual(3, <R, A>(self: Env<R>, ref: EnvRef<A>, value: A): Env<R> => {
652
- const refs = Object.assign(Object.create(null), self.refs)
653
- refs[ref.key] = value
654
- return envMake(refs)
655
- })
988
+ export const fromOption = <A>(option: Option.Option<A>): Micro<A, NoSuchElementException> =>
989
+ option._tag === "Some" ? succeed(option.value) : fail(new NoSuchElementException({}))
656
990
 
657
991
  /**
992
+ * Converts an `Either` into a `Micro` effect, that will fail with the left side
993
+ * of the either if it is a `Left`. Otherwise, it will succeed with the right
994
+ * side of the either.
995
+ *
658
996
  * @since 3.4.0
659
997
  * @experimental
660
- * @category environment
998
+ * @category constructors
661
999
  */
662
- export const envMutate: {
1000
+ export const fromEither = <R, L>(either: Either.Either<R, L>): Micro<R, L> =>
1001
+ either._tag === "Right" ? succeed(either.right) : fail(either.left)
1002
+
1003
+ const void_: Micro<void> = succeed(void 0)
1004
+ export {
663
1005
  /**
1006
+ * A `Micro` effect that will succeed with `void` (`undefined`).
1007
+ *
664
1008
  * @since 3.4.0
665
1009
  * @experimental
666
- * @category environment
1010
+ * @category constructors
667
1011
  */
668
- (f: (map: Record<string, unknown>) => void): <R>(self: Env<R>) => Env<R>
1012
+ void_ as void
1013
+ }
1014
+
1015
+ const try_ = <A, E>(options: {
1016
+ try: LazyArg<A>
1017
+ catch: (error: unknown) => E
1018
+ }): Micro<A, E> =>
1019
+ suspend(() => {
1020
+ try {
1021
+ return succeed(options.try())
1022
+ } catch (err) {
1023
+ return fail(options.catch(err))
1024
+ }
1025
+ })
1026
+ export {
669
1027
  /**
1028
+ * The `Micro` equivalent of a try / catch block, which allows you to map
1029
+ * thrown errors to a specific error type.
1030
+ *
670
1031
  * @since 3.4.0
671
1032
  * @experimental
672
- * @category environment
1033
+ * @category constructors
1034
+ * @example
1035
+ * ```ts
1036
+ * import { Micro } from "effect"
1037
+ *
1038
+ * Micro.try({
1039
+ * try: () => throw new Error("boom"),
1040
+ * catch: (cause) => new Error("caught", { cause })
1041
+ * })
1042
+ * ```
673
1043
  */
674
- <R>(self: Env<R>, f: (map: Record<string, unknown>) => void): Env<R>
675
- } = dual(
676
- 2,
677
- <R>(self: Env<R>, f: (map: Record<string, unknown>) => ReadonlyRecord<string, unknown>): Env<R> =>
678
- envMake(f(Object.assign(Object.create(null), self.refs)))
679
- )
1044
+ try_ as try
1045
+ }
680
1046
 
681
1047
  /**
682
- * Access the given `Context.Tag` from the environment.
1048
+ * Wrap a `Promise` into a `Micro` effect. Any errors will result in a
1049
+ * `CauseDie`.
683
1050
  *
684
1051
  * @since 3.4.0
685
1052
  * @experimental
686
- * @category environment
1053
+ * @category constructors
687
1054
  */
688
- export const service = <I, S>(tag: Context.Tag<I, S>): Micro<S, never, I> =>
689
- make(function(env, onExit) {
690
- onExit(exitSucceed(Context.get(envGet(env, currentContext) as Context.Context<I>, tag as any) as S))
691
- })
1055
+ export const promise = <A>(evaluate: (signal: AbortSignal) => PromiseLike<A>): Micro<A> =>
1056
+ asyncOptions<A>(function(resume, signal) {
1057
+ evaluate(signal!).then(
1058
+ (a) => resume(succeed(a)),
1059
+ (e) => resume(die(e))
1060
+ )
1061
+ }, evaluate.length !== 0)
692
1062
 
693
1063
  /**
694
- * Access the given `Context.Tag` from the environment, without tracking the
695
- * dependency at the type level.
1064
+ * Wrap a `Promise` into a `Micro` effect. Any errors will be caught and
1065
+ * converted into a specific error type.
696
1066
  *
697
- * It will return an `Option` of the service, depending on whether it is
698
- * available in the environment or not.
1067
+ * @since 3.4.0
1068
+ * @experimental
1069
+ * @category constructors
1070
+ * @example
1071
+ * ```ts
1072
+ * import { Micro } from "effect"
1073
+ *
1074
+ * Micro.tryPromise({
1075
+ * try: () => Promise.resolve("success"),
1076
+ * catch: (cause) => new Error("caught", { cause })
1077
+ * })
1078
+ * ```
1079
+ */
1080
+ export const tryPromise = <A, E>(options: {
1081
+ readonly try: (signal: AbortSignal) => PromiseLike<A>
1082
+ readonly catch: (error: unknown) => E
1083
+ }): Micro<A, E> =>
1084
+ asyncOptions<A, E>(function(resume, signal) {
1085
+ try {
1086
+ options.try(signal!).then(
1087
+ (a) => resume(succeed(a)),
1088
+ (e) => resume(fail(options.catch(e)))
1089
+ )
1090
+ } catch (err) {
1091
+ resume(fail(options.catch(err)))
1092
+ }
1093
+ }, options.try.length !== 0)
1094
+
1095
+ /**
1096
+ * Create a `Micro` effect using the current `Fiber`.
699
1097
  *
700
1098
  * @since 3.4.0
701
1099
  * @experimental
702
- * @category environment
1100
+ * @category constructors
703
1101
  */
704
- export const serviceOption = <I, S>(tag: Context.Tag<I, S>): Micro<Option.Option<S>> =>
705
- make(function(env, onExit) {
706
- onExit(exitSucceed(Context.getOption(envGet(env, currentContext) as Context.Context<I>, tag)))
707
- })
1102
+ export const withFiber: <A, E = never, R = never>(
1103
+ evaluate: (fiber: FiberImpl<A, E>) => Micro<A, E, R>
1104
+ ) => Micro<A, E, R> = makePrimitive({
1105
+ op: "WithFiber",
1106
+ eval(fiber) {
1107
+ return this[args](fiber)
1108
+ }
1109
+ })
708
1110
 
709
1111
  /**
710
- * Retrieve the current value of the given `EnvRef`.
1112
+ * Flush any yielded effects that are waiting to be executed.
711
1113
  *
712
1114
  * @since 3.4.0
713
1115
  * @experimental
714
- * @category environment
1116
+ * @category constructors
715
1117
  */
716
- export const getEnvRef = <A>(envRef: EnvRef<A>): Micro<A> =>
717
- make((env, onExit) => onExit(Either.right(envGet(env, envRef))))
1118
+ export const yieldFlush: Micro<void> = withFiber((fiber) => {
1119
+ fiber.getRef(CurrentScheduler).flush()
1120
+ return exitVoid
1121
+ })
1122
+
1123
+ const asyncOptions: <A, E = never, R = never>(
1124
+ register: (
1125
+ resume: (effect: Micro<A, E, R>) => void,
1126
+ signal?: AbortSignal
1127
+ ) => void | Micro<void, never, R>,
1128
+ withSignal: boolean
1129
+ ) => Micro<A, E, R> = makePrimitive({
1130
+ op: "Async",
1131
+ single: false,
1132
+ eval(fiber) {
1133
+ const register = this[args][0]
1134
+ let resumed = false
1135
+ let yielded: boolean | Primitive = false
1136
+ const controller = this[args][1] ? new AbortController() : undefined
1137
+ const onCancel = register((effect) => {
1138
+ if (resumed) return
1139
+ resumed = true
1140
+ if (yielded) {
1141
+ fiber.evaluate(effect as any)
1142
+ } else {
1143
+ yielded = effect as any
1144
+ }
1145
+ }, controller?.signal)
1146
+ if (yielded !== false) return yielded
1147
+ yielded = true
1148
+ fiber._yielded = () => {
1149
+ resumed = true
1150
+ }
1151
+ if (controller === undefined && onCancel === undefined) {
1152
+ return Yield
1153
+ }
1154
+ fiber._stack.push(asyncFinalizer(() => {
1155
+ resumed = true
1156
+ controller?.abort()
1157
+ return onCancel ?? exitVoid
1158
+ }))
1159
+ return Yield
1160
+ }
1161
+ })
1162
+ const asyncFinalizer: (onInterrupt: () => Micro<void, any, any>) => Primitive = makePrimitive({
1163
+ op: "AsyncFinalizer",
1164
+ ensure(fiber) {
1165
+ if (fiber.interruptible) {
1166
+ fiber.interruptible = false
1167
+ fiber._stack.push(setInterruptible(true))
1168
+ }
1169
+ },
1170
+ contE(cause, _fiber) {
1171
+ return causeIsInterrupt(cause)
1172
+ ? flatMap(this[args](), () => failCause(cause))
1173
+ : failCause(cause)
1174
+ }
1175
+ })
718
1176
 
719
1177
  /**
720
- * Set the value of the given `EnvRef` for the duration of the effect.
1178
+ * Create a `Micro` effect from an asynchronous computation.
1179
+ *
1180
+ * You can return a cleanup effect that will be run when the effect is aborted.
1181
+ * It is also passed an `AbortSignal` that is triggered when the effect is
1182
+ * aborted.
721
1183
  *
722
1184
  * @since 3.4.0
723
1185
  * @experimental
724
- * @category environment
1186
+ * @category constructors
725
1187
  */
726
- export const locally: {
727
- /**
728
- * Set the value of the given `EnvRef` for the duration of the effect.
729
- *
730
- * @since 3.4.0
731
- * @experimental
732
- * @category environment
733
- */
734
- <A>(fiberRef: EnvRef<A>, value: A): <XA, E, R>(self: Micro<XA, E, R>) => Micro<XA, E, R>
735
- /**
736
- * Set the value of the given `EnvRef` for the duration of the effect.
737
- *
738
- * @since 3.4.0
739
- * @experimental
740
- * @category environment
741
- */
742
- <XA, E, R, A>(self: Micro<XA, E, R>, fiberRef: EnvRef<A>, value: A): Micro<XA, E, R>
743
- } = dual(
744
- 3,
745
- <XA, E, R, A>(self: Micro<XA, E, R>, fiberRef: EnvRef<A>, value: A): Micro<XA, E, R> =>
746
- make((env, onExit) => self[runSymbol](envSet(env, fiberRef, value), onExit))
747
- )
1188
+ export const async = <A, E = never, R = never>(
1189
+ register: (
1190
+ resume: (effect: Micro<A, E, R>) => void,
1191
+ signal: AbortSignal
1192
+ ) => void | Micro<void, never, R>
1193
+ ): Micro<A, E, R> => asyncOptions(register as any, register.length >= 2)
748
1194
 
749
1195
  /**
750
- * Access the current `Context` from the environment.
1196
+ * A `Micro` that will never succeed or fail. It wraps `setInterval` to prevent
1197
+ * the Javascript runtime from exiting.
751
1198
  *
752
1199
  * @since 3.4.0
753
1200
  * @experimental
754
- * @category environment
1201
+ * @category constructors
755
1202
  */
756
- export const context = <R>(): Micro<Context.Context<R>> => getEnvRef(currentContext) as any
1203
+ export const never: Micro<never> = async<never>(function() {
1204
+ const interval = setInterval(constVoid, 2147483646)
1205
+ return sync(() => clearInterval(interval))
1206
+ })
757
1207
 
758
1208
  /**
759
- * Merge the given `Context` with the current context.
1209
+ * @since 3.4.0
1210
+ * @experimental
1211
+ * @category constructors
1212
+ */
1213
+ export const gen = <Self, Eff extends YieldWrap<Micro<any, any, any>>, AEff>(
1214
+ ...args:
1215
+ | [self: Self, body: (this: Self) => Generator<Eff, AEff, never>]
1216
+ | [body: () => Generator<Eff, AEff, never>]
1217
+ ): Micro<
1218
+ AEff,
1219
+ [Eff] extends [never] ? never : [Eff] extends [YieldWrap<Micro<infer _A, infer E, infer _R>>] ? E : never,
1220
+ [Eff] extends [never] ? never : [Eff] extends [YieldWrap<Micro<infer _A, infer _E, infer R>>] ? R : never
1221
+ > => suspend(() => fromIterator(args.length === 1 ? args[0]() : args[1].call(args[0]) as any))
1222
+
1223
+ const fromIterator: (
1224
+ iterator: Iterator<any, YieldWrap<Micro<any, any, any>>>
1225
+ ) => Micro<any, any, any> = makePrimitive({
1226
+ op: "Iterator",
1227
+ contA(value, fiber) {
1228
+ const state = this[args].next(value)
1229
+ if (state.done) return succeed(state.value)
1230
+ fiber._stack.push(this)
1231
+ return yieldWrapGet(state.value)
1232
+ },
1233
+ eval(this: any, fiber: FiberImpl) {
1234
+ return this[successCont](undefined, fiber)
1235
+ }
1236
+ })
1237
+
1238
+ // ----------------------------------------------------------------------------
1239
+ // mapping & sequencing
1240
+ // ----------------------------------------------------------------------------
1241
+
1242
+ /**
1243
+ * Create a `Micro` effect that will replace the success value of the given
1244
+ * effect.
760
1245
  *
761
1246
  * @since 3.4.0
762
1247
  * @experimental
763
- * @category environment
1248
+ * @category mapping & sequencing
764
1249
  */
765
- export const provideContext: {
1250
+ export const as: {
1251
+ // ----------------------------------------------------------------------------
1252
+ // mapping & sequencing
1253
+ // ----------------------------------------------------------------------------
1254
+
766
1255
  /**
767
- * Merge the given `Context` with the current context.
1256
+ * Create a `Micro` effect that will replace the success value of the given
1257
+ * effect.
768
1258
  *
769
1259
  * @since 3.4.0
770
1260
  * @experimental
771
- * @category environment
1261
+ * @category mapping & sequencing
772
1262
  */
773
- <XR>(context: Context.Context<XR>): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, Exclude<R, XR>>
774
- /**
775
- * Merge the given `Context` with the current context.
776
- *
1263
+ <A, B>(value: B): <E, R>(self: Micro<A, E, R>) => Micro<B, E, R>
1264
+ // ----------------------------------------------------------------------------
1265
+ // mapping & sequencing
1266
+ // ----------------------------------------------------------------------------
1267
+
1268
+ /**
1269
+ * Create a `Micro` effect that will replace the success value of the given
1270
+ * effect.
1271
+ *
777
1272
  * @since 3.4.0
778
1273
  * @experimental
779
- * @category environment
1274
+ * @category mapping & sequencing
780
1275
  */
781
- <A, E, R, XR>(self: Micro<A, E, R>, context: Context.Context<XR>): Micro<A, E, Exclude<R, XR>>
782
- } = dual(
783
- 2,
784
- <A, E, R, XR>(self: Micro<A, E, R>, provided: Context.Context<XR>): Micro<A, E, Exclude<R, XR>> =>
785
- make(function(env, onExit) {
786
- const context = envGet(env, currentContext)
787
- const nextEnv = envSet(env, currentContext, Context.merge(context, provided))
788
- self[runSymbol](nextEnv, onExit)
789
- })
790
- )
1276
+ <A, E, R, B>(self: Micro<A, E, R>, value: B): Micro<B, E, R>
1277
+ } = dual(2, <A, E, R, B>(self: Micro<A, E, R>, value: B): Micro<B, E, R> => map(self, (_) => value))
791
1278
 
792
1279
  /**
793
- * Add the provided service to the current context.
1280
+ * Wrap the success value of this `Micro` effect in an `Option.Some`.
794
1281
  *
795
1282
  * @since 3.4.0
796
1283
  * @experimental
797
- * @category environment
1284
+ * @category mapping & sequencing
798
1285
  */
799
- export const provideService: {
1286
+ export const asSome = <A, E, R>(self: Micro<A, E, R>): Micro<Option.Option<A>, E, R> => map(self, Option.some)
1287
+
1288
+ /**
1289
+ * Swap the error and success types of the `Micro` effect.
1290
+ *
1291
+ * @since 3.4.0
1292
+ * @experimental
1293
+ * @category mapping & sequencing
1294
+ */
1295
+ export const flip = <A, E, R>(self: Micro<A, E, R>): Micro<E, A, R> =>
1296
+ matchEffect(self, {
1297
+ onFailure: succeed,
1298
+ onSuccess: fail
1299
+ })
1300
+
1301
+ /**
1302
+ * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
1303
+ * a single api.
1304
+ *
1305
+ * It also allows you to pass in a `Micro` effect directly, which will be
1306
+ * executed after the current effect.
1307
+ *
1308
+ * @since 3.4.0
1309
+ * @experimental
1310
+ * @category mapping & sequencing
1311
+ */
1312
+ export const andThen: {
800
1313
  /**
801
- * Add the provided service to the current context.
1314
+ * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
1315
+ * a single api.
1316
+ *
1317
+ * It also allows you to pass in a `Micro` effect directly, which will be
1318
+ * executed after the current effect.
802
1319
  *
803
1320
  * @since 3.4.0
804
1321
  * @experimental
805
- * @category environment
1322
+ * @category mapping & sequencing
806
1323
  */
807
- <I, S>(tag: Context.Tag<I, S>, service: S): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, Exclude<R, I>>
1324
+ <A, X>(f: (a: A) => X): <E, R>(
1325
+ self: Micro<A, E, R>
1326
+ ) => [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1327
+ : Micro<X, E, R>
808
1328
  /**
809
- * Add the provided service to the current context.
1329
+ * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
1330
+ * a single api.
1331
+ *
1332
+ * It also allows you to pass in a `Micro` effect directly, which will be
1333
+ * executed after the current effect.
810
1334
  *
811
1335
  * @since 3.4.0
812
1336
  * @experimental
813
- * @category environment
1337
+ * @category mapping & sequencing
814
1338
  */
815
- <A, E, R, I, S>(self: Micro<A, E, R>, tag: Context.Tag<I, S>, service: S): Micro<A, E, Exclude<R, I>>
816
- } = dual(
817
- 3,
818
- <A, E, R, I, S>(self: Micro<A, E, R>, tag: Context.Tag<I, S>, service: S): Micro<A, E, Exclude<R, I>> =>
819
- make(function(env, onExit) {
820
- const context = envGet(env, currentContext)
821
- const nextEnv = envSet(env, currentContext, Context.add(context, tag, service))
822
- self[runSymbol](nextEnv, onExit)
823
- })
824
- )
825
-
826
- /**
827
- * Create a service using the provided `Micro` effect, and add it to the
828
- * current context.
829
- *
830
- * @since 3.4.6
831
- * @experimental
832
- * @category environment
833
- */
834
- export const provideServiceEffect: {
1339
+ <X>(f: NotFunction<X>): <A, E, R>(
1340
+ self: Micro<A, E, R>
1341
+ ) => [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1342
+ : Micro<X, E, R>
835
1343
  /**
836
- * Create a service using the provided `Micro` effect, and add it to the
837
- * current context.
1344
+ * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
1345
+ * a single api.
838
1346
  *
839
- * @since 3.4.6
1347
+ * It also allows you to pass in a `Micro` effect directly, which will be
1348
+ * executed after the current effect.
1349
+ *
1350
+ * @since 3.4.0
840
1351
  * @experimental
841
- * @category environment
1352
+ * @category mapping & sequencing
842
1353
  */
843
- <I, S, E2, R2>(
844
- tag: Context.Tag<I, S>,
845
- acquire: Micro<S, E2, R2>
846
- ): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E | E2, Exclude<R, I> | R2>
1354
+ <A, E, R, X>(
1355
+ self: Micro<A, E, R>,
1356
+ f: (a: A) => X
1357
+ ): [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1358
+ : Micro<X, E, R>
847
1359
  /**
848
- * Create a service using the provided `Micro` effect, and add it to the
849
- * current context.
1360
+ * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
1361
+ * a single api.
850
1362
  *
851
- * @since 3.4.6
1363
+ * It also allows you to pass in a `Micro` effect directly, which will be
1364
+ * executed after the current effect.
1365
+ *
1366
+ * @since 3.4.0
852
1367
  * @experimental
853
- * @category environment
1368
+ * @category mapping & sequencing
854
1369
  */
855
- <A, E, R, I, S, E2, R2>(
1370
+ <A, E, R, X>(
856
1371
  self: Micro<A, E, R>,
857
- tag: Context.Tag<I, S>,
858
- acquire: Micro<S, E2, R2>
859
- ): Micro<A, E | E2, Exclude<R, I> | R2>
1372
+ f: NotFunction<X>
1373
+ ): [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1374
+ : Micro<X, E, R>
860
1375
  } = dual(
861
- 3,
862
- <A, E, R, I, S, E2, R2>(
863
- self: Micro<A, E, R>,
864
- tag: Context.Tag<I, S>,
865
- acquire: Micro<S, E2, R2>
866
- ): Micro<A, E | E2, Exclude<R, I> | R2> => flatMap(acquire, (service) => provideService(self, tag, service))
1376
+ 2,
1377
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: any): Micro<B, E | E2, R | R2> =>
1378
+ flatMap(self, (a) => {
1379
+ const value = isMicro(f) ? f : typeof f === "function" ? f(a) : f
1380
+ return isMicro(value) ? value : succeed(value)
1381
+ })
867
1382
  )
868
1383
 
869
- // ----------------------------------------------------------------------------
870
- // scheduler
871
- // ----------------------------------------------------------------------------
872
-
873
1384
  /**
874
- * @since 3.5.9
875
- * @experimental
876
- * @category scheduler
877
- */
878
- export interface MicroScheduler {
879
- readonly scheduleTask: (task: () => void, priority: number) => void
880
- readonly shouldYield: (env: Env<unknown>) => boolean
881
- readonly flush: () => void
882
- }
883
-
884
- const setImmediate = "setImmediate" in globalThis ? globalThis.setImmediate : (f: () => void) => setTimeout(f, 0)
885
-
886
- /**
887
- * @since 3.5.9
1385
+ * Execute a side effect from the success value of the `Micro` effect.
1386
+ *
1387
+ * It is similar to the `andThen` api, but the success value is ignored.
1388
+ *
1389
+ * @since 3.4.0
888
1390
  * @experimental
889
- * @category scheduler
1391
+ * @category mapping & sequencing
890
1392
  */
891
- export class MicroSchedulerDefault implements MicroScheduler {
892
- private tasks: Array<() => void> = []
893
- private running = false
894
-
895
- /**
896
- * @since 3.5.9
897
- */
898
- scheduleTask(task: () => void, _priority: number) {
899
- this.tasks.push(task)
900
- if (!this.running) {
901
- this.running = true
902
- setImmediate(this.afterScheduled)
903
- }
904
- }
905
-
906
- /**
907
- * @since 3.5.9
908
- */
909
- afterScheduled = () => {
910
- this.running = false
911
- this.runTasks()
912
- }
913
-
914
- /**
915
- * @since 3.5.9
916
- */
917
- runTasks() {
918
- const tasks = this.tasks
919
- this.tasks = []
920
- for (let i = 0, len = tasks.length; i < len; i++) {
921
- tasks[i]()
922
- }
923
- }
924
-
1393
+ export const tap: {
925
1394
  /**
926
- * @since 3.5.9
1395
+ * Execute a side effect from the success value of the `Micro` effect.
1396
+ *
1397
+ * It is similar to the `andThen` api, but the success value is ignored.
1398
+ *
1399
+ * @since 3.4.0
1400
+ * @experimental
1401
+ * @category mapping & sequencing
927
1402
  */
928
- shouldYield(_env: Env<unknown>) {
929
- return false
930
- }
931
-
1403
+ <A, X>(f: (a: NoInfer<A>) => X): <E, R>(
1404
+ self: Micro<A, E, R>
1405
+ ) => [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1406
+ : Micro<A, E, R>
932
1407
  /**
933
- * @since 3.5.9
1408
+ * Execute a side effect from the success value of the `Micro` effect.
1409
+ *
1410
+ * It is similar to the `andThen` api, but the success value is ignored.
1411
+ *
1412
+ * @since 3.4.0
1413
+ * @experimental
1414
+ * @category mapping & sequencing
934
1415
  */
935
- flush() {
936
- while (this.tasks.length > 0) {
937
- this.runTasks()
938
- }
939
- }
940
- }
941
-
942
- // ========================================================================
943
- // Env refs
944
- // ========================================================================
945
-
946
- /**
947
- * @since 3.4.0
948
- * @experimental
949
- * @category environment
950
- */
951
- export const EnvRefTypeId: unique symbol = Symbol.for("effect/Micro/EnvRef")
952
-
953
- /**
954
- * @since 3.4.0
955
- * @experimental
956
- * @category environment
957
- */
958
- export type EnvRefTypeId = typeof EnvRefTypeId
959
-
960
- /**
961
- * @since 3.4.0
962
- * @experimental
963
- * @category environment
964
- */
965
- export interface EnvRef<A> extends Micro<A> {
966
- readonly [EnvRefTypeId]: EnvRefTypeId
967
- readonly key: string
968
- readonly initial: A
969
-
970
- [Unify.typeSymbol]?: unknown
971
- [Unify.unifySymbol]?: EnvRefUnify<this>
972
- [Unify.ignoreSymbol]?: EnvRefUnifyIgnore
973
- }
974
-
975
- /**
976
- * @category models
977
- * @since 3.8.4
978
- * @experimental
979
- */
980
- export interface EnvRefUnify<A extends { [Unify.typeSymbol]?: any }> extends MicroUnify<A> {
981
- EnvRef?: () => A[Unify.typeSymbol] extends EnvRef<infer A0> | infer _ ? EnvRef<A0> : never
982
- }
983
-
984
- /**
985
- * @category models
986
- * @since 3.8.4
987
- * @experimental
988
- */
989
- export interface EnvRefUnifyIgnore extends MicroUnifyIgnore {
990
- Micro?: true
991
- }
992
-
993
- const EnvRefProto: ThisType<EnvRef<any>> = {
994
- ...MicroProto,
995
- [EnvRefTypeId]: EnvRefTypeId,
996
- [runSymbol](env: Env<any>, onExit: (exit: MicroExit<any, any>) => void) {
997
- getEnvRef(this)[runSymbol](env, onExit)
998
- }
999
- }
1000
-
1001
- /**
1002
- * @since 3.4.0
1003
- * @experimental
1004
- * @category environment refs
1005
- */
1006
- export const envRefMake = <A>(key: string, initial: LazyArg<A>): EnvRef<A> =>
1007
- globalValue(key, () => {
1008
- const self = Object.create(EnvRefProto)
1009
- self.key = key
1010
- self.initial = initial()
1011
- return self
1012
- })
1013
-
1014
- /**
1015
- * @since 3.4.0
1016
- * @experimental
1017
- * @category environment refs
1018
- */
1019
- export const currentAbortController: EnvRef<AbortController> = envRefMake(
1020
- "effect/Micro/currentAbortController",
1021
- () => undefined as any
1022
- )
1023
-
1024
- /**
1025
- * @since 3.4.0
1026
- * @experimental
1027
- * @category environment refs
1028
- */
1029
- export const currentAbortSignal: EnvRef<AbortSignal> = envRefMake(
1030
- "effect/Micro/currentAbortSignal",
1031
- () => undefined as any
1032
- )
1033
-
1034
- /**
1035
- * @since 3.4.0
1036
- * @experimental
1037
- * @category environment refs
1038
- */
1039
- export const currentContext: EnvRef<Context.Context<never>> = envRefMake(
1040
- "effect/Micro/currentContext",
1041
- () => Context.empty()
1042
- )
1043
-
1044
- /**
1045
- * @since 3.4.0
1046
- * @experimental
1047
- * @category environment refs
1048
- */
1049
- export const currentConcurrency: EnvRef<"unbounded" | number> = envRefMake(
1050
- "effect/Micro/currentConcurrency",
1051
- () => "unbounded"
1052
- )
1053
-
1054
- /**
1055
- * @since 3.4.0
1056
- * @experimental
1057
- * @category environment refs
1058
- */
1059
- export const currentMaxDepthBeforeYield: EnvRef<number> = envRefMake(
1060
- "effect/Micro/currentMaxDepthBeforeYield",
1061
- () => 2048
1062
- )
1063
-
1064
- const currentInterruptible: EnvRef<boolean> = envRefMake(
1065
- "effect/Micro/currentInterruptible",
1066
- () => true
1067
- )
1068
-
1069
- /**
1070
- * @since 3.4.0
1071
- * @experimental
1072
- * @category environment refs
1073
- */
1074
- export const currentScheduler: EnvRef<MicroScheduler> = envRefMake(
1075
- "effect/Micro/currentScheduler",
1076
- () => new MicroSchedulerDefault()
1077
- )
1078
-
1079
- /**
1080
- * If you have a `Micro` that uses `concurrency: "inherit"`, you can use this
1081
- * api to control the concurrency of that `Micro` when it is run.
1082
- *
1083
- * @since 3.4.0
1084
- * @experimental
1085
- * @category environment refs
1086
- * @example
1087
- * ```ts
1088
- * import * as Micro from "effect/Micro"
1089
- *
1090
- * Micro.forEach([1, 2, 3], (n) => Micro.succeed(n), {
1091
- * concurrency: "inherit"
1092
- * }).pipe(
1093
- * Micro.withConcurrency(2) // use a concurrency of 2
1094
- * )
1095
- * ```
1096
- */
1097
- export const withConcurrency: {
1416
+ <X>(f: NotFunction<X>): <A, E, R>(
1417
+ self: Micro<A, E, R>
1418
+ ) => [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1419
+ : Micro<A, E, R>
1098
1420
  /**
1099
- * If you have a `Micro` that uses `concurrency: "inherit"`, you can use this
1100
- * api to control the concurrency of that `Micro` when it is run.
1421
+ * Execute a side effect from the success value of the `Micro` effect.
1422
+ *
1423
+ * It is similar to the `andThen` api, but the success value is ignored.
1101
1424
  *
1102
1425
  * @since 3.4.0
1103
1426
  * @experimental
1104
- * @category environment refs
1105
- * @example
1106
- * ```ts
1107
- * import * as Micro from "effect/Micro"
1108
- *
1109
- * Micro.forEach([1, 2, 3], (n) => Micro.succeed(n), {
1110
- * concurrency: "inherit"
1111
- * }).pipe(
1112
- * Micro.withConcurrency(2) // use a concurrency of 2
1113
- * )
1114
- * ```
1427
+ * @category mapping & sequencing
1115
1428
  */
1116
- (concurrency: "unbounded" | number): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, R>
1429
+ <A, E, R, X>(
1430
+ self: Micro<A, E, R>,
1431
+ f: (a: NoInfer<A>) => X
1432
+ ): [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1433
+ : Micro<A, E, R>
1117
1434
  /**
1118
- * If you have a `Micro` that uses `concurrency: "inherit"`, you can use this
1119
- * api to control the concurrency of that `Micro` when it is run.
1435
+ * Execute a side effect from the success value of the `Micro` effect.
1436
+ *
1437
+ * It is similar to the `andThen` api, but the success value is ignored.
1120
1438
  *
1121
1439
  * @since 3.4.0
1122
1440
  * @experimental
1123
- * @category environment refs
1124
- * @example
1125
- * ```ts
1126
- * import * as Micro from "effect/Micro"
1127
- *
1128
- * Micro.forEach([1, 2, 3], (n) => Micro.succeed(n), {
1129
- * concurrency: "inherit"
1130
- * }).pipe(
1131
- * Micro.withConcurrency(2) // use a concurrency of 2
1132
- * )
1133
- * ```
1441
+ * @category mapping & sequencing
1134
1442
  */
1135
- <A, E, R>(self: Micro<A, E, R>, concurrency: "unbounded" | number): Micro<A, E, R>
1443
+ <A, E, R, X>(
1444
+ self: Micro<A, E, R>,
1445
+ f: NotFunction<X>
1446
+ ): [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1447
+ : Micro<A, E, R>
1136
1448
  } = dual(
1137
1449
  2,
1138
- <A, E, R>(self: Micro<A, E, R>, concurrency: "unbounded" | number): Micro<A, E, R> =>
1139
- locally(self, currentConcurrency, concurrency)
1450
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2> =>
1451
+ flatMap(self, (a) => {
1452
+ const value = isMicro(f) ? f : typeof f === "function" ? f(a) : f
1453
+ return isMicro(value) ? as(value, a) : succeed(a)
1454
+ })
1140
1455
  )
1141
1456
 
1142
- // ----------------------------------------------------------------------------
1143
- // constructors
1144
- // ----------------------------------------------------------------------------
1145
-
1146
- const microDepthState = globalValue("effect/Micro/microDepthState", () => ({
1147
- depth: 0,
1148
- maxDepthBeforeYield: currentMaxDepthBeforeYield.initial
1149
- }))
1150
-
1151
- const unsafeMake = <R, A, E>(
1152
- run: (env: Env<R>, onExit: (exit: MicroExit<A, E>) => void) => void
1153
- ): Micro<A, E, R> => {
1154
- const self = Object.create(MicroProto)
1155
- self[runSymbol] = run
1156
- return self
1157
- }
1158
-
1159
- const unsafeMakeOptions = <R, A, E>(
1160
- run: (env: Env<R>, onExit: (exit: MicroExit<A, E>) => void) => void,
1161
- checkAbort: boolean
1162
- ): Micro<A, E, R> =>
1163
- unsafeMake(function execute(env, onExit) {
1164
- if (
1165
- checkAbort && env.refs[currentInterruptible.key] !== false &&
1166
- (env.refs[currentAbortSignal.key] as AbortSignal).aborted
1167
- ) {
1168
- return onExit(exitInterrupt)
1169
- }
1170
- microDepthState.depth++
1171
- if (microDepthState.depth === 1) {
1172
- microDepthState.maxDepthBeforeYield = envGet(env, currentMaxDepthBeforeYield)
1173
- }
1174
- const scheduler = env.refs[currentScheduler.key] as MicroScheduler
1175
- if (microDepthState.depth >= microDepthState.maxDepthBeforeYield || scheduler.shouldYield(env)) {
1176
- scheduler.scheduleTask(() => execute(env, onExit), 0)
1177
- } else {
1178
- try {
1179
- run(env, onExit)
1180
- } catch (err) {
1181
- onExit(exitDie(err))
1182
- }
1183
- }
1184
- microDepthState.depth--
1185
- })
1186
-
1187
1457
  /**
1188
- * A low-level constructor for creating a `Micro` effect. It takes a function
1189
- * that receives an environment and a callback which should be called with the
1190
- * result of the effect.
1458
+ * Replace the success value of the `Micro` effect with `void`.
1191
1459
  *
1192
1460
  * @since 3.4.0
1193
1461
  * @experimental
1194
- * @category constructors
1462
+ * @category mapping & sequencing
1195
1463
  */
1196
- export const make = <R, A, E>(
1197
- run: (env: Env<R>, onExit: (exit: MicroExit<A, E>) => void) => void
1198
- ): Micro<A, E, R> => unsafeMakeOptions(run, true)
1464
+ export const asVoid = <A, E, R>(self: Micro<A, E, R>): Micro<void, E, R> => flatMap(self, (_) => exitVoid)
1199
1465
 
1200
1466
  /**
1201
- * Converts a `MicroExit` into a `Micro` effect.
1467
+ * Access the `MicroExit` of the given `Micro` effect.
1202
1468
  *
1203
1469
  * @since 3.4.6
1204
1470
  * @experimental
1205
- * @category constructors
1471
+ * @category mapping & sequencing
1206
1472
  */
1207
- export const fromExit = <A, E>(self: MicroExit<A, E>): Micro<A, E> =>
1208
- make(function(_env, onExit) {
1209
- onExit(self)
1473
+ export const exit = <A, E, R>(self: Micro<A, E, R>): Micro<MicroExit<A, E>, never, R> =>
1474
+ matchCause(self, {
1475
+ onFailure: exitFailCause,
1476
+ onSuccess: exitSucceed
1210
1477
  })
1211
1478
 
1212
1479
  /**
1213
- * Converts a lazy `MicroExit` into a `Micro` effect.
1480
+ * Replace the error type of the given `Micro` with the full `MicroCause` object.
1214
1481
  *
1215
- * @since 3.4.6
1482
+ * @since 3.4.0
1216
1483
  * @experimental
1217
- * @category constructors
1484
+ * @category mapping & sequencing
1218
1485
  */
1219
- export const fromExitSync = <A, E>(self: LazyArg<MicroExit<A, E>>): Micro<A, E> =>
1220
- make(function(_env, onExit) {
1221
- onExit(self())
1222
- })
1486
+ export const sandbox = <A, E, R>(self: Micro<A, E, R>): Micro<A, MicroCause<E>, R> => catchAllCause(self, fail)
1223
1487
 
1224
1488
  /**
1225
- * Creates a `Micro` effect that will succeed with the specified constant value.
1489
+ * Returns an effect that races all the specified effects,
1490
+ * yielding the value of the first effect to succeed with a value. Losers of
1491
+ * the race will be interrupted immediately
1226
1492
  *
1227
1493
  * @since 3.4.0
1228
1494
  * @experimental
1229
- * @category constructors
1495
+ * @category sequencing
1230
1496
  */
1231
- export const succeed = <A>(a: A): Micro<A> => fromExit(exitSucceed(a))
1497
+ export const raceAll = <Eff extends Micro<any, any, any>>(
1498
+ all: Iterable<Eff>
1499
+ ): Micro<Micro.Success<Eff>, Micro.Error<Eff>, Micro.Context<Eff>> =>
1500
+ withFiber((parent) =>
1501
+ async((resume) => {
1502
+ const effects = Arr.fromIterable(all)
1503
+ const len = effects.length
1504
+ let doneCount = 0
1505
+ let done = false
1506
+ const fibers = new Set<Fiber<any, any>>()
1507
+ const causes: Array<MicroCause<any>> = []
1508
+ const onExit = (exit: MicroExit<any, any>) => {
1509
+ doneCount++
1510
+ if (exit._tag === "Failure") {
1511
+ causes.push(exit.cause)
1512
+ if (doneCount >= len) {
1513
+ resume(failCause(causes[0]))
1514
+ }
1515
+ return
1516
+ }
1517
+ done = true
1518
+ resume(fibers.size === 0 ? exit : flatMap(uninterruptible(fiberInterruptAll(fibers)), () => exit))
1519
+ }
1520
+
1521
+ for (let i = 0; i < len; i++) {
1522
+ if (done) break
1523
+ const fiber = unsafeFork(parent, interruptible(effects[i]), true, true)
1524
+ fibers.add(fiber)
1525
+ fiber.addObserver((exit) => {
1526
+ fibers.delete(fiber)
1527
+ onExit(exit)
1528
+ })
1529
+ }
1530
+
1531
+ return fiberInterruptAll(fibers)
1532
+ })
1533
+ )
1232
1534
 
1233
1535
  /**
1234
- * Creates a `Micro` effect that will succeed with `Option.Some` of the value.
1536
+ * Returns an effect that races all the specified effects,
1537
+ * yielding the value of the first effect to succeed or fail. Losers of
1538
+ * the race will be interrupted immediately
1235
1539
  *
1236
1540
  * @since 3.4.0
1237
1541
  * @experimental
1238
- * @category constructors
1542
+ * @category sequencing
1239
1543
  */
1240
- export const succeedSome = <A>(a: A): Micro<Option.Option<A>> => succeed(Option.some(a))
1544
+ export const raceAllFirst = <Eff extends Micro<any, any, any>>(
1545
+ all: Iterable<Eff>
1546
+ ): Micro<Micro.Success<Eff>, Micro.Error<Eff>, Micro.Context<Eff>> =>
1547
+ withFiber((parent) =>
1548
+ async((resume) => {
1549
+ let done = false
1550
+ const fibers = new Set<Fiber<any, any>>()
1551
+ const onExit = (exit: MicroExit<any, any>) => {
1552
+ done = true
1553
+ resume(fibers.size === 0 ? exit : flatMap(fiberInterruptAll(fibers), () => exit))
1554
+ }
1555
+
1556
+ for (const effect of all) {
1557
+ if (done) break
1558
+ const fiber = unsafeFork(parent, interruptible(effect), true, true)
1559
+ fibers.add(fiber)
1560
+ fiber.addObserver((exit) => {
1561
+ fibers.delete(fiber)
1562
+ onExit(exit)
1563
+ })
1564
+ }
1565
+
1566
+ return fiberInterruptAll(fibers)
1567
+ })
1568
+ )
1241
1569
 
1242
1570
  /**
1243
- * Creates a `Micro` effect that will succeed with `Option.None`.
1571
+ * Returns an effect that races two effects, yielding the value of the first
1572
+ * effect to succeed. Losers of the race will be interrupted immediately
1244
1573
  *
1245
1574
  * @since 3.4.0
1246
1575
  * @experimental
1247
- * @category constructors
1576
+ * @category sequencing
1248
1577
  */
1249
- export const succeedNone: Micro<Option.Option<never>> = succeed(Option.none())
1578
+ export const race: {
1579
+ /**
1580
+ * Returns an effect that races two effects, yielding the value of the first
1581
+ * effect to succeed. Losers of the race will be interrupted immediately
1582
+ *
1583
+ * @since 3.4.0
1584
+ * @experimental
1585
+ * @category sequencing
1586
+ */
1587
+ <A2, E2, R2>(that: Micro<A2, E2, R2>): <A, E, R>(self: Micro<A, E, R>) => Micro<A | A2, E | E2, R | R2>
1588
+ /**
1589
+ * Returns an effect that races two effects, yielding the value of the first
1590
+ * effect to succeed. Losers of the race will be interrupted immediately
1591
+ *
1592
+ * @since 3.4.0
1593
+ * @experimental
1594
+ * @category sequencing
1595
+ */
1596
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2>
1597
+ } = dual(
1598
+ 2,
1599
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2> =>
1600
+ raceAll([self, that])
1601
+ )
1250
1602
 
1251
1603
  /**
1252
- * Creates a `Micro` effect that will fail with the specified error.
1604
+ * Returns an effect that races two effects, yielding the value of the first
1605
+ * effect to succeed *or* fail. Losers of the race will be interrupted immediately
1253
1606
  *
1254
- * This will result in a `CauseFail`, where the error is tracked at the
1255
- * type level.
1607
+ * @since 3.4.0
1608
+ * @experimental
1609
+ * @category sequencing
1610
+ */
1611
+ export const raceFirst: {
1612
+ /**
1613
+ * Returns an effect that races two effects, yielding the value of the first
1614
+ * effect to succeed *or* fail. Losers of the race will be interrupted immediately
1615
+ *
1616
+ * @since 3.4.0
1617
+ * @experimental
1618
+ * @category sequencing
1619
+ */
1620
+ <A2, E2, R2>(that: Micro<A2, E2, R2>): <A, E, R>(self: Micro<A, E, R>) => Micro<A | A2, E | E2, R | R2>
1621
+ /**
1622
+ * Returns an effect that races two effects, yielding the value of the first
1623
+ * effect to succeed *or* fail. Losers of the race will be interrupted immediately
1624
+ *
1625
+ * @since 3.4.0
1626
+ * @experimental
1627
+ * @category sequencing
1628
+ */
1629
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2>
1630
+ } = dual(
1631
+ 2,
1632
+ <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2> =>
1633
+ raceAllFirst([self, that])
1634
+ )
1635
+
1636
+ /**
1637
+ * Map the success value of this `Micro` effect to another `Micro` effect, then
1638
+ * flatten the result.
1256
1639
  *
1257
1640
  * @since 3.4.0
1258
1641
  * @experimental
1259
- * @category constructors
1642
+ * @category mapping & sequencing
1260
1643
  */
1261
- export const fail = <E>(e: E): Micro<never, E> => fromExit(exitFail(e))
1644
+ export const flatMap: {
1645
+ /**
1646
+ * Map the success value of this `Micro` effect to another `Micro` effect, then
1647
+ * flatten the result.
1648
+ *
1649
+ * @since 3.4.0
1650
+ * @experimental
1651
+ * @category mapping & sequencing
1652
+ */
1653
+ <A, B, E2, R2>(f: (a: A) => Micro<B, E2, R2>): <E, R>(self: Micro<A, E, R>) => Micro<B, E | E2, R | R2>
1654
+ /**
1655
+ * Map the success value of this `Micro` effect to another `Micro` effect, then
1656
+ * flatten the result.
1657
+ *
1658
+ * @since 3.4.0
1659
+ * @experimental
1660
+ * @category mapping & sequencing
1661
+ */
1662
+ <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<B, E | E2, R | R2>
1663
+ } = dual(
1664
+ 2,
1665
+ <A, E, R, B, E2, R2>(
1666
+ self: Micro<A, E, R>,
1667
+ f: (a: A) => Micro<B, E2, R2>
1668
+ ): Micro<B, E | E2, R | R2> => {
1669
+ const onSuccess = Object.create(OnSuccessProto)
1670
+ onSuccess[args] = self
1671
+ onSuccess[successCont] = f
1672
+ return onSuccess
1673
+ }
1674
+ )
1675
+ const OnSuccessProto = makePrimitiveProto({
1676
+ op: "OnSuccess",
1677
+ eval(this: any, fiber: FiberImpl): Primitive {
1678
+ fiber._stack.push(this)
1679
+ return this[args]
1680
+ }
1681
+ })
1682
+
1683
+ // ----------------------------------------------------------------------------
1684
+ // mapping & sequencing
1685
+ // ----------------------------------------------------------------------------
1262
1686
 
1263
1687
  /**
1264
- * Creates a `Micro` effect that will fail with the lazily evaluated error.
1688
+ * Flattens any nested `Micro` effects, merging the error and requirement types.
1265
1689
  *
1266
- * This will result in a `CauseFail`, where the error is tracked at the
1267
- * type level.
1690
+ * @since 3.4.0
1691
+ * @experimental
1692
+ * @category mapping & sequencing
1693
+ */
1694
+ export const flatten = <A, E, R, E2, R2>(
1695
+ self: Micro<Micro<A, E, R>, E2, R2>
1696
+ ): Micro<A, E | E2, R | R2> => flatMap(self, identity)
1697
+
1698
+ /**
1699
+ * Transforms the success value of the `Micro` effect with the specified
1700
+ * function.
1268
1701
  *
1269
1702
  * @since 3.4.0
1270
1703
  * @experimental
1271
- * @category constructors
1704
+ * @category mapping & sequencing
1272
1705
  */
1273
- export const failSync = <E>(e: LazyArg<E>): Micro<never, E> =>
1274
- make(function(_env, onExit) {
1275
- onExit(exitFail(e()))
1276
- })
1706
+ export const map: {
1707
+ /**
1708
+ * Transforms the success value of the `Micro` effect with the specified
1709
+ * function.
1710
+ *
1711
+ * @since 3.4.0
1712
+ * @experimental
1713
+ * @category mapping & sequencing
1714
+ */
1715
+ <A, B>(f: (a: A) => B): <E, R>(self: Micro<A, E, R>) => Micro<B, E, R>
1716
+ /**
1717
+ * Transforms the success value of the `Micro` effect with the specified
1718
+ * function.
1719
+ *
1720
+ * @since 3.4.0
1721
+ * @experimental
1722
+ * @category mapping & sequencing
1723
+ */
1724
+ <A, E, R, B>(self: Micro<A, E, R>, f: (a: A) => B): Micro<B, E, R>
1725
+ } = dual(
1726
+ 2,
1727
+ <A, E, R, B>(self: Micro<A, E, R>, f: (a: A) => B): Micro<B, E, R> => flatMap(self, (a) => succeed(f(a)))
1728
+ )
1729
+
1730
+ // ----------------------------------------------------------------------------
1731
+ // MicroExit
1732
+ // ----------------------------------------------------------------------------
1277
1733
 
1278
1734
  /**
1279
- * Creates a `Micro` effect that will die with the specified error.
1735
+ * The MicroExit type is a data type that represents the result of a Micro
1736
+ * computation.
1280
1737
  *
1281
- * This will result in a `CauseDie`, where the error is not tracked at
1282
- * the type level.
1738
+ * It uses the `Either` data type to represent the success and failure cases.
1283
1739
  *
1284
- * @since 3.4.0
1740
+ * @since 3.4.6
1285
1741
  * @experimental
1286
- * @category constructors
1742
+ * @category MicroExit
1743
+ */
1744
+ export type MicroExit<A, E = never> =
1745
+ | MicroExit.Success<A, E>
1746
+ | MicroExit.Failure<A, E>
1747
+
1748
+ /**
1749
+ * @since 3.4.6
1750
+ * @experimental
1751
+ * @category MicroExit
1287
1752
  */
1288
- export const die = (defect: unknown): Micro<never> => fromExit(exitDie(defect))
1753
+ export declare namespace MicroExit {
1754
+ /**
1755
+ * @since 3.4.6
1756
+ * @experimental
1757
+ * @category MicroExit
1758
+ */
1759
+ export interface Proto<out A, out E = never> extends Micro<A, E> {
1760
+ readonly [MicroExitTypeId]: MicroExitTypeId
1761
+ }
1762
+
1763
+ /**
1764
+ * @since 3.4.6
1765
+ * @experimental
1766
+ * @category MicroExit
1767
+ */
1768
+ export interface Success<out A, out E> extends Proto<A, E> {
1769
+ readonly _tag: "Success"
1770
+ readonly value: A
1771
+ }
1772
+
1773
+ /**
1774
+ * @since 3.4.6
1775
+ * @experimental
1776
+ * @category MicroExit
1777
+ */
1778
+ export interface Failure<out A, out E> extends Proto<A, E> {
1779
+ readonly _tag: "Failure"
1780
+ readonly cause: MicroCause<E>
1781
+ }
1782
+ }
1289
1783
 
1290
1784
  /**
1291
- * Creates a `Micro` effect that will fail with the specified `MicroCause`.
1292
- *
1293
1785
  * @since 3.4.6
1294
1786
  * @experimental
1295
- * @category constructors
1787
+ * @category MicroExit
1296
1788
  */
1297
- export const failCause = <E>(cause: MicroCause<E>): Micro<never, E> => fromExit(exitFailCause(cause))
1789
+ export const isMicroExit = (u: unknown): u is MicroExit<unknown, unknown> => hasProperty(u, MicroExitTypeId)
1298
1790
 
1299
1791
  /**
1300
- * Creates a `Micro` effect that will fail with the lazily evaluated `MicroCause`.
1301
- *
1302
1792
  * @since 3.4.6
1303
1793
  * @experimental
1304
- * @category constructors
1305
- */
1306
- export const failCauseSync = <E>(cause: LazyArg<MicroCause<E>>): Micro<never, E> =>
1307
- fromExitSync(() => exitFailCause(cause()))
1308
-
1309
- /**
1310
- * Creates a `Micro` effect that will succeed with the lazily evaluated value.
1311
- *
1312
- * If the evaluation of the value throws an error, the effect will fail with
1313
- * `CauseDie`.
1314
- *
1315
- * @since 3.4.0
1316
- * @experimental
1317
- * @category constructors
1794
+ * @category MicroExit
1318
1795
  */
1319
- export const sync = <A>(evaluate: LazyArg<A>): Micro<A> =>
1320
- make(function(_env, onExit) {
1321
- onExit(exitSucceed(evaluate()))
1322
- })
1796
+ export const exitSucceed: <A>(a: A) => MicroExit<A, never> = succeed as any
1323
1797
 
1324
1798
  /**
1325
- * Converts an `Option` into a `Micro` effect, that will fail with
1326
- * `NoSuchElementException` if the option is `None`. Otherwise, it will succeed with the
1327
- * value of the option.
1328
- *
1329
- * @since 3.4.0
1799
+ * @since 3.4.6
1330
1800
  * @experimental
1331
- * @category constructors
1801
+ * @category MicroExit
1332
1802
  */
1333
- export const fromOption = <A>(option: Option.Option<A>): Micro<A, NoSuchElementException> =>
1334
- make(function(_env, onExit) {
1335
- onExit(option._tag === "Some" ? exitSucceed(option.value) : exitFail(new NoSuchElementException({})))
1336
- })
1803
+ export const exitFailCause: <E>(cause: MicroCause<E>) => MicroExit<never, E> = failCause as any
1337
1804
 
1338
1805
  /**
1339
- * Converts an `Either` into a `Micro` effect, that will fail with the left side
1340
- * of the either if it is a `Left`. Otherwise, it will succeed with the right
1341
- * side of the either.
1342
- *
1343
- * @since 3.4.0
1806
+ * @since 3.4.6
1344
1807
  * @experimental
1345
- * @category constructors
1808
+ * @category MicroExit
1346
1809
  */
1347
- export const fromEither = <R, L>(either: Either.Either<R, L>): Micro<R, L> =>
1348
- make(function(_env, onExit) {
1349
- onExit(either._tag === "Right" ? either as MicroExit<R, never> : exitFail(either.left))
1350
- })
1810
+ export const exitInterrupt: MicroExit<never> = exitFailCause(causeInterrupt())
1351
1811
 
1352
1812
  /**
1353
- * Lazily creates a `Micro` effect from the given side-effect.
1354
- *
1355
- * @since 3.4.0
1813
+ * @since 3.4.6
1356
1814
  * @experimental
1357
- * @category constructors
1815
+ * @category MicroExit
1358
1816
  */
1359
- export const suspend = <A, E, R>(evaluate: LazyArg<Micro<A, E, R>>): Micro<A, E, R> =>
1360
- make(function(env, onExit) {
1361
- evaluate()[runSymbol](env, onExit)
1362
- })
1363
-
1364
- const void_: Micro<void> = succeed(void 0)
1365
- export {
1366
- /**
1367
- * A `Micro` effect that will succeed with `void` (`undefined`).
1368
- *
1369
- * @since 3.4.0
1370
- * @experimental
1371
- * @category constructors
1372
- */
1373
- void_ as void
1374
- }
1817
+ export const exitFail = <E>(e: E): MicroExit<never, E> => exitFailCause(causeFail(e))
1375
1818
 
1376
1819
  /**
1377
- * Create a `Micro` effect from an asynchronous computation.
1378
- *
1379
- * You can return a cleanup effect that will be run when the effect is aborted.
1380
- * It is also passed an `AbortSignal` that is triggered when the effect is
1381
- * aborted.
1382
- *
1383
- * @since 3.4.0
1820
+ * @since 3.4.6
1384
1821
  * @experimental
1385
- * @category constructors
1822
+ * @category MicroExit
1386
1823
  */
1387
- export const async = <A, E = never, R = never>(
1388
- register: (resume: (effect: Micro<A, E, R>) => void, signal: AbortSignal) => void | Micro<void, never, R>
1389
- ): Micro<A, E, R> =>
1390
- make(function(env, onExit) {
1391
- let resumed = false
1392
- const controller = register.length > 1 ? new AbortController() : undefined
1393
- const signal = envGet(env, currentAbortSignal)
1394
- let cleanup: Micro<void, never, R> | void = undefined
1395
- function onAbort() {
1396
- if (cleanup) {
1397
- resume(uninterruptible(andThen(cleanup, fromExit(exitInterrupt))))
1398
- } else {
1399
- resume(fromExit(exitInterrupt))
1400
- }
1401
- if (controller !== undefined) {
1402
- controller.abort()
1403
- }
1404
- }
1405
- function resume(effect: Micro<A, E, R>) {
1406
- if (resumed) {
1407
- return
1408
- }
1409
- resumed = true
1410
- signal.removeEventListener("abort", onAbort)
1411
- effect[runSymbol](env, onExit)
1412
- }
1413
- cleanup = controller === undefined
1414
- ? (register as any)(resume)
1415
- : register(resume, controller.signal)
1416
- if (resumed) return
1417
- signal.addEventListener("abort", onAbort)
1418
- })
1419
-
1420
- const try_ = <A, E>(options: {
1421
- try: LazyArg<A>
1422
- catch: (error: unknown) => E
1423
- }): Micro<A, E> =>
1424
- make(function(_env, onExit) {
1425
- try {
1426
- onExit(exitSucceed(options.try()))
1427
- } catch (err) {
1428
- onExit(exitFail(options.catch(err)))
1429
- }
1430
- })
1431
- export {
1432
- /**
1433
- * The `Micro` equivalent of a try / catch block, which allows you to map
1434
- * thrown errors to a specific error type.
1435
- *
1436
- * @since 3.4.0
1437
- * @experimental
1438
- * @category constructors
1439
- * @example
1440
- * ```ts
1441
- * import { Micro } from "effect"
1442
- *
1443
- * Micro.try({
1444
- * try: () => throw new Error("boom"),
1445
- * catch: (cause) => new Error("caught", { cause })
1446
- * })
1447
- * ```
1448
- */
1449
- try_ as try
1450
- }
1824
+ export const exitDie = (defect: unknown): MicroExit<never> => exitFailCause(causeDie(defect))
1451
1825
 
1452
1826
  /**
1453
- * Wrap a `Promise` into a `Micro` effect. Any errors will result in a
1454
- * `CauseDie`.
1455
- *
1456
- * @since 3.4.0
1827
+ * @since 3.4.6
1457
1828
  * @experimental
1458
- * @category constructors
1829
+ * @category MicroExit
1459
1830
  */
1460
- export const promise = <A>(evaluate: (signal: AbortSignal) => PromiseLike<A>): Micro<A> =>
1461
- async<A>(function(resume, signal) {
1462
- evaluate(signal).then(
1463
- (a) => resume(succeed(a)),
1464
- (e) => resume(die(e))
1465
- )
1466
- })
1831
+ export const exitIsSuccess = <A, E>(
1832
+ self: MicroExit<A, E>
1833
+ ): self is MicroExit.Success<A, E> => self._tag === "Success"
1467
1834
 
1468
1835
  /**
1469
- * Wrap a `Promise` into a `Micro` effect. Any errors will be caught and
1470
- * converted into a specific error type.
1471
- *
1472
- * @since 3.4.0
1836
+ * @since 3.4.6
1473
1837
  * @experimental
1474
- * @category constructors
1475
- * @example
1476
- * ```ts
1477
- * import { Micro } from "effect"
1478
- *
1479
- * Micro.tryPromise({
1480
- * try: () => Promise.resolve("success"),
1481
- * catch: (cause) => new Error("caught", { cause })
1482
- * })
1483
- * ```
1838
+ * @category MicroExit
1484
1839
  */
1485
- export const tryPromise = <A, E>(options: {
1486
- readonly try: (signal: AbortSignal) => PromiseLike<A>
1487
- readonly catch: (error: unknown) => E
1488
- }): Micro<A, E> =>
1489
- async<A, E>(function(resume, signal) {
1490
- try {
1491
- options.try(signal).then(
1492
- (a) => resume(succeed(a)),
1493
- (e) => resume(fail(options.catch(e)))
1494
- )
1495
- } catch (err) {
1496
- resume(fail(options.catch(err)))
1497
- }
1498
- })
1840
+ export const exitIsFailure = <A, E>(
1841
+ self: MicroExit<A, E>
1842
+ ): self is MicroExit.Failure<A, E> => self._tag === "Failure"
1499
1843
 
1500
1844
  /**
1501
- * Pause the execution of the current `Micro` effect, and resume it on the next
1502
- * iteration of the event loop.
1503
- *
1504
- * You can specify a priority for the task, which will determine when it is
1505
- * executed relative to other tasks.
1506
- *
1507
- * @since 3.4.0
1845
+ * @since 3.4.6
1508
1846
  * @experimental
1509
- * @category constructors
1847
+ * @category MicroExit
1510
1848
  */
1511
- export const yieldWithPriority = (priority: number): Micro<void> =>
1512
- make(function(env, onExit) {
1513
- envGet(env, currentScheduler).scheduleTask(() => onExit(exitVoid), priority)
1514
- })
1849
+ export const exitIsInterrupt = <A, E>(
1850
+ self: MicroExit<A, E>
1851
+ ): self is MicroExit.Failure<A, E> & {
1852
+ readonly cause: MicroCause.Interrupt
1853
+ } => exitIsFailure(self) && self.cause._tag === "Interrupt"
1515
1854
 
1516
1855
  /**
1517
- * Pause the execution of the current `Micro` effect, and resume it on the next
1518
- * iteration of the event loop.
1519
- *
1520
- * @since 3.4.0
1856
+ * @since 3.4.6
1521
1857
  * @experimental
1522
- * @category constructors
1858
+ * @category MicroExit
1523
1859
  */
1524
- export const yieldNow: Micro<void> = yieldWithPriority(0)
1860
+ export const exitIsFail = <A, E>(
1861
+ self: MicroExit<A, E>
1862
+ ): self is MicroExit.Failure<A, E> & {
1863
+ readonly cause: MicroCause.Fail<E>
1864
+ } => exitIsFailure(self) && self.cause._tag === "Fail"
1525
1865
 
1526
1866
  /**
1527
- * Flush any yielded effects that are waiting to be executed.
1528
- *
1529
- * @since 3.4.0
1867
+ * @since 3.4.6
1530
1868
  * @experimental
1531
- * @category constructors
1869
+ * @category MicroExit
1532
1870
  */
1533
- export const yieldFlush: Micro<void> = make(function(env, onExit) {
1534
- envGet(env, currentScheduler).flush()
1535
- onExit(exitVoid)
1536
- })
1871
+ export const exitIsDie = <A, E>(
1872
+ self: MicroExit<A, E>
1873
+ ): self is MicroExit.Failure<A, E> & {
1874
+ readonly cause: MicroCause.Die
1875
+ } => exitIsFailure(self) && self.cause._tag === "Die"
1537
1876
 
1538
1877
  /**
1539
- * A `Micro` that will never succeed or fail. It wraps `setInterval` to prevent
1540
- * the Javascript runtime from exiting.
1541
- *
1542
- * @since 3.4.0
1878
+ * @since 3.4.6
1543
1879
  * @experimental
1544
- * @category constructors
1880
+ * @category MicroExit
1545
1881
  */
1546
- export const never: Micro<never> = async<never>(function() {
1547
- const interval = setInterval(constVoid, 2147483646)
1548
- return sync(() => clearInterval(interval))
1549
- })
1882
+ export const exitVoid: MicroExit<void> = exitSucceed(void 0)
1550
1883
 
1551
1884
  /**
1552
- * @since 3.4.0
1885
+ * @since 3.11.0
1553
1886
  * @experimental
1554
- * @category constructors
1887
+ * @category MicroExit
1555
1888
  */
1556
- export const gen = <Self, Eff extends YieldWrap<Micro<any, any, any>>, AEff>(
1557
- ...args:
1558
- | [self: Self, body: (this: Self) => Generator<Eff, AEff, never>]
1559
- | [body: () => Generator<Eff, AEff, never>]
1560
- ): Micro<
1561
- AEff,
1562
- [Eff] extends [never] ? never : [Eff] extends [YieldWrap<Micro<infer _A, infer E, infer _R>>] ? E : never,
1563
- [Eff] extends [never] ? never : [Eff] extends [YieldWrap<Micro<infer _A, infer _E, infer R>>] ? R : never
1564
- > =>
1565
- make(function(env, onExit) {
1566
- const iterator: Generator<Eff, AEff, any> = args.length === 1 ? args[0]() : args[1].call(args[0])
1567
- let running = false
1568
- let value: any = undefined
1569
- function run() {
1570
- running = true
1571
- try {
1572
- let shouldContinue = true
1573
- while (shouldContinue) {
1574
- const result = iterator.next(value)
1575
- if (result.done) {
1576
- return onExit(exitSucceed(result.value))
1577
- }
1578
- shouldContinue = false
1579
- yieldWrapGet(result.value)[runSymbol](env, function(exit) {
1580
- if (exit._tag === "Left") {
1581
- onExit(exit)
1582
- } else {
1583
- shouldContinue = true
1584
- value = exit.right
1585
- if (!running) run()
1586
- }
1587
- })
1588
- }
1589
- } catch (err) {
1590
- onExit(exitDie(err))
1591
- }
1592
- running = false
1889
+ export const exitVoidAll = <I extends Iterable<MicroExit<any, any>>>(
1890
+ exits: I
1891
+ ): MicroExit<void, I extends Iterable<MicroExit<infer _A, infer _E>> ? _E : never> => {
1892
+ for (const exit of exits) {
1893
+ if (exit._tag === "Failure") {
1894
+ return exit
1593
1895
  }
1594
- run()
1595
- })
1896
+ }
1897
+ return exitVoid
1898
+ }
1596
1899
 
1597
1900
  // ----------------------------------------------------------------------------
1598
- // mapping & sequencing
1901
+ // scheduler
1599
1902
  // ----------------------------------------------------------------------------
1600
1903
 
1601
1904
  /**
1602
- * Flattens any nested `Micro` effects, merging the error and requirement types.
1603
- *
1604
- * @since 3.4.0
1905
+ * @since 3.5.9
1605
1906
  * @experimental
1606
- * @category mapping & sequencing
1907
+ * @category scheduler
1607
1908
  */
1608
- export const flatten = <A, E, R, E2, R2>(self: Micro<Micro<A, E, R>, E2, R2>): Micro<A, E | E2, R | R2> =>
1609
- make(function(env, onExit) {
1610
- self[runSymbol](
1611
- env,
1612
- (exit) => exit._tag === "Left" ? onExit(exit as MicroExit<never, E2>) : exit.right[runSymbol](env, onExit)
1613
- )
1614
- })
1909
+ export interface MicroScheduler {
1910
+ readonly scheduleTask: (task: () => void, priority: number) => void
1911
+ readonly shouldYield: (fiber: Fiber<unknown, unknown>) => boolean
1912
+ readonly flush: () => void
1913
+ }
1914
+
1915
+ const setImmediate = "setImmediate" in globalThis
1916
+ ? globalThis.setImmediate
1917
+ : (f: () => void) => setTimeout(f, 0)
1615
1918
 
1616
1919
  /**
1617
- * Transforms the success value of the `Micro` effect with the specified
1618
- * function.
1619
- *
1620
- * @since 3.4.0
1920
+ * @since 3.5.9
1621
1921
  * @experimental
1622
- * @category mapping & sequencing
1922
+ * @category scheduler
1623
1923
  */
1624
- export const map: {
1924
+ export class MicroSchedulerDefault implements MicroScheduler {
1925
+ private tasks: Array<() => void> = []
1926
+ private running = false
1927
+
1625
1928
  /**
1626
- * Transforms the success value of the `Micro` effect with the specified
1627
- * function.
1628
- *
1629
- * @since 3.4.0
1630
- * @experimental
1631
- * @category mapping & sequencing
1929
+ * @since 3.5.9
1632
1930
  */
1633
- <A, B>(f: (a: A) => B): <E, R>(self: Micro<A, E, R>) => Micro<B, E, R>
1931
+ scheduleTask(task: () => void, _priority: number) {
1932
+ this.tasks.push(task)
1933
+ if (!this.running) {
1934
+ this.running = true
1935
+ setImmediate(this.afterScheduled)
1936
+ }
1937
+ }
1938
+
1634
1939
  /**
1635
- * Transforms the success value of the `Micro` effect with the specified
1636
- * function.
1637
- *
1638
- * @since 3.4.0
1639
- * @experimental
1640
- * @category mapping & sequencing
1940
+ * @since 3.5.9
1641
1941
  */
1642
- <A, E, R, B>(self: Micro<A, E, R>, f: (a: A) => B): Micro<B, E, R>
1643
- } = dual(2, <A, E, R, B>(self: Micro<A, E, R>, f: (a: A) => B): Micro<B, E, R> =>
1644
- make(function(env, onExit) {
1645
- self[runSymbol](env, function(exit) {
1646
- onExit(exit._tag === "Left" ? exit as MicroExit<never, E> : exitSucceed(f(exit.right)))
1647
- })
1648
- }))
1942
+ afterScheduled = () => {
1943
+ this.running = false
1944
+ this.runTasks()
1945
+ }
1649
1946
 
1650
- /**
1651
- * Create a `Micro` effect that will replace the success value of the given
1652
- * effect.
1653
- *
1654
- * @since 3.4.0
1655
- * @experimental
1656
- * @category mapping & sequencing
1657
- */
1658
- export const as: {
1659
1947
  /**
1660
- * Create a `Micro` effect that will replace the success value of the given
1661
- * effect.
1662
- *
1663
- * @since 3.4.0
1664
- * @experimental
1665
- * @category mapping & sequencing
1948
+ * @since 3.5.9
1666
1949
  */
1667
- <A, B>(value: B): <E, R>(self: Micro<A, E, R>) => Micro<B, E, R>
1950
+ runTasks() {
1951
+ const tasks = this.tasks
1952
+ this.tasks = []
1953
+ for (let i = 0, len = tasks.length; i < len; i++) {
1954
+ tasks[i]()
1955
+ }
1956
+ }
1957
+
1668
1958
  /**
1669
- * Create a `Micro` effect that will replace the success value of the given
1670
- * effect.
1671
- *
1672
- * @since 3.4.0
1673
- * @experimental
1674
- * @category mapping & sequencing
1959
+ * @since 3.5.9
1675
1960
  */
1676
- <A, E, R, B>(self: Micro<A, E, R>, value: B): Micro<B, E, R>
1677
- } = dual(2, <A, E, R, B>(self: Micro<A, E, R>, value: B): Micro<B, E, R> => map(self, (_) => value))
1961
+ shouldYield(fiber: Fiber<unknown, unknown>) {
1962
+ return fiber.currentOpCount >= fiber.getRef(MaxOpsBeforeYield)
1963
+ }
1678
1964
 
1679
- /**
1680
- * Wrap the success value of this `Micro` effect in an `Option.Some`.
1681
- *
1682
- * @since 3.4.0
1683
- * @experimental
1684
- * @category mapping & sequencing
1685
- */
1686
- export const asSome = <A, E, R>(self: Micro<A, E, R>): Micro<Option.Option<A>, E, R> => map(self, Option.some)
1965
+ /**
1966
+ * @since 3.5.9
1967
+ */
1968
+ flush() {
1969
+ while (this.tasks.length > 0) {
1970
+ this.runTasks()
1971
+ }
1972
+ }
1973
+ }
1687
1974
 
1688
1975
  /**
1689
- * Map the success value of this `Micro` effect to another `Micro` effect, then
1690
- * flatten the result.
1976
+ * Access the given `Context.Tag` from the environment.
1691
1977
  *
1692
1978
  * @since 3.4.0
1693
1979
  * @experimental
1694
- * @category mapping & sequencing
1980
+ * @category environment
1695
1981
  */
1696
- export const flatMap: {
1982
+ export const service: {
1697
1983
  /**
1698
- * Map the success value of this `Micro` effect to another `Micro` effect, then
1699
- * flatten the result.
1984
+ * Access the given `Context.Tag` from the environment.
1700
1985
  *
1701
1986
  * @since 3.4.0
1702
1987
  * @experimental
1703
- * @category mapping & sequencing
1988
+ * @category environment
1704
1989
  */
1705
- <A, B, E2, R2>(f: (a: A) => Micro<B, E2, R2>): <E, R>(self: Micro<A, E, R>) => Micro<B, E | E2, R | R2>
1990
+ <I, S>(tag: Context.Reference<I, S>): Micro<S>
1706
1991
  /**
1707
- * Map the success value of this `Micro` effect to another `Micro` effect, then
1708
- * flatten the result.
1992
+ * Access the given `Context.Tag` from the environment.
1709
1993
  *
1710
1994
  * @since 3.4.0
1711
1995
  * @experimental
1712
- * @category mapping & sequencing
1996
+ * @category environment
1713
1997
  */
1714
- <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<B, E | E2, R | R2>
1715
- } = dual(
1716
- 2,
1717
- <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<B, E | E2, R | R2> =>
1718
- make(function(env, onExit) {
1719
- self[runSymbol](env, function(exit) {
1720
- if (exit._tag === "Left") {
1721
- return onExit(exit as MicroExit<never, E>)
1722
- }
1723
- f(exit.right)[runSymbol](env, onExit)
1724
- })
1725
- })
1726
- )
1998
+ <I, S>(tag: Context.Tag<I, S>): Micro<S, never, I>
1999
+ } =
2000
+ (<I, S>(tag: Context.Tag<I, S>): Micro<S, never, I> =>
2001
+ withFiber((fiber) => succeed(Context.unsafeGet(fiber.context, tag)))) as any
1727
2002
 
1728
2003
  /**
1729
- * Swap the error and success types of the `Micro` effect.
2004
+ * Access the given `Context.Tag` from the environment, without tracking the
2005
+ * dependency at the type level.
2006
+ *
2007
+ * It will return an `Option` of the service, depending on whether it is
2008
+ * available in the environment or not.
1730
2009
  *
1731
2010
  * @since 3.4.0
1732
2011
  * @experimental
1733
- * @category mapping & sequencing
2012
+ * @category environment
1734
2013
  */
1735
- export const flip = <A, E, R>(self: Micro<A, E, R>): Micro<E, A, R> =>
1736
- matchEffect(self, {
1737
- onFailure: succeed,
1738
- onSuccess: fail
1739
- })
2014
+ export const serviceOption = <I, S>(
2015
+ tag: Context.Tag<I, S>
2016
+ ): Micro<Option.Option<S>> => withFiber((fiber) => succeed(Context.getOption(fiber.context, tag)))
1740
2017
 
1741
2018
  /**
1742
- * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
1743
- * a single api.
1744
- *
1745
- * It also allows you to pass in a `Micro` effect directly, which will be
1746
- * executed after the current effect.
2019
+ * Update the Context with the given mapping function.
1747
2020
  *
1748
- * @since 3.4.0
2021
+ * @since 3.11.0
1749
2022
  * @experimental
1750
- * @category mapping & sequencing
2023
+ * @category environment
1751
2024
  */
1752
- export const andThen: {
1753
- /**
1754
- * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
1755
- * a single api.
1756
- *
1757
- * It also allows you to pass in a `Micro` effect directly, which will be
1758
- * executed after the current effect.
1759
- *
1760
- * @since 3.4.0
1761
- * @experimental
1762
- * @category mapping & sequencing
1763
- */
1764
- <A, X>(f: (a: A) => X): <E, R>(
1765
- self: Micro<A, E, R>
1766
- ) => [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1767
- : Micro<X, E, R>
1768
- /**
1769
- * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
1770
- * a single api.
1771
- *
1772
- * It also allows you to pass in a `Micro` effect directly, which will be
1773
- * executed after the current effect.
1774
- *
1775
- * @since 3.4.0
1776
- * @experimental
1777
- * @category mapping & sequencing
1778
- */
1779
- <X>(f: NotFunction<X>): <A, E, R>(
1780
- self: Micro<A, E, R>
1781
- ) => [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1782
- : Micro<X, E, R>
2025
+ export const updateContext: {
1783
2026
  /**
1784
- * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
1785
- * a single api.
2027
+ * Update the Context with the given mapping function.
1786
2028
  *
1787
- * It also allows you to pass in a `Micro` effect directly, which will be
1788
- * executed after the current effect.
1789
- *
1790
- * @since 3.4.0
2029
+ * @since 3.11.0
1791
2030
  * @experimental
1792
- * @category mapping & sequencing
2031
+ * @category environment
1793
2032
  */
1794
- <A, E, R, X>(
1795
- self: Micro<A, E, R>,
1796
- f: (a: A) => X
1797
- ): [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1798
- : Micro<X, E, R>
2033
+ <R2, R>(
2034
+ f: (context: Context.Context<R2>) => Context.Context<NoInfer<R>>
2035
+ ): <A, E>(self: Micro<A, E, R>) => Micro<A, E, R2>
1799
2036
  /**
1800
- * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
1801
- * a single api.
1802
- *
1803
- * It also allows you to pass in a `Micro` effect directly, which will be
1804
- * executed after the current effect.
2037
+ * Update the Context with the given mapping function.
1805
2038
  *
1806
- * @since 3.4.0
2039
+ * @since 3.11.0
1807
2040
  * @experimental
1808
- * @category mapping & sequencing
2041
+ * @category environment
1809
2042
  */
1810
- <A, E, R, X>(
2043
+ <A, E, R, R2>(
1811
2044
  self: Micro<A, E, R>,
1812
- f: NotFunction<X>
1813
- ): [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
1814
- : Micro<X, E, R>
2045
+ f: (context: Context.Context<R2>) => Context.Context<NoInfer<R>>
2046
+ ): Micro<A, E, R2>
1815
2047
  } = dual(
1816
2048
  2,
1817
- <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: any): Micro<B, E | E2, R | R2> =>
1818
- make(function(env, onExit) {
1819
- self[runSymbol](env, function(exit) {
1820
- if (exit._tag === "Left") {
1821
- return onExit(exit as MicroExit<never, E>)
1822
- } else if (envGet(env, currentAbortSignal).aborted) {
1823
- return onExit(exitInterrupt)
1824
- }
1825
- const value = isMicro(f) ? f : typeof f === "function" ? f(exit.right) : f
1826
- if (isMicro(value)) {
1827
- value[runSymbol](env, onExit)
1828
- } else {
1829
- onExit(exitSucceed(value))
2049
+ <A, E, R, R2>(
2050
+ self: Micro<A, E, R>,
2051
+ f: (context: Context.Context<R2>) => Context.Context<NoInfer<R>>
2052
+ ): Micro<A, E, R2> =>
2053
+ withFiber<
2054
+ /**
2055
+ * Update the Context with the given mapping function.
2056
+ *
2057
+ * @since 3.11.0
2058
+ * @experimental
2059
+ * @category environment
2060
+ */
2061
+ A, /**
2062
+ * Update the Context with the given mapping function.
2063
+ *
2064
+ * @since 3.11.0
2065
+ * @experimental
2066
+ * @category environment
2067
+ */
2068
+ E, /**
2069
+ * Update the Context with the given mapping function.
2070
+ *
2071
+ * @since 3.11.0
2072
+ * @experimental
2073
+ * @category environment
2074
+ */
2075
+ R2
2076
+ >((fiber) => {
2077
+ const prev = fiber.context as Context.Context<R2>
2078
+ fiber.context = f(prev)
2079
+ return onExit(
2080
+ self as any,
2081
+ () => {
2082
+ fiber.context = prev
2083
+ return void_
1830
2084
  }
1831
- })
2085
+ )
1832
2086
  })
1833
2087
  )
1834
2088
 
1835
2089
  /**
1836
- * Execute a side effect from the success value of the `Micro` effect.
1837
- *
1838
- * It is similar to the `andThen` api, but the success value is ignored.
2090
+ * Update the service for the given `Context.Tag` in the environment.
1839
2091
  *
1840
- * @since 3.4.0
2092
+ * @since 3.11.0
1841
2093
  * @experimental
1842
- * @category mapping & sequencing
2094
+ * @category environment
1843
2095
  */
1844
- export const tap: {
2096
+ export const updateService: {
1845
2097
  /**
1846
- * Execute a side effect from the success value of the `Micro` effect.
2098
+ * Update the service for the given `Context.Tag` in the environment.
1847
2099
  *
1848
- * It is similar to the `andThen` api, but the success value is ignored.
1849
- *
1850
- * @since 3.4.0
2100
+ * @since 3.11.0
1851
2101
  * @experimental
1852
- * @category mapping & sequencing
2102
+ * @category environment
1853
2103
  */
1854
- <A, X>(f: (a: NoInfer<A>) => X): <E, R>(
1855
- self: Micro<A, E, R>
1856
- ) => [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1857
- : Micro<A, E, R>
2104
+ <I, A>(tag: Context.Reference<I, A>, f: (value: A) => A): <XA, E, R>(self: Micro<XA, E, R>) => Micro<XA, E, R>
1858
2105
  /**
1859
- * Execute a side effect from the success value of the `Micro` effect.
1860
- *
1861
- * It is similar to the `andThen` api, but the success value is ignored.
2106
+ * Update the service for the given `Context.Tag` in the environment.
1862
2107
  *
1863
- * @since 3.4.0
2108
+ * @since 3.11.0
1864
2109
  * @experimental
1865
- * @category mapping & sequencing
2110
+ * @category environment
1866
2111
  */
1867
- <X>(f: NotFunction<X>): <A, E, R>(
1868
- self: Micro<A, E, R>
1869
- ) => [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1870
- : Micro<A, E, R>
2112
+ <I, A>(tag: Context.Tag<I, A>, f: (value: A) => A): <XA, E, R>(self: Micro<XA, E, R>) => Micro<XA, E, R | I>
1871
2113
  /**
1872
- * Execute a side effect from the success value of the `Micro` effect.
2114
+ * Update the service for the given `Context.Tag` in the environment.
1873
2115
  *
1874
- * It is similar to the `andThen` api, but the success value is ignored.
1875
- *
1876
- * @since 3.4.0
2116
+ * @since 3.11.0
1877
2117
  * @experimental
1878
- * @category mapping & sequencing
2118
+ * @category environment
1879
2119
  */
1880
- <A, E, R, X>(
1881
- self: Micro<A, E, R>,
1882
- f: (a: NoInfer<A>) => X
1883
- ): [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1884
- : Micro<A, E, R>
2120
+ <XA, E, R, I, A>(self: Micro<XA, E, R>, tag: Context.Reference<I, A>, f: (value: A) => A): Micro<XA, E, R>
1885
2121
  /**
1886
- * Execute a side effect from the success value of the `Micro` effect.
1887
- *
1888
- * It is similar to the `andThen` api, but the success value is ignored.
2122
+ * Update the service for the given `Context.Tag` in the environment.
1889
2123
  *
1890
- * @since 3.4.0
2124
+ * @since 3.11.0
1891
2125
  * @experimental
1892
- * @category mapping & sequencing
2126
+ * @category environment
1893
2127
  */
1894
- <A, E, R, X>(
1895
- self: Micro<A, E, R>,
1896
- f: NotFunction<X>
1897
- ): [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
1898
- : Micro<A, E, R>
2128
+ <XA, E, R, I, A>(self: Micro<XA, E, R>, tag: Context.Tag<I, A>, f: (value: A) => A): Micro<XA, E, R | I>
1899
2129
  } = dual(
1900
- 2,
1901
- <A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2> =>
1902
- make(function(env, onExit) {
1903
- self[runSymbol](env, function(selfExit) {
1904
- if (selfExit._tag === "Left") {
1905
- return onExit(selfExit as MicroExit<never, E>)
1906
- } else if (envGet(env, currentAbortSignal).aborted) {
1907
- return onExit(exitInterrupt)
1908
- }
1909
- const value = isMicro(f) ? f : typeof f === "function" ? f(selfExit.right) : f
1910
- if (isMicro(value)) {
1911
- value[runSymbol](env, function(tapExit) {
1912
- if (tapExit._tag === "Left") {
1913
- return onExit(tapExit)
1914
- }
1915
- onExit(selfExit)
1916
- })
1917
- } else {
1918
- onExit(selfExit)
2130
+ 3,
2131
+ <XA, E, R, I, A>(
2132
+ self: Micro<XA, E, R>,
2133
+ tag: Context.Reference<I, A>,
2134
+ f: (value: A) => A
2135
+ ): Micro<XA, E, R> =>
2136
+ withFiber((fiber) => {
2137
+ const prev = Context.unsafeGet(fiber.context, tag)
2138
+ fiber.context = Context.add(fiber.context, tag, f(prev))
2139
+ return onExit(
2140
+ self,
2141
+ () => {
2142
+ fiber.context = Context.add(fiber.context, tag, prev)
2143
+ return void_
1919
2144
  }
1920
- })
2145
+ )
1921
2146
  })
1922
2147
  )
1923
-
1924
- /**
1925
- * Replace the success value of the `Micro` effect with `void`.
1926
- *
1927
- * @since 3.4.0
1928
- * @experimental
1929
- * @category mapping & sequencing
1930
- */
1931
- export const asVoid = <A, E, R>(self: Micro<A, E, R>): Micro<void, E, R> => map(self, (_) => void 0)
1932
-
1933
- /**
1934
- * Access the `MicroExit` of the given `Micro` effect.
1935
- *
1936
- * @since 3.4.6
1937
- * @experimental
1938
- * @category mapping & sequencing
1939
- */
1940
- export const exit = <A, E, R>(self: Micro<A, E, R>): Micro<MicroExit<A, E>, never, R> =>
1941
- make(function(env, onExit) {
1942
- self[runSymbol](env, function(exit) {
1943
- onExit(exitSucceed(exit))
1944
- })
1945
- })
1946
-
1947
- /**
1948
- * Replace the error type of the given `Micro` with the full `MicroCause` object.
1949
- *
1950
- * @since 3.4.0
1951
- * @experimental
1952
- * @category mapping & sequencing
1953
- */
1954
- export const sandbox = <A, E, R>(self: Micro<A, E, R>): Micro<A, MicroCause<E>, R> =>
1955
- catchAllCause(self, (cause) => fail(cause))
1956
-
1957
- function forkSignal(env: Env<any>) {
1958
- const controller = new AbortController()
1959
- const parentSignal = envGet(env, currentAbortSignal)
1960
- function onAbort() {
1961
- controller.abort()
1962
- parentSignal.removeEventListener("abort", onAbort)
1963
- }
1964
- parentSignal.addEventListener("abort", onAbort)
1965
- const envWithSignal = envMutate(env, function(refs) {
1966
- refs[currentAbortController.key] = controller
1967
- refs[currentAbortSignal.key] = controller.signal
1968
- return refs
1969
- })
1970
- return [envWithSignal, onAbort] as const
1971
- }
1972
-
1973
- /**
1974
- * Returns an effect that races all the specified effects,
1975
- * yielding the value of the first effect to succeed with a value. Losers of
1976
- * the race will be interrupted immediately
2148
+
2149
+ /**
2150
+ * Access the current `Context` from the environment.
1977
2151
  *
1978
2152
  * @since 3.4.0
1979
2153
  * @experimental
1980
- * @category sequencing
2154
+ * @category environment
1981
2155
  */
1982
- export const raceAll = <Eff extends Micro<any, any, any>>(
1983
- all: Iterable<Eff>
1984
- ): Micro<Micro.Success<Eff>, Micro.Error<Eff>, Micro.Context<Eff>> =>
1985
- make(function(env, onExit) {
1986
- const [envWithSignal, onAbort] = forkSignal(env)
1987
-
1988
- const effects = Array.from(all)
1989
- let len = effects.length
1990
- let index = 0
1991
- let done = 0
1992
- let exit: MicroExit<any, any> | undefined = undefined
1993
- const causes: Array<MicroCause<any>> = []
1994
- function onDone(exit_: MicroExit<any, any>) {
1995
- done++
1996
- if (exit_._tag === "Right" && exit === undefined) {
1997
- len = index
1998
- exit = exit_
1999
- onAbort()
2000
- } else if (exit_._tag === "Left") {
2001
- causes.push(exit_.left)
2002
- }
2003
- if (done >= len) {
2004
- onExit(exit ?? Either.left(causes[0]))
2005
- }
2006
- }
2007
-
2008
- for (; index < len; index++) {
2009
- effects[index][runSymbol](envWithSignal, onDone)
2010
- }
2011
- })
2156
+ export const context = <R>(): Micro<Context.Context<R>> => getContext as any
2157
+ const getContext = withFiber((fiber) => succeed(fiber.context))
2012
2158
 
2013
2159
  /**
2014
- * Returns an effect that races all the specified effects,
2015
- * yielding the value of the first effect to succeed or fail. Losers of
2016
- * the race will be interrupted immediately
2160
+ * Merge the given `Context` with the current context.
2017
2161
  *
2018
2162
  * @since 3.4.0
2019
2163
  * @experimental
2020
- * @category sequencing
2164
+ * @category environment
2021
2165
  */
2022
- export const raceAllFirst = <Eff extends Micro<any, any, any>>(
2023
- all: Iterable<Eff>
2024
- ): Micro<Micro.Success<Eff>, Micro.Error<Eff>, Micro.Context<Eff>> =>
2025
- make(function(env, onExit) {
2026
- const [envWithSignal, onAbort] = forkSignal(env)
2027
-
2028
- const effects = Array.from(all)
2029
- let len = effects.length
2030
- let index = 0
2031
- let done = 0
2032
- let exit: MicroExit<any, any> | undefined = undefined
2033
- const causes: Array<MicroCause<any>> = []
2034
- function onDone(exit_: MicroExit<any, any>) {
2035
- done++
2036
- if (exit === undefined) {
2037
- len = index
2038
- exit = exit_
2039
- onAbort()
2040
- }
2041
- if (done >= len) {
2042
- onExit(exit ?? Either.left(causes[0]))
2043
- }
2044
- }
2045
-
2046
- for (; index < len; index++) {
2047
- effects[index][runSymbol](envWithSignal, onDone)
2048
- }
2049
- })
2166
+ export const provideContext: {
2167
+ /**
2168
+ * Merge the given `Context` with the current context.
2169
+ *
2170
+ * @since 3.4.0
2171
+ * @experimental
2172
+ * @category environment
2173
+ */
2174
+ <XR>(context: Context.Context<XR>): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, Exclude<R, XR>>
2175
+ /**
2176
+ * Merge the given `Context` with the current context.
2177
+ *
2178
+ * @since 3.4.0
2179
+ * @experimental
2180
+ * @category environment
2181
+ */
2182
+ <A, E, R, XR>(self: Micro<A, E, R>, context: Context.Context<XR>): Micro<A, E, Exclude<R, XR>>
2183
+ } = dual(
2184
+ 2,
2185
+ <A, E, R, XR>(
2186
+ self: Micro<A, E, R>,
2187
+ provided: Context.Context<XR>
2188
+ ): Micro<A, E, Exclude<R, XR>> => updateContext(self, Context.merge(provided)) as any
2189
+ )
2050
2190
 
2051
2191
  /**
2052
- * Returns an effect that races two effects, yielding the value of the first
2053
- * effect to succeed. Losers of the race will be interrupted immediately
2192
+ * Add the provided service to the current context.
2054
2193
  *
2055
2194
  * @since 3.4.0
2056
2195
  * @experimental
2057
- * @category sequencing
2196
+ * @category environment
2058
2197
  */
2059
- export const race: {
2198
+ export const provideService: {
2060
2199
  /**
2061
- * Returns an effect that races two effects, yielding the value of the first
2062
- * effect to succeed. Losers of the race will be interrupted immediately
2200
+ * Add the provided service to the current context.
2063
2201
  *
2064
2202
  * @since 3.4.0
2065
2203
  * @experimental
2066
- * @category sequencing
2204
+ * @category environment
2067
2205
  */
2068
- <A2, E2, R2>(that: Micro<A2, E2, R2>): <A, E, R>(self: Micro<A, E, R>) => Micro<A | A2, E | E2, R | R2>
2206
+ <I, S>(tag: Context.Tag<I, S>, service: S): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, Exclude<R, I>>
2069
2207
  /**
2070
- * Returns an effect that races two effects, yielding the value of the first
2071
- * effect to succeed. Losers of the race will be interrupted immediately
2208
+ * Add the provided service to the current context.
2072
2209
  *
2073
2210
  * @since 3.4.0
2074
2211
  * @experimental
2075
- * @category sequencing
2212
+ * @category environment
2076
2213
  */
2077
- <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2>
2214
+ <A, E, R, I, S>(self: Micro<A, E, R>, tag: Context.Tag<I, S>, service: S): Micro<A, E, Exclude<R, I>>
2078
2215
  } = dual(
2079
- 2,
2080
- <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2> =>
2081
- raceAll([self, that])
2216
+ 3,
2217
+ <A, E, R, I, S>(
2218
+ self: Micro<A, E, R>,
2219
+ tag: Context.Tag<I, S>,
2220
+ service: S
2221
+ ): Micro<A, E, Exclude<R, I>> => updateContext(self, Context.add(tag, service)) as any
2082
2222
  )
2083
2223
 
2084
2224
  /**
2085
- * Returns an effect that races two effects, yielding the value of the first
2086
- * effect to succeed *or* fail. Losers of the race will be interrupted immediately
2225
+ * Create a service using the provided `Micro` effect, and add it to the
2226
+ * current context.
2227
+ *
2228
+ * @since 3.4.6
2229
+ * @experimental
2230
+ * @category environment
2231
+ */
2232
+ export const provideServiceEffect: {
2233
+ /**
2234
+ * Create a service using the provided `Micro` effect, and add it to the
2235
+ * current context.
2236
+ *
2237
+ * @since 3.4.6
2238
+ * @experimental
2239
+ * @category environment
2240
+ */
2241
+ <I, S, E2, R2>(
2242
+ tag: Context.Tag<I, S>,
2243
+ acquire: Micro<S, E2, R2>
2244
+ ): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E | E2, Exclude<R, I> | R2>
2245
+ /**
2246
+ * Create a service using the provided `Micro` effect, and add it to the
2247
+ * current context.
2248
+ *
2249
+ * @since 3.4.6
2250
+ * @experimental
2251
+ * @category environment
2252
+ */
2253
+ <A, E, R, I, S, E2, R2>(
2254
+ self: Micro<A, E, R>,
2255
+ tag: Context.Tag<I, S>,
2256
+ acquire: Micro<S, E2, R2>
2257
+ ): Micro<A, E | E2, Exclude<R, I> | R2>
2258
+ } = dual(
2259
+ 3,
2260
+ <A, E, R, I, S, E2, R2>(
2261
+ self: Micro<A, E, R>,
2262
+ tag: Context.Tag<I, S>,
2263
+ acquire: Micro<S, E2, R2>
2264
+ ): Micro<A, E | E2, Exclude<R, I> | R2> => flatMap(acquire, (service) => provideService(self, tag, service))
2265
+ )
2266
+
2267
+ // ========================================================================
2268
+ // References
2269
+ // ========================================================================
2270
+
2271
+ /**
2272
+ * @since 3.11.0
2273
+ * @experimental
2274
+ * @category references
2275
+ */
2276
+ export class MaxOpsBeforeYield extends Context.Reference<MaxOpsBeforeYield>()<
2277
+ "effect/Micro/currentMaxOpsBeforeYield",
2278
+ number
2279
+ >(
2280
+ "effect/Micro/currentMaxOpsBeforeYield",
2281
+ { defaultValue: () => 2048 }
2282
+ ) {}
2283
+
2284
+ /**
2285
+ * @since 3.11.0
2286
+ * @experimental
2287
+ * @category environment refs
2288
+ */
2289
+ export class CurrentConcurrency extends Context.Reference<CurrentConcurrency>()<
2290
+ "effect/Micro/currentConcurrency",
2291
+ "unbounded" | number
2292
+ >(
2293
+ "effect/Micro/currentConcurrency",
2294
+ { defaultValue: () => "unbounded" }
2295
+ ) {}
2296
+
2297
+ /**
2298
+ * @since 3.11.0
2299
+ * @experimental
2300
+ * @category environment refs
2301
+ */
2302
+ export class CurrentScheduler extends Context.Reference<CurrentScheduler>()<
2303
+ "effect/Micro/currentScheduler",
2304
+ MicroScheduler
2305
+ >(
2306
+ "effect/Micro/currentScheduler",
2307
+ { defaultValue: () => new MicroSchedulerDefault() }
2308
+ ) {}
2309
+
2310
+ /**
2311
+ * If you have a `Micro` that uses `concurrency: "inherit"`, you can use this
2312
+ * api to control the concurrency of that `Micro` when it is run.
2087
2313
  *
2088
2314
  * @since 3.4.0
2089
2315
  * @experimental
2090
- * @category sequencing
2316
+ * @category environment refs
2317
+ * @example
2318
+ * import * as Micro from "effect/Micro"
2319
+ *
2320
+ * Micro.forEach([1, 2, 3], (n) => Micro.succeed(n), {
2321
+ * concurrency: "inherit"
2322
+ * }).pipe(
2323
+ * Micro.withConcurrency(2) // use a concurrency of 2
2324
+ * )
2091
2325
  */
2092
- export const raceFirst: {
2326
+ export const withConcurrency: {
2093
2327
  /**
2094
- * Returns an effect that races two effects, yielding the value of the first
2095
- * effect to succeed *or* fail. Losers of the race will be interrupted immediately
2328
+ * If you have a `Micro` that uses `concurrency: "inherit"`, you can use this
2329
+ * api to control the concurrency of that `Micro` when it is run.
2096
2330
  *
2097
2331
  * @since 3.4.0
2098
2332
  * @experimental
2099
- * @category sequencing
2333
+ * @category environment refs
2334
+ * @example
2335
+ * import * as Micro from "effect/Micro"
2336
+ *
2337
+ * Micro.forEach([1, 2, 3], (n) => Micro.succeed(n), {
2338
+ * concurrency: "inherit"
2339
+ * }).pipe(
2340
+ * Micro.withConcurrency(2) // use a concurrency of 2
2341
+ * )
2100
2342
  */
2101
- <A2, E2, R2>(that: Micro<A2, E2, R2>): <A, E, R>(self: Micro<A, E, R>) => Micro<A | A2, E | E2, R | R2>
2343
+ (concurrency: "unbounded" | number): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, R>
2102
2344
  /**
2103
- * Returns an effect that races two effects, yielding the value of the first
2104
- * effect to succeed *or* fail. Losers of the race will be interrupted immediately
2345
+ * If you have a `Micro` that uses `concurrency: "inherit"`, you can use this
2346
+ * api to control the concurrency of that `Micro` when it is run.
2105
2347
  *
2106
2348
  * @since 3.4.0
2107
2349
  * @experimental
2108
- * @category sequencing
2350
+ * @category environment refs
2351
+ * @example
2352
+ * import * as Micro from "effect/Micro"
2353
+ *
2354
+ * Micro.forEach([1, 2, 3], (n) => Micro.succeed(n), {
2355
+ * concurrency: "inherit"
2356
+ * }).pipe(
2357
+ * Micro.withConcurrency(2) // use a concurrency of 2
2358
+ * )
2109
2359
  */
2110
- <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2>
2360
+ <A, E, R>(self: Micro<A, E, R>, concurrency: "unbounded" | number): Micro<A, E, R>
2111
2361
  } = dual(
2112
2362
  2,
2113
- <A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2> =>
2114
- raceAllFirst([self, that])
2363
+ <A, E, R>(
2364
+ self: Micro<A, E, R>,
2365
+ concurrency: "unbounded" | number
2366
+ ): Micro<A, E, R> => provideService(self, CurrentConcurrency, concurrency)
2115
2367
  )
2116
2368
 
2117
2369
  // ----------------------------------------------------------------------------
@@ -2212,13 +2464,11 @@ export const zipWith: {
2212
2464
  that: Micro<A2, E2, R2>,
2213
2465
  f: (a: A, b: A2) => B,
2214
2466
  options?: { readonly concurrent?: boolean | undefined }
2215
- ): Micro<B, E2 | E, R2 | R> => {
2216
- if (options?.concurrent) {
2467
+ ): Micro<B, E2 | E, R2 | R> =>
2468
+ options?.concurrent
2217
2469
  // Use `all` exclusively for concurrent cases, as it introduces additional overhead due to the management of concurrency
2218
- return map(all([self, that], { concurrency: "unbounded" }), ([a, a2]) => f(a, a2))
2219
- }
2220
- return flatMap(self, (a) => map(that, (a2) => f(a, a2)))
2221
- })
2470
+ ? map(all([self, that], { concurrency: 2 }), ([a, a2]) => f(a, a2))
2471
+ : flatMap(self, (a) => map(that, (a2) => f(a, a2))))
2222
2472
 
2223
2473
  // ----------------------------------------------------------------------------
2224
2474
  // filtering & conditionals
@@ -2431,7 +2681,7 @@ export const when: {
2431
2681
  self: Micro<A, E, R>,
2432
2682
  condition: LazyArg<boolean> | Micro<boolean, E2, R2>
2433
2683
  ): Micro<Option.Option<A>, E | E2, R | R2> =>
2434
- flatMap(isMicro(condition) ? condition : sync(condition), (pass) => pass ? asSome(self) : succeed(Option.none()))
2684
+ flatMap(isMicro(condition) ? condition : sync(condition), (pass) => pass ? asSome(self) : succeedNone)
2435
2685
  )
2436
2686
 
2437
2687
  // ----------------------------------------------------------------------------
@@ -2497,14 +2747,15 @@ export const repeatExit: {
2497
2747
  times?: number | undefined
2498
2748
  schedule?: MicroSchedule | undefined
2499
2749
  }): Micro<A, E, R> =>
2500
- make(function(env, onExit) {
2750
+ suspend(() => {
2501
2751
  const startedAt = options.schedule ? Date.now() : 0
2502
2752
  let attempt = 0
2503
- self[runSymbol](env, function loop(exit) {
2753
+
2754
+ const loop: Micro<A, E, R> = flatMap(exit(self), (exit) => {
2504
2755
  if (options.while !== undefined && !options.while(exit)) {
2505
- return onExit(exit)
2756
+ return exit
2506
2757
  } else if (options.times !== undefined && attempt >= options.times) {
2507
- return onExit(exit)
2758
+ return exit
2508
2759
  }
2509
2760
  attempt++
2510
2761
  let delayEffect = yieldNow
@@ -2512,17 +2763,14 @@ export const repeatExit: {
2512
2763
  const elapsed = Date.now() - startedAt
2513
2764
  const duration = options.schedule(attempt, elapsed)
2514
2765
  if (Option.isNone(duration)) {
2515
- return onExit(exit)
2766
+ return exit
2516
2767
  }
2517
2768
  delayEffect = sleep(duration.value)
2518
2769
  }
2519
- delayEffect[runSymbol](env, function(exit) {
2520
- if (exit._tag === "Left") {
2521
- return onExit(exit as MicroExit<never, never>)
2522
- }
2523
- self[runSymbol](env, loop)
2524
- })
2770
+ return flatMap(delayEffect, () => loop)
2525
2771
  })
2772
+
2773
+ return loop
2526
2774
  }))
2527
2775
 
2528
2776
  /**
@@ -2575,9 +2823,116 @@ export const repeat: {
2575
2823
  ): Micro<A, E, R> =>
2576
2824
  repeatExit(self, {
2577
2825
  ...options,
2578
- while: (exit) => exit._tag === "Right" && (options?.while === undefined || options.while(exit.right))
2826
+ while: (exit) => exit._tag === "Success" && (options?.while === undefined || options.while(exit.value))
2579
2827
  }))
2580
2828
 
2829
+ /**
2830
+ * Replicates the given effect `n` times.
2831
+ *
2832
+ * @since 3.11.0
2833
+ * @experimental
2834
+ * @category repetition
2835
+ */
2836
+ export const replicate: {
2837
+ /**
2838
+ * Replicates the given effect `n` times.
2839
+ *
2840
+ * @since 3.11.0
2841
+ * @experimental
2842
+ * @category repetition
2843
+ */
2844
+ (n: number): <A, E, R>(self: Micro<A, E, R>) => Array<Micro<A, E, R>>
2845
+ /**
2846
+ * Replicates the given effect `n` times.
2847
+ *
2848
+ * @since 3.11.0
2849
+ * @experimental
2850
+ * @category repetition
2851
+ */
2852
+ <A, E, R>(self: Micro<A, E, R>, n: number): Array<Micro<A, E, R>>
2853
+ } = dual(
2854
+ 2,
2855
+ <A, E, R>(self: Micro<A, E, R>, n: number): Array<Micro<A, E, R>> => Array.from({ length: n }, () => self)
2856
+ )
2857
+
2858
+ /**
2859
+ * Performs this effect the specified number of times and collects the
2860
+ * results.
2861
+ *
2862
+ * @since 3.11.0
2863
+ * @category repetition
2864
+ */
2865
+ export const replicateEffect: {
2866
+ /**
2867
+ * Performs this effect the specified number of times and collects the
2868
+ * results.
2869
+ *
2870
+ * @since 3.11.0
2871
+ * @category repetition
2872
+ */
2873
+ (
2874
+ n: number,
2875
+ options?: {
2876
+ readonly concurrency?: Concurrency | undefined
2877
+ readonly discard?: false | undefined
2878
+ }
2879
+ ): <A, E, R>(self: Micro<A, E, R>) => Micro<Array<A>, E, R>
2880
+ /**
2881
+ * Performs this effect the specified number of times and collects the
2882
+ * results.
2883
+ *
2884
+ * @since 3.11.0
2885
+ * @category repetition
2886
+ */
2887
+ (
2888
+ n: number,
2889
+ options: {
2890
+ readonly concurrency?: Concurrency | undefined
2891
+ readonly discard: true
2892
+ }
2893
+ ): <A, E, R>(self: Micro<A, E, R>) => Micro<void, E, R>
2894
+ /**
2895
+ * Performs this effect the specified number of times and collects the
2896
+ * results.
2897
+ *
2898
+ * @since 3.11.0
2899
+ * @category repetition
2900
+ */
2901
+ <A, E, R>(
2902
+ self: Micro<A, E, R>,
2903
+ n: number,
2904
+ options?: {
2905
+ readonly concurrency?: Concurrency | undefined
2906
+ readonly discard?: false | undefined
2907
+ }
2908
+ ): Micro<Array<A>, E, R>
2909
+ /**
2910
+ * Performs this effect the specified number of times and collects the
2911
+ * results.
2912
+ *
2913
+ * @since 3.11.0
2914
+ * @category repetition
2915
+ */
2916
+ <A, E, R>(
2917
+ self: Micro<A, E, R>,
2918
+ n: number,
2919
+ options: {
2920
+ readonly concurrency?: Concurrency | undefined
2921
+ readonly discard: true
2922
+ }
2923
+ ): Micro<void, E, R>
2924
+ } = dual(
2925
+ (args) => isMicro(args[0]),
2926
+ <A, E, R>(
2927
+ self: Micro<A, E, R>,
2928
+ n: number,
2929
+ options: {
2930
+ readonly concurrency?: Concurrency | undefined
2931
+ readonly discard: true
2932
+ }
2933
+ ): Micro<void, E, R> => all(replicate(self, n), options)
2934
+ )
2935
+
2581
2936
  /**
2582
2937
  * Repeat the given `Micro` effect forever, only stopping if the effect fails.
2583
2938
  *
@@ -2848,8 +3203,20 @@ export const catchAllCause: {
2848
3203
  <A, E, R, B, E2, R2>(
2849
3204
  self: Micro<A, E, R>,
2850
3205
  f: (cause: NoInfer<MicroCause<E>>) => Micro<B, E2, R2>
2851
- ): Micro<A | B, E2, R | R2> => catchCauseIf(self, constTrue, f) as Micro<A | B, E2, R | R2>
3206
+ ): Micro<A | B, E2, R | R2> => {
3207
+ const onFailure = Object.create(OnFailureProto)
3208
+ onFailure[args] = self
3209
+ onFailure[failureCont] = f
3210
+ return onFailure
3211
+ }
2852
3212
  )
3213
+ const OnFailureProto = makePrimitiveProto({
3214
+ op: "OnFailure",
3215
+ eval(this: any, fiber: FiberImpl): Primitive {
3216
+ fiber._stack.push(this as any)
3217
+ return this[args]
3218
+ }
3219
+ })
2853
3220
 
2854
3221
  /**
2855
3222
  * Selectively catch a `MicroCause` object of the given `Micro` effect,
@@ -2871,7 +3238,9 @@ export const catchCauseIf: {
2871
3238
  <E, B, E2, R2, EB extends MicroCause<E>>(
2872
3239
  refinement: Refinement<MicroCause<E>, EB>,
2873
3240
  f: (cause: EB) => Micro<B, E2, R2>
2874
- ): <A, R>(self: Micro<A, E, R>) => Micro<A | B, Exclude<E, MicroCause.Error<EB>> | E2, R | R2>
3241
+ ): <A, R>(
3242
+ self: Micro<A, E, R>
3243
+ ) => Micro<A | B, Exclude<E, MicroCause.Error<EB>> | E2, R | R2>
2875
3244
  /**
2876
3245
  * Selectively catch a `MicroCause` object of the given `Micro` effect,
2877
3246
  * using the provided predicate to determine if the failure should be caught.
@@ -2910,20 +3279,15 @@ export const catchCauseIf: {
2910
3279
  predicate: Predicate<MicroCause<NoInfer<E>>>,
2911
3280
  f: (cause: NoInfer<MicroCause<E>>) => Micro<B, E2, R2>
2912
3281
  ): Micro<A | B, E | E2, R | R2>
2913
- } = dual(3, <A, E, R, B, E2, R2>(
2914
- self: Micro<A, E, R>,
2915
- predicate: Predicate<MicroCause<E>>,
2916
- f: (cause: MicroCause<E>) => Micro<B, E2, R2>
2917
- ): Micro<A | B, E | E2, R | R2> =>
2918
- make(function(env, onExit) {
2919
- self[runSymbol](env, function(exit) {
2920
- if (exit._tag === "Right" || !predicate(exit.left)) {
2921
- onExit(exit)
2922
- } else {
2923
- f(exit.left)[runSymbol](env, onExit)
2924
- }
2925
- })
2926
- }))
3282
+ } = dual(
3283
+ 3,
3284
+ <A, E, R, B, E2, R2>(
3285
+ self: Micro<A, E, R>,
3286
+ predicate: Predicate<MicroCause<E>>,
3287
+ f: (cause: MicroCause<E>) => Micro<B, E2, R2>
3288
+ ): Micro<A | B, E | E2, R | R2> =>
3289
+ catchAllCause(self, (cause) => predicate(cause) ? f(cause) : failCause(cause) as any)
3290
+ )
2927
3291
 
2928
3292
  /**
2929
3293
  * Catch the error of the given `Micro` effect, allowing you to recover from it.
@@ -2960,7 +3324,7 @@ export const catchAll: {
2960
3324
  <A, E, R, B, E2, R2>(
2961
3325
  self: Micro<A, E, R>,
2962
3326
  f: (a: NoInfer<E>) => Micro<B, E2, R2>
2963
- ): Micro<A | B, E2, R | R2> => catchAllCause(self, (cause) => causeIsFail(cause) ? f(cause.error) : failCause(cause))
3327
+ ): Micro<A | B, E2, R | R2> => catchCauseIf(self, causeIsFail, (cause) => f(cause.error))
2964
3328
  )
2965
3329
 
2966
3330
  /**
@@ -3396,7 +3760,7 @@ export const ignoreLogged = <A, E, R>(self: Micro<A, E, R>): Micro<void, never,
3396
3760
  * @category error handling
3397
3761
  */
3398
3762
  export const option = <A, E, R>(self: Micro<A, E, R>): Micro<Option.Option<A>, never, R> =>
3399
- match(self, { onFailure: (_) => Option.none(), onSuccess: Option.some })
3763
+ match(self, { onFailure: Option.none, onSuccess: Option.some })
3400
3764
 
3401
3765
  /**
3402
3766
  * Replace the success value of the given `Micro` effect with an `Either`,
@@ -3458,8 +3822,8 @@ export const retry: {
3458
3822
  repeatExit(self, {
3459
3823
  ...options,
3460
3824
  while: (exit) =>
3461
- exit._tag === "Left" && exit.left._tag === "Fail" &&
3462
- (options?.while === undefined || options.while(exit.left.error))
3825
+ exit._tag === "Failure" && exit.cause._tag === "Fail" &&
3826
+ (options?.while === undefined || options.while(exit.cause.error))
3463
3827
  }))
3464
3828
 
3465
3829
  /**
@@ -3506,12 +3870,7 @@ export const withTrace: {
3506
3870
  const lineMatch = line.match(/\((.*)\)$/)
3507
3871
  return causeWithTrace(cause, `at ${name} (${lineMatch ? lineMatch[1] : line})`)
3508
3872
  }
3509
- const f = (name: string) => (self: Micro<any, any, any>) =>
3510
- unsafeMakeOptions(function(env, onExit) {
3511
- self[runSymbol](env, function(exit) {
3512
- onExit(exit._tag === "Left" ? Either.left(generate(name, exit.left)) : exit)
3513
- })
3514
- }, false)
3873
+ const f = (name: string) => (self: Micro<any, any, any>) => onError(self, (cause) => failCause(generate(name, cause)))
3515
3874
  if (arguments.length === 2) {
3516
3875
  return f(arguments[1])(arguments[0])
3517
3876
  }
@@ -3567,18 +3926,21 @@ export const matchCauseEffect: {
3567
3926
  readonly onFailure: (cause: MicroCause<E>) => Micro<A2, E2, R2>
3568
3927
  readonly onSuccess: (a: A) => Micro<A3, E3, R3>
3569
3928
  }
3570
- ): Micro<A2 | A3, E2 | E3, R2 | R3 | R> =>
3571
- make(function(env, onExit) {
3572
- self[runSymbol](env, function(exit) {
3573
- try {
3574
- const next = exit._tag === "Left" ? options.onFailure(exit.left) : options.onSuccess(exit.right)
3575
- next[runSymbol](env, onExit)
3576
- } catch (err) {
3577
- onExit(exitDie(err))
3578
- }
3579
- })
3580
- })
3929
+ ): Micro<A2 | A3, E2 | E3, R2 | R3 | R> => {
3930
+ const primitive = Object.create(OnSuccessAndFailureProto)
3931
+ primitive[args] = self
3932
+ primitive[successCont] = options.onSuccess
3933
+ primitive[failureCont] = options.onFailure
3934
+ return primitive
3935
+ }
3581
3936
  )
3937
+ const OnSuccessAndFailureProto = makePrimitiveProto({
3938
+ op: "OnSuccessAndFailure",
3939
+ eval(this: any, fiber: FiberImpl): Primitive {
3940
+ fiber._stack.push(this)
3941
+ return this[args]
3942
+ }
3943
+ })
3582
3944
 
3583
3945
  /**
3584
3946
  * @since 3.4.6
@@ -3724,12 +4086,12 @@ export const match: {
3724
4086
  * @category delays & timeouts
3725
4087
  */
3726
4088
  export const sleep = (millis: number): Micro<void> =>
3727
- async(function(resume) {
3728
- const timeout = setTimeout(function() {
4089
+ async((resume) => {
4090
+ const timeout = setTimeout(() => {
3729
4091
  resume(void_)
3730
4092
  }, millis)
3731
4093
  return sync(() => {
3732
- return clearTimeout(timeout)
4094
+ clearTimeout(timeout)
3733
4095
  })
3734
4096
  })
3735
4097
 
@@ -3997,7 +4359,7 @@ class MicroScopeImpl implements MicroScope.Closeable {
3997
4359
  this.state = { _tag: "Closed", exit: microExit }
3998
4360
  return flatMap(
3999
4361
  forEach(finalizers, (finalizer) => exit(finalizer(microExit))),
4000
- (exits) => asVoid(fromExit(Either.all(exits)))
4362
+ exitVoidAll
4001
4363
  )
4002
4364
  }
4003
4365
  return void_
@@ -4082,7 +4444,7 @@ export const provideScope: {
4082
4444
  * @category resources & finalization
4083
4445
  */
4084
4446
  export const scoped = <A, E, R>(self: Micro<A, E, R>): Micro<A, E, Exclude<R, MicroScope>> =>
4085
- suspend(function() {
4447
+ suspend(() => {
4086
4448
  const scope = new MicroScopeImpl()
4087
4449
  return onExit(provideService(self, MicroScope, scope), (exit) => scope.close(exit))
4088
4450
  })
@@ -4149,7 +4511,45 @@ export const onExit: {
4149
4511
  <A, E, R, XE, XR>(
4150
4512
  self: Micro<A, E, R>,
4151
4513
  f: (exit: MicroExit<A, E>) => Micro<void, XE, XR>
4152
- ): Micro<A, E | XE, R | XR> => onExitIf(self, constTrue, f)
4514
+ ): Micro<A, E | XE, R | XR> =>
4515
+ uninterruptibleMask((restore) =>
4516
+ matchCauseEffect(restore(self), {
4517
+ onFailure: (cause) => flatMap(f(exitFailCause(cause)), () => failCause(cause)),
4518
+ onSuccess: (a) => flatMap(f(exitSucceed(a)), () => succeed(a))
4519
+ })
4520
+ )
4521
+ )
4522
+
4523
+ /**
4524
+ * Regardless of the result of the this `Micro` effect, run the finalizer effect.
4525
+ *
4526
+ * @since 3.4.0
4527
+ * @experimental
4528
+ * @category resources & finalization
4529
+ */
4530
+ export const ensuring: {
4531
+ /**
4532
+ * Regardless of the result of the this `Micro` effect, run the finalizer effect.
4533
+ *
4534
+ * @since 3.4.0
4535
+ * @experimental
4536
+ * @category resources & finalization
4537
+ */
4538
+ <XE, XR>(finalizer: Micro<void, XE, XR>): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
4539
+ /**
4540
+ * Regardless of the result of the this `Micro` effect, run the finalizer effect.
4541
+ *
4542
+ * @since 3.4.0
4543
+ * @experimental
4544
+ * @category resources & finalization
4545
+ */
4546
+ <A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR>
4547
+ } = dual(
4548
+ 2,
4549
+ <A, E, R, XE, XR>(
4550
+ self: Micro<A, E, R>,
4551
+ finalizer: Micro<void, XE, XR>
4552
+ ): Micro<A, E | XE, R | XR> => onExit(self, (_) => finalizer)
4153
4553
  )
4154
4554
 
4155
4555
  /**
@@ -4217,52 +4617,7 @@ export const onExitIf: {
4217
4617
  self: Micro<A, E, R>,
4218
4618
  refinement: Refinement<MicroExit<A, E>, B>,
4219
4619
  f: (exit: B) => Micro<void, XE, XR>
4220
- ): Micro<A, E | XE, R | XR> =>
4221
- uninterruptibleMask((restore) =>
4222
- make(function(env, onExit) {
4223
- restore(self)[runSymbol](env, function(exit) {
4224
- if (!refinement(exit)) {
4225
- return onExit(exit)
4226
- }
4227
- f(exit)[runSymbol](env, function(finalizerExit) {
4228
- if (finalizerExit._tag === "Left") {
4229
- return onExit(finalizerExit as MicroExit<never, XE>)
4230
- }
4231
- onExit(exit)
4232
- })
4233
- })
4234
- })
4235
- )
4236
- )
4237
-
4238
- /**
4239
- * Regardless of the result of the this `Micro` effect, run the finalizer effect.
4240
- *
4241
- * @since 3.4.0
4242
- * @experimental
4243
- * @category resources & finalization
4244
- */
4245
- export const ensuring: {
4246
- /**
4247
- * Regardless of the result of the this `Micro` effect, run the finalizer effect.
4248
- *
4249
- * @since 3.4.0
4250
- * @experimental
4251
- * @category resources & finalization
4252
- */
4253
- <XE, XR>(finalizer: Micro<void, XE, XR>): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
4254
- /**
4255
- * Regardless of the result of the this `Micro` effect, run the finalizer effect.
4256
- *
4257
- * @since 3.4.0
4258
- * @experimental
4259
- * @category resources & finalization
4260
- */
4261
- <A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR>
4262
- } = dual(
4263
- 2,
4264
- <A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR> =>
4265
- onExit(self, (_) => finalizer)
4620
+ ): Micro<A, E | XE, R | XR> => onExit(self, (exit) => (refinement(exit) ? f(exit) : exitVoid))
4266
4621
  )
4267
4622
 
4268
4623
  /**
@@ -4302,7 +4657,7 @@ export const onError: {
4302
4657
  <A, E, R, XE, XR>(
4303
4658
  self: Micro<A, E, R>,
4304
4659
  f: (cause: MicroCause<NoInfer<E>>) => Micro<void, XE, XR>
4305
- ): Micro<A, E | XE, R | XR> => onExitIf(self, exitIsFailure, (exit) => f(exit.left))
4660
+ ): Micro<A, E | XE, R | XR> => onExitIf(self, exitIsFailure, (exit) => f(exit.cause))
4306
4661
  )
4307
4662
 
4308
4663
  /**
@@ -4354,7 +4709,7 @@ export const acquireUseRelease = <Resource, E, R, A, E2, R2, E3, R3>(
4354
4709
  (a) =>
4355
4710
  flatMap(
4356
4711
  exit(restore(use(a))),
4357
- (exit) => andThen(release(a, exit), fromExit(exit))
4712
+ (exit) => andThen(release(a, exit), exit)
4358
4713
  )
4359
4714
  )
4360
4715
  )
@@ -4370,29 +4725,54 @@ export const acquireUseRelease = <Resource, E, R, A, E2, R2, E3, R3>(
4370
4725
  * @experimental
4371
4726
  * @category interruption
4372
4727
  */
4373
- export const interrupt: Micro<never> = make(function(env, onExit) {
4374
- const controller = envGet(env, currentAbortController)
4375
- controller.abort()
4376
- onExit(exitInterrupt)
4728
+ export const interrupt: Micro<never> = failCause(causeInterrupt())
4729
+
4730
+ /**
4731
+ * Flag the effect as uninterruptible, which means that when the effect is
4732
+ * interrupted, it will be allowed to continue running until completion.
4733
+ *
4734
+ * @since 3.4.0
4735
+ * @experimental
4736
+ * @category flags
4737
+ */
4738
+ export const uninterruptible = <A, E, R>(
4739
+ self: Micro<A, E, R>
4740
+ ): Micro<A, E, R> =>
4741
+ withFiber((fiber) => {
4742
+ if (!fiber.interruptible) return self
4743
+ fiber.interruptible = false
4744
+ fiber._stack.push(setInterruptible(true))
4745
+ return self
4746
+ })
4747
+
4748
+ const setInterruptible: (interruptible: boolean) => Primitive = makePrimitive({
4749
+ op: "SetInterruptible",
4750
+ ensure(fiber) {
4751
+ fiber.interruptible = this[args]
4752
+ if (fiber._interrupted && fiber.interruptible) {
4753
+ return () => exitInterrupt
4754
+ }
4755
+ }
4377
4756
  })
4378
4757
 
4379
4758
  /**
4380
- * Wrap the given `Micro` effect in an uninterruptible region, preventing the
4381
- * effect from being aborted.
4759
+ * Flag the effect as interruptible, which means that when the effect is
4760
+ * interrupted, it will be interrupted immediately.
4382
4761
  *
4383
4762
  * @since 3.4.0
4384
4763
  * @experimental
4385
- * @category interruption
4764
+ * @category flags
4386
4765
  */
4387
- export const uninterruptible = <A, E, R>(self: Micro<A, E, R>): Micro<A, E, R> =>
4388
- unsafeMakeOptions(function(env, onExit) {
4389
- const nextEnv = envMutate(env, function(env) {
4390
- env[currentInterruptible.key] = false
4391
- env[currentAbortSignal.key] = new AbortController().signal
4392
- return env
4393
- })
4394
- self[runSymbol](nextEnv, onExit)
4395
- }, false)
4766
+ export const interruptible = <A, E, R>(
4767
+ self: Micro<A, E, R>
4768
+ ): Micro<A, E, R> =>
4769
+ withFiber((fiber) => {
4770
+ if (fiber.interruptible) return self
4771
+ fiber.interruptible = true
4772
+ fiber._stack.push(setInterruptible(false))
4773
+ if (fiber._interrupted) return exitInterrupt
4774
+ return self
4775
+ })
4396
4776
 
4397
4777
  /**
4398
4778
  * Wrap the given `Micro` effect in an uninterruptible region, preventing the
@@ -4416,42 +4796,15 @@ export const uninterruptible = <A, E, R>(self: Micro<A, E, R>): Micro<A, E, R> =
4416
4796
  * ```
4417
4797
  */
4418
4798
  export const uninterruptibleMask = <A, E, R>(
4419
- f: (restore: <A, E, R>(effect: Micro<A, E, R>) => Micro<A, E, R>) => Micro<A, E, R>
4799
+ f: (
4800
+ restore: <A, E, R>(effect: Micro<A, E, R>) => Micro<A, E, R>
4801
+ ) => Micro<A, E, R>
4420
4802
  ): Micro<A, E, R> =>
4421
- unsafeMakeOptions((env, onExit) => {
4422
- const isInterruptible = envGet(env, currentInterruptible)
4423
- const effect = isInterruptible ? f(interruptible) : f(identity)
4424
- const nextEnv = isInterruptible ?
4425
- envMutate(env, function(env) {
4426
- env[currentInterruptible.key] = false
4427
- env[currentAbortSignal.key] = new AbortController().signal
4428
- return env
4429
- }) :
4430
- env
4431
- effect[runSymbol](nextEnv, onExit)
4432
- }, false)
4433
-
4434
- /**
4435
- * Wrap the given `Micro` effect in an interruptible region, allowing the effect
4436
- * to be aborted.
4437
- *
4438
- * @since 3.4.0
4439
- * @experimental
4440
- * @category interruption
4441
- */
4442
- export const interruptible = <A, E, R>(self: Micro<A, E, R>): Micro<A, E, R> =>
4443
- make((env, onExit) => {
4444
- const isInterruptible = envGet(env, currentInterruptible)
4445
- let newEnv = env
4446
- if (!isInterruptible) {
4447
- const controller = envGet(env, currentAbortController)
4448
- newEnv = envMutate(env, function(env) {
4449
- env[currentInterruptible.key] = true
4450
- env[currentAbortSignal.key] = controller.signal
4451
- return env
4452
- })
4453
- }
4454
- self[runSymbol](newEnv, onExit)
4803
+ withFiber((fiber) => {
4804
+ if (!fiber.interruptible) return f(identity)
4805
+ fiber.interruptible = false
4806
+ fiber._stack.push(setInterruptible(true))
4807
+ return f(interruptible)
4455
4808
  })
4456
4809
 
4457
4810
  // ========================================================================
@@ -4571,6 +4924,34 @@ export const all = <
4571
4924
  }) as any
4572
4925
  }
4573
4926
 
4927
+ /**
4928
+ * @since 3.11.0
4929
+ * @experimental
4930
+ * @category collecting & elements
4931
+ */
4932
+ export const whileLoop: <A, E, R>(options: {
4933
+ readonly while: LazyArg<boolean>
4934
+ readonly body: LazyArg<Micro<A, E, R>>
4935
+ readonly step: (a: A) => void
4936
+ }) => Micro<void, E, R> = makePrimitive({
4937
+ op: "While",
4938
+ contA(value, fiber) {
4939
+ this[args].step(value)
4940
+ if (this[args].while()) {
4941
+ fiber._stack.push(this)
4942
+ return this[args].body()
4943
+ }
4944
+ return exitVoid
4945
+ },
4946
+ eval(fiber) {
4947
+ if (this[args].while()) {
4948
+ fiber._stack.push(this)
4949
+ return this[args].body()
4950
+ }
4951
+ return exitVoid
4952
+ }
4953
+ })
4954
+
4574
4955
  /**
4575
4956
  * For each element of the provided iterable, run the effect and collect the results.
4576
4957
  *
@@ -4636,64 +5017,89 @@ export const forEach: {
4636
5017
  readonly concurrency?: Concurrency | undefined
4637
5018
  readonly discard?: boolean | undefined
4638
5019
  }): Micro<any, E, R> =>
4639
- make(function(env, onExit) {
5020
+ withFiber((parent) => {
4640
5021
  const concurrencyOption = options?.concurrency === "inherit"
4641
- ? envGet(env, currentConcurrency)
5022
+ ? parent.getRef(CurrentConcurrency)
4642
5023
  : options?.concurrency ?? 1
4643
5024
  const concurrency = concurrencyOption === "unbounded"
4644
5025
  ? Number.POSITIVE_INFINITY
4645
5026
  : Math.max(1, concurrencyOption)
4646
5027
 
4647
- // abort
4648
- const [envWithSignal, onAbort] = forkSignal(env)
4649
-
4650
- // iterate
4651
- let result: MicroExit<any, any> | undefined = undefined
4652
- const items = Array.from(iterable)
5028
+ const items = Arr.fromIterable(iterable)
4653
5029
  let length = items.length
4654
5030
  if (length === 0) {
4655
- return onExit(Either.right(options?.discard ? undefined : []))
5031
+ return options?.discard ? void_ : succeed([])
4656
5032
  }
5033
+
4657
5034
  const out: Array<B> | undefined = options?.discard ? undefined : new Array(length)
4658
5035
  let index = 0
4659
- let inProgress = 0
4660
- let doneCount = 0
4661
- let pumping = false
4662
- function pump() {
4663
- pumping = true
4664
- while (inProgress < concurrency && index < length) {
4665
- const currentIndex = index
4666
- const item = items[currentIndex]
4667
- index++
4668
- inProgress++
4669
- try {
4670
- f(item, currentIndex)[runSymbol](envWithSignal, function(exit) {
4671
- if (exit._tag === "Left") {
4672
- if (result === undefined) {
4673
- result = exit
4674
- length = index
4675
- onAbort()
5036
+
5037
+ if (concurrency === 1) {
5038
+ return as(
5039
+ whileLoop({
5040
+ while: () => index < items.length,
5041
+ body: () => f(items[index], index),
5042
+ step: out ?
5043
+ (b) => out[index++] = b :
5044
+ (_) => index++
5045
+ }),
5046
+ out as any
5047
+ )
5048
+ }
5049
+ return async((resume) => {
5050
+ const fibers = new Set<Fiber<unknown, unknown>>()
5051
+ let result: MicroExit<any, any> | undefined = undefined
5052
+ let inProgress = 0
5053
+ let doneCount = 0
5054
+ let pumping = false
5055
+ let interrupted = false
5056
+ function pump() {
5057
+ pumping = true
5058
+ while (inProgress < concurrency && index < length) {
5059
+ const currentIndex = index
5060
+ const item = items[currentIndex]
5061
+ index++
5062
+ inProgress++
5063
+ try {
5064
+ const child = unsafeFork(parent, f(item, currentIndex), true, true)
5065
+ fibers.add(child)
5066
+ child.addObserver((exit) => {
5067
+ fibers.delete(child)
5068
+ if (interrupted) {
5069
+ return
5070
+ } else if (exit._tag === "Failure") {
5071
+ if (result === undefined) {
5072
+ result = exit
5073
+ length = index
5074
+ fibers.forEach((fiber) => fiber.unsafeInterrupt())
5075
+ }
5076
+ } else if (out !== undefined) {
5077
+ out[currentIndex] = exit.value
4676
5078
  }
4677
- } else if (out !== undefined) {
4678
- out[currentIndex] = exit.right
4679
- }
4680
- doneCount++
4681
- inProgress--
4682
- if (doneCount === length) {
4683
- onExit(result ?? Either.right(out))
4684
- } else if (!pumping && inProgress < concurrency) {
4685
- pump()
4686
- }
4687
- })
4688
- } catch (err) {
4689
- result = exitDie(err)
4690
- length = index
4691
- onAbort()
5079
+ doneCount++
5080
+ inProgress--
5081
+ if (doneCount === length) {
5082
+ resume(result ?? succeed(out))
5083
+ } else if (!pumping && inProgress < concurrency) {
5084
+ pump()
5085
+ }
5086
+ })
5087
+ } catch (err) {
5088
+ result = exitDie(err)
5089
+ length = index
5090
+ fibers.forEach((fiber) => fiber.unsafeInterrupt())
5091
+ }
4692
5092
  }
5093
+ pumping = false
4693
5094
  }
4694
- pumping = false
4695
- }
4696
- pump()
5095
+ pump()
5096
+
5097
+ return suspend(() => {
5098
+ interrupted = true
5099
+ index = length
5100
+ return fiberInterruptAll(fibers)
5101
+ })
5102
+ })
4697
5103
  })
4698
5104
 
4699
5105
  /**
@@ -4843,151 +5249,9 @@ export {
4843
5249
  }
4844
5250
 
4845
5251
  // ----------------------------------------------------------------------------
4846
- // handle & forking
5252
+ // fibers & forking
4847
5253
  // ----------------------------------------------------------------------------
4848
5254
 
4849
- /**
4850
- * @since 3.4.0
4851
- * @experimental
4852
- * @category handle & forking
4853
- */
4854
- export const HandleTypeId: unique symbol = Symbol.for("effect/Micro/Handle")
4855
-
4856
- /**
4857
- * @since 3.4.0
4858
- * @experimental
4859
- * @category handle & forking
4860
- */
4861
- export type HandleTypeId = typeof HandleTypeId
4862
-
4863
- /**
4864
- * @since 3.4.0
4865
- * @experimental
4866
- * @category handle & forking
4867
- */
4868
- export interface Handle<A, E = never> extends Micro<A, E> {
4869
- readonly [HandleTypeId]: HandleTypeId
4870
- readonly await: Micro<MicroExit<A, E>>
4871
- readonly join: Micro<A, E>
4872
- readonly interrupt: Micro<MicroExit<A, E>>
4873
- readonly unsafeInterrupt: () => void
4874
- readonly addObserver: (observer: (exit: MicroExit<A, E>) => void) => void
4875
- readonly removeObserver: (observer: (exit: MicroExit<A, E>) => void) => void
4876
- readonly unsafePoll: () => MicroExit<A, E> | null
4877
-
4878
- [Unify.typeSymbol]?: unknown
4879
- [Unify.unifySymbol]?: HandleUnify<this>
4880
- [Unify.ignoreSymbol]?: HandleUnifyIgnore
4881
- }
4882
-
4883
- /**
4884
- * @category models
4885
- * @since 3.8.4
4886
- * @experimental
4887
- */
4888
- export interface HandleUnify<A extends { [Unify.typeSymbol]?: any }> extends MicroUnify<A> {
4889
- Handle?: () => A[Unify.typeSymbol] extends Handle<infer A0, infer E0> | infer _ ? Handle<A0, E0> : never
4890
- }
4891
-
4892
- /**
4893
- * @category models
4894
- * @since 3.8.4
4895
- * @experimental
4896
- */
4897
- export interface HandleUnifyIgnore extends MicroUnifyIgnore {
4898
- Micro?: true
4899
- }
4900
-
4901
- /**
4902
- * @since 3.4.0
4903
- * @experimental
4904
- * @category handle & forking
4905
- */
4906
- export const isHandle = (u: unknown): u is Handle<unknown, unknown> =>
4907
- typeof u === "object" && u !== null && HandleTypeId in u
4908
-
4909
- class HandleImpl<A, E> extends Class<A, E> implements Handle<A, E> {
4910
- readonly [HandleTypeId]: HandleTypeId
4911
-
4912
- readonly observers: Set<(exit: MicroExit<A, E>) => void> = new Set()
4913
- private _exit: MicroExit<A, E> | undefined = undefined
4914
- _controller: AbortController
4915
- readonly isRoot: boolean
4916
-
4917
- constructor(readonly parentSignal: AbortSignal, controller?: AbortController) {
4918
- super()
4919
- this[HandleTypeId] = HandleTypeId
4920
- this.isRoot = controller !== undefined
4921
- this._controller = controller ?? new AbortController()
4922
- if (!this.isRoot) {
4923
- parentSignal.addEventListener("abort", this.unsafeInterrupt)
4924
- }
4925
- }
4926
-
4927
- unsafePoll(): MicroExit<A, E> | null {
4928
- return this._exit ?? null
4929
- }
4930
-
4931
- unsafeInterrupt = () => {
4932
- this._controller.abort()
4933
- }
4934
-
4935
- emit(exit: MicroExit<A, E>): void {
4936
- if (this._exit) {
4937
- return
4938
- }
4939
- this._exit = exit
4940
- if (!this.isRoot) {
4941
- this.parentSignal.removeEventListener("abort", this.unsafeInterrupt)
4942
- }
4943
- this.observers.forEach((observer) => observer(exit))
4944
- this.observers.clear()
4945
- }
4946
-
4947
- addObserver(observer: (exit: MicroExit<A, E>) => void): void {
4948
- if (this._exit) {
4949
- return observer(this._exit)
4950
- }
4951
- this.observers.add(observer)
4952
- }
4953
-
4954
- removeObserver(observer: (exit: MicroExit<A, E>) => void): void {
4955
- this.observers.delete(observer)
4956
- }
4957
-
4958
- get await(): Micro<MicroExit<A, E>> {
4959
- return suspend(() => {
4960
- if (this._exit) {
4961
- return succeed(this._exit)
4962
- }
4963
- return async((resume) => {
4964
- function observer(exit: MicroExit<A, E>) {
4965
- resume(succeed(exit))
4966
- }
4967
- this.addObserver(observer)
4968
- return sync(() => {
4969
- this.removeObserver(observer)
4970
- })
4971
- })
4972
- })
4973
- }
4974
-
4975
- get join(): Micro<A, E> {
4976
- return flatMap(this.await, fromExit)
4977
- }
4978
-
4979
- get interrupt(): Micro<MicroExit<A, E>> {
4980
- return suspend(() => {
4981
- this.unsafeInterrupt()
4982
- return this.await
4983
- })
4984
- }
4985
-
4986
- asMicro(): Micro<A, E> {
4987
- return this.join
4988
- }
4989
- }
4990
-
4991
5255
  /**
4992
5256
  * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
4993
5257
  * aborted.
@@ -4998,23 +5262,33 @@ class HandleImpl<A, E> extends Class<A, E> implements Handle<A, E> {
4998
5262
  * @experimental
4999
5263
  * @category handle & forking
5000
5264
  */
5001
- export const fork = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never, R> =>
5002
- make(function(env, onExit) {
5003
- const signal = envGet(env, currentAbortSignal)
5004
- const handle = new HandleImpl<A, E>(signal)
5005
- const nextEnv = envMutate(env, (map) => {
5006
- map[currentAbortController.key] = handle._controller
5007
- map[currentAbortSignal.key] = handle._controller.signal
5008
- return map
5009
- })
5010
- envGet(env, currentScheduler).scheduleTask(() => {
5011
- self[runSymbol](nextEnv, (exit) => {
5012
- handle.emit(exit)
5013
- })
5014
- }, 0)
5015
- onExit(Either.right(handle))
5265
+ export const fork = <A, E, R>(
5266
+ self: Micro<A, E, R>
5267
+ ): Micro<Fiber<A, E>, never, R> =>
5268
+ withFiber((fiber) => {
5269
+ fiberMiddleware.interruptChildren ??= fiberInterruptChildren
5270
+ return succeed(unsafeFork(fiber, self))
5016
5271
  })
5017
5272
 
5273
+ const unsafeFork = <FA, FE, A, E, R>(
5274
+ parent: FiberImpl<FA, FE>,
5275
+ effect: Micro<A, E, R>,
5276
+ immediate = false,
5277
+ daemon = false
5278
+ ): Fiber<A, E> => {
5279
+ const child = new FiberImpl<A, E>(parent.context, parent.interruptible)
5280
+ if (!daemon) {
5281
+ parent.children().add(child)
5282
+ child.addObserver(() => parent.children().delete(child))
5283
+ }
5284
+ if (immediate) {
5285
+ child.evaluate(effect as any)
5286
+ } else {
5287
+ parent.getRef(CurrentScheduler).scheduleTask(() => child.evaluate(effect as any), 0)
5288
+ }
5289
+ return child
5290
+ }
5291
+
5018
5292
  /**
5019
5293
  * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
5020
5294
  * aborted.
@@ -5025,22 +5299,9 @@ export const fork = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never,
5025
5299
  * @experimental
5026
5300
  * @category handle & forking
5027
5301
  */
5028
- export const forkDaemon = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never, R> =>
5029
- make(function(env, onExit) {
5030
- const controller = new AbortController()
5031
- const handle = new HandleImpl<A, E>(controller.signal, controller)
5032
- const nextEnv = envMutate(env, (map) => {
5033
- map[currentAbortController.key] = controller
5034
- map[currentAbortSignal.key] = controller.signal
5035
- return map
5036
- })
5037
- envGet(env, currentScheduler).scheduleTask(() => {
5038
- self[runSymbol](nextEnv, (exit) => {
5039
- handle.emit(exit)
5040
- })
5041
- }, 0)
5042
- onExit(Either.right(handle))
5043
- })
5302
+ export const forkDaemon = <A, E, R>(
5303
+ self: Micro<A, E, R>
5304
+ ): Micro<Fiber<A, E>, never, R> => withFiber((fiber) => succeed(unsafeFork(fiber, self, false, true)))
5044
5305
 
5045
5306
  /**
5046
5307
  * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
@@ -5063,7 +5324,7 @@ export const forkIn: {
5063
5324
  * @experimental
5064
5325
  * @category handle & forking
5065
5326
  */
5066
- (scope: MicroScope): <A, E, R>(self: Micro<A, E, R>) => Micro<Handle<A, E>, never, R>
5327
+ (scope: MicroScope): <A, E, R>(self: Micro<A, E, R>) => Micro<Fiber<A, E>, never, R>
5067
5328
  /**
5068
5329
  * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
5069
5330
  * aborted.
@@ -5074,15 +5335,15 @@ export const forkIn: {
5074
5335
  * @experimental
5075
5336
  * @category handle & forking
5076
5337
  */
5077
- <A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<Handle<A, E>, never, R>
5338
+ <A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<Fiber<A, E>, never, R>
5078
5339
  } = dual(
5079
5340
  2,
5080
- <A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<Handle<A, E>, never, R> =>
5341
+ <A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<Fiber<A, E>, never, R> =>
5081
5342
  uninterruptibleMask((restore) =>
5082
5343
  flatMap(scope.fork, (scope) =>
5083
5344
  tap(
5084
5345
  restore(forkDaemon(onExit(self, (exit) => scope.close(exit)))),
5085
- (fiber) => scope.addFinalizer((_) => asVoid(fiber.interrupt))
5346
+ (fiber) => scope.addFinalizer((_) => fiberInterrupt(fiber))
5086
5347
  ))
5087
5348
  )
5088
5349
  )
@@ -5097,7 +5358,7 @@ export const forkIn: {
5097
5358
  * @experimental
5098
5359
  * @category handle & forking
5099
5360
  */
5100
- export const forkScoped = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never, R | MicroScope> =>
5361
+ export const forkScoped = <A, E, R>(self: Micro<A, E, R>): Micro<Fiber<A, E>, never, R | MicroScope> =>
5101
5362
  flatMap(scope, (scope) => forkIn(self, scope))
5102
5363
 
5103
5364
  // ----------------------------------------------------------------------------
@@ -5134,28 +5395,21 @@ export const runFork = <A, E>(
5134
5395
  readonly signal?: AbortSignal | undefined
5135
5396
  readonly scheduler?: MicroScheduler | undefined
5136
5397
  } | undefined
5137
- ): Handle<A, E> => {
5138
- const controller = new AbortController()
5139
- const refs = Object.create(null)
5140
- refs[currentAbortController.key] = controller
5141
- refs[currentAbortSignal.key] = controller.signal
5142
- refs[currentScheduler.key] = options?.scheduler ?? new MicroSchedulerDefault()
5143
- const env = envMake(refs)
5144
- const handle = new HandleImpl<A, E>(controller.signal, controller)
5145
- effect[runSymbol](envSet(env, currentAbortSignal, handle._controller.signal), (exit) => {
5146
- handle.emit(exit)
5147
- if (options?.signal) {
5148
- options.signal.removeEventListener("abort", handle.unsafeInterrupt)
5149
- }
5150
- })
5398
+ ): FiberImpl<A, E> => {
5399
+ const fiber = new FiberImpl<A, E>(CurrentScheduler.context(
5400
+ options?.scheduler ?? new MicroSchedulerDefault()
5401
+ ))
5402
+ fiber.evaluate(effect as any)
5151
5403
  if (options?.signal) {
5152
5404
  if (options.signal.aborted) {
5153
- handle.unsafeInterrupt()
5405
+ fiber.unsafeInterrupt()
5154
5406
  } else {
5155
- options.signal.addEventListener("abort", handle.unsafeInterrupt, { once: true })
5407
+ const abort = () => fiber.unsafeInterrupt()
5408
+ options.signal.addEventListener("abort", abort, { once: true })
5409
+ fiber.addObserver(() => options.signal!.removeEventListener("abort", abort))
5156
5410
  }
5157
5411
  }
5158
- return handle
5412
+ return fiber
5159
5413
  }
5160
5414
 
5161
5415
  /**
@@ -5194,10 +5448,10 @@ export const runPromise = <A, E>(
5194
5448
  } | undefined
5195
5449
  ): Promise<A> =>
5196
5450
  runPromiseExit(effect, options).then((exit) => {
5197
- if (exit._tag === "Left") {
5198
- throw exit.left
5451
+ if (exit._tag === "Failure") {
5452
+ throw exit.cause
5199
5453
  }
5200
- return exit.right
5454
+ return exit.value
5201
5455
  })
5202
5456
 
5203
5457
  /**
@@ -5212,13 +5466,9 @@ export const runPromise = <A, E>(
5212
5466
  */
5213
5467
  export const runSyncExit = <A, E>(effect: Micro<A, E>): MicroExit<A, E> => {
5214
5468
  const scheduler = new MicroSchedulerDefault()
5215
- const handle = runFork(effect, { scheduler })
5469
+ const fiber = runFork(effect, { scheduler })
5216
5470
  scheduler.flush()
5217
- const exit = handle.unsafePoll()
5218
- if (exit === null) {
5219
- return exitDie(handle)
5220
- }
5221
- return exit
5471
+ return fiber._exit ?? exitDie(fiber)
5222
5472
  }
5223
5473
 
5224
5474
  /**
@@ -5231,10 +5481,8 @@ export const runSyncExit = <A, E>(effect: Micro<A, E>): MicroExit<A, E> => {
5231
5481
  */
5232
5482
  export const runSync = <A, E>(effect: Micro<A, E>): A => {
5233
5483
  const exit = runSyncExit(effect)
5234
- if (exit._tag === "Left") {
5235
- throw exit.left
5236
- }
5237
- return exit.right
5484
+ if (exit._tag === "Failure") throw exit.cause
5485
+ return exit.value
5238
5486
  }
5239
5487
 
5240
5488
  // ----------------------------------------------------------------------------
@@ -5247,35 +5495,35 @@ export const runSync = <A, E>(effect: Micro<A, E>): A => {
5247
5495
  * @category errors
5248
5496
  */
5249
5497
  export interface YieldableError extends Pipeable, Inspectable, Readonly<Error> {
5250
- readonly [EffectTypeId]: Effect.VarianceStruct<never, this, never>
5251
- readonly [StreamTypeId]: Stream.VarianceStruct<never, this, never>
5252
- readonly [SinkTypeId]: Sink.VarianceStruct<never, unknown, never, this, never>
5253
- readonly [ChannelTypeId]: Channel.VarianceStruct<never, unknown, this, unknown, never, unknown, never>
5498
+ readonly [Effectable.EffectTypeId]: Effect.VarianceStruct<never, this, never>
5499
+ readonly [Effectable.StreamTypeId]: Stream.VarianceStruct<never, this, never>
5500
+ readonly [Effectable.SinkTypeId]: Sink.VarianceStruct<never, unknown, never, this, never>
5501
+ readonly [Effectable.ChannelTypeId]: Channel.VarianceStruct<never, unknown, this, unknown, never, unknown, never>
5254
5502
  readonly [TypeId]: Micro.Variance<never, this, never>
5255
- readonly [runSymbol]: (env: Env<any>, onExit: (exit: MicroExit<never, this>) => void) => void
5256
5503
  [Symbol.iterator](): MicroIterator<Micro<never, this, never>>
5257
5504
  }
5258
5505
 
5259
5506
  const YieldableError: new(message?: string) => YieldableError = (function() {
5260
- class YieldableError extends globalThis.Error {
5261
- [runSymbol](_env: any, onExit: any) {
5262
- onExit(exitFail(this))
5263
- }
5264
- toString() {
5507
+ class YieldableError extends globalThis.Error {}
5508
+ Object.assign(YieldableError.prototype, MicroProto, StructuralPrototype, {
5509
+ [identifier]: "Failure",
5510
+ [evaluate]() {
5511
+ return fail(this)
5512
+ },
5513
+ toString(this: Error) {
5265
5514
  return this.message ? `${this.name}: ${this.message}` : this.name
5266
- }
5515
+ },
5267
5516
  toJSON() {
5268
5517
  return { ...this }
5269
- }
5270
- [NodeInspectSymbol](): string {
5518
+ },
5519
+ [NodeInspectSymbol](this: Error): string {
5271
5520
  const stack = this.stack
5272
5521
  if (stack) {
5273
5522
  return `${this.toString()}\n${stack.split("\n").slice(1).join("\n")}`
5274
5523
  }
5275
5524
  return this.toString()
5276
5525
  }
5277
- }
5278
- Object.assign(YieldableError.prototype, MicroProto, StructuralPrototype)
5526
+ })
5279
5527
  return YieldableError as any
5280
5528
  })()
5281
5529