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/dist/esm/Micro.js CHANGED
@@ -1,16 +1,25 @@
1
+ /**
2
+ * A lightweight alternative to the `Effect` data type, with a subset of the functionality.
3
+ *
4
+ * @since 3.4.0
5
+ * @experimental
6
+ */
7
+ import * as Arr from "effect/Array";
1
8
  import * as Context from "./Context.js";
2
9
  import * as Effectable from "./Effectable.js";
3
10
  import * as Either from "./Either.js";
11
+ import * as Equal from "./Equal.js";
4
12
  import { constTrue, constVoid, dual, identity } from "./Function.js";
5
13
  import { globalValue } from "./GlobalValue.js";
6
- import { NodeInspectSymbol, toStringUnknown } from "./Inspectable.js";
14
+ import * as Hash from "./Hash.js";
15
+ import { format, NodeInspectSymbol, toStringUnknown } from "./Inspectable.js";
16
+ import * as InternalContext from "./internal/context.js";
7
17
  import * as doNotation from "./internal/doNotation.js";
8
18
  import { StructuralPrototype } from "./internal/effectable.js";
9
- import { SingleShotGen } from "./internal/singleShotGen.js";
10
19
  import * as Option from "./Option.js";
11
20
  import { pipeArguments } from "./Pipeable.js";
12
21
  import { hasProperty, isIterable, isTagged } from "./Predicate.js";
13
- import { YieldWrap, yieldWrapGet } from "./Utils.js";
22
+ import { SingleShotGen, YieldWrap, yieldWrapGet } from "./Utils.js";
14
23
  /**
15
24
  * @since 3.4.0
16
25
  * @experimental
@@ -20,9 +29,9 @@ export const TypeId = /*#__PURE__*/Symbol.for("effect/Micro");
20
29
  /**
21
30
  * @since 3.4.0
22
31
  * @experimental
23
- * @category symbols
32
+ * @category MicroExit
24
33
  */
25
- export const runSymbol = /*#__PURE__*/Symbol.for("effect/Micro/runSymbol");
34
+ export const MicroExitTypeId = /*#__PURE__*/Symbol.for("effect/Micro/MicroExit");
26
35
  /**
27
36
  * @since 3.4.0
28
37
  * @experimental
@@ -30,40 +39,6 @@ export const runSymbol = /*#__PURE__*/Symbol.for("effect/Micro/runSymbol");
30
39
  */
31
40
  export const isMicro = u => typeof u === "object" && u !== null && TypeId in u;
32
41
  // ----------------------------------------------------------------------------
33
- // Microable
34
- // ----------------------------------------------------------------------------
35
- const MicroProto = {
36
- ...Effectable.EffectPrototype,
37
- _op: "Micro",
38
- [TypeId]: {
39
- _A: identity,
40
- _E: identity,
41
- _R: identity
42
- },
43
- [Symbol.iterator]() {
44
- return new SingleShotGen(new YieldWrap(this));
45
- }
46
- };
47
- const MicroBase = /*#__PURE__*/function () {
48
- function Base() {}
49
- Base.prototype = MicroProto;
50
- return Base;
51
- }();
52
- /**
53
- * @since 3.8.4
54
- * @experimental
55
- * @category constructors
56
- */
57
- export class Class extends MicroBase {
58
- /**
59
- * @since 3.8.4
60
- * @experimental
61
- */
62
- [runSymbol](env, onExit) {
63
- this.asMicro()[runSymbol](env, onExit);
64
- }
65
- }
66
- // ----------------------------------------------------------------------------
67
42
  // MicroCause
68
43
  // ----------------------------------------------------------------------------
69
44
  /**
@@ -197,976 +172,1102 @@ export const causeWithTrace = /*#__PURE__*/dual(2, (self, trace) => {
197
172
  return causeFail(self.error, traces);
198
173
  }
199
174
  });
175
+ // ----------------------------------------------------------------------------
176
+ // Fiber
177
+ // ----------------------------------------------------------------------------
200
178
  /**
201
- * @since 3.4.6
202
- * @experimental
203
- * @category MicroExit
204
- */
205
- export const exitInterrupt = /*#__PURE__*/Either.left( /*#__PURE__*/causeInterrupt());
206
- /**
207
- * @since 3.4.6
208
- * @experimental
209
- * @category MicroExit
210
- */
211
- export const exitSucceed = Either.right;
212
- /**
213
- * @since 3.4.6
214
- * @experimental
215
- * @category MicroExit
216
- */
217
- export const exitFail = e => Either.left(causeFail(e));
218
- /**
219
- * @since 3.4.6
220
- * @experimental
221
- * @category MicroExit
222
- */
223
- export const exitDie = defect => Either.left(causeDie(defect));
224
- /**
225
- * @since 3.4.6
179
+ * @since 3.11.0
226
180
  * @experimental
227
- * @category MicroExit
181
+ * @category Fiber
228
182
  */
229
- export const exitFailCause = Either.left;
183
+ export const FiberTypeId = /*#__PURE__*/Symbol.for("effect/Micro/Fiber");
184
+ const fiberVariance = {
185
+ _A: identity,
186
+ _E: identity
187
+ };
188
+ class FiberImpl {
189
+ context;
190
+ interruptible;
191
+ [FiberTypeId];
192
+ _stack = [];
193
+ _observers = [];
194
+ _exit;
195
+ _children;
196
+ currentOpCount = 0;
197
+ constructor(context, interruptible = true) {
198
+ this.context = context;
199
+ this.interruptible = interruptible;
200
+ this[FiberTypeId] = fiberVariance;
201
+ }
202
+ getRef(ref) {
203
+ return InternalContext.unsafeGetReference(this.context, ref);
204
+ }
205
+ addObserver(cb) {
206
+ if (this._exit) {
207
+ cb(this._exit);
208
+ return constVoid;
209
+ }
210
+ this._observers.push(cb);
211
+ return () => {
212
+ const index = this._observers.indexOf(cb);
213
+ if (index >= 0) {
214
+ this._observers.splice(index, 1);
215
+ }
216
+ };
217
+ }
218
+ _interrupted = false;
219
+ unsafeInterrupt() {
220
+ if (this._exit) {
221
+ return;
222
+ }
223
+ this._interrupted = true;
224
+ if (this.interruptible) {
225
+ this.evaluate(exitInterrupt);
226
+ }
227
+ }
228
+ unsafePoll() {
229
+ return this._exit;
230
+ }
231
+ evaluate(effect) {
232
+ if (this._exit) {
233
+ return;
234
+ } else if (this._yielded !== undefined) {
235
+ const yielded = this._yielded;
236
+ this._yielded = undefined;
237
+ yielded();
238
+ }
239
+ const exit = this.runLoop(effect);
240
+ if (exit === Yield) {
241
+ return;
242
+ }
243
+ // the interruptChildren middlware is added in Micro.fork, so it can be
244
+ // tree-shaken if not used
245
+ const interruptChildren = fiberMiddleware.interruptChildren && fiberMiddleware.interruptChildren(this);
246
+ if (interruptChildren !== undefined) {
247
+ return this.evaluate(flatMap(interruptChildren, () => exit));
248
+ }
249
+ this._exit = exit;
250
+ for (let i = 0; i < this._observers.length; i++) {
251
+ this._observers[i](exit);
252
+ }
253
+ this._observers.length = 0;
254
+ }
255
+ runLoop(effect) {
256
+ let yielding = false;
257
+ let current = effect;
258
+ this.currentOpCount = 0;
259
+ try {
260
+ while (true) {
261
+ this.currentOpCount++;
262
+ if (!yielding && this.getRef(CurrentScheduler).shouldYield(this)) {
263
+ yielding = true;
264
+ const prev = current;
265
+ current = flatMap(yieldNow, () => prev);
266
+ }
267
+ current = current[evaluate](this);
268
+ if (current === Yield) {
269
+ const yielded = this._yielded;
270
+ if (MicroExitTypeId in yielded) {
271
+ this._yielded = undefined;
272
+ return yielded;
273
+ }
274
+ return Yield;
275
+ }
276
+ }
277
+ } catch (error) {
278
+ if (!hasProperty(current, evaluate)) {
279
+ return exitDie(`Micro/Fiber.runLoop: Not a valid effect: ${String(current)}`);
280
+ }
281
+ return exitDie(error);
282
+ }
283
+ }
284
+ getCont(symbol) {
285
+ while (true) {
286
+ const op = this._stack.pop();
287
+ if (!op) return undefined;
288
+ const cont = op[ensureCont] && op[ensureCont](this);
289
+ if (cont) return {
290
+ [symbol]: cont
291
+ };
292
+ if (op[symbol]) return op;
293
+ }
294
+ }
295
+ // cancel the yielded operation, or for the yielded exit value
296
+ _yielded = undefined;
297
+ yieldWith(value) {
298
+ this._yielded = value;
299
+ return Yield;
300
+ }
301
+ children() {
302
+ return this._children ??= new Set();
303
+ }
304
+ }
305
+ const fiberMiddleware = /*#__PURE__*/globalValue("effect/Micro/fiberMiddleware", () => ({
306
+ interruptChildren: undefined
307
+ }));
308
+ const fiberInterruptChildren = fiber => {
309
+ if (fiber._children === undefined || fiber._children.size === 0) {
310
+ return undefined;
311
+ }
312
+ return fiberInterruptAll(fiber._children);
313
+ };
230
314
  /**
231
- * @since 3.4.6
315
+ * @since 3.11.0
232
316
  * @experimental
233
- * @category MicroExit
317
+ * @category Fiber
234
318
  */
235
- export const exitIsSuccess = Either.isRight;
319
+ export const fiberAwait = self => async(resume => sync(self.addObserver(exit => resume(succeed(exit)))));
236
320
  /**
237
- * @since 3.4.6
321
+ * @since 3.11.0
238
322
  * @experimental
239
- * @category MicroExit
323
+ * @category Fiber
240
324
  */
241
- export const exitIsFailure = Either.isLeft;
325
+ export const fiberInterrupt = self => suspend(() => {
326
+ self.unsafeInterrupt();
327
+ return asVoid(fiberAwait(self));
328
+ });
242
329
  /**
243
- * @since 3.4.6
330
+ * @since 3.11.0
244
331
  * @experimental
245
- * @category MicroExit
332
+ * @category Fiber
246
333
  */
247
- export const exitIsInterrupt = self => exitIsFailure(self) && self.left._tag === "Interrupt";
334
+ export const fiberInterruptAll = fibers => suspend(() => {
335
+ for (const fiber of fibers) fiber.unsafeInterrupt();
336
+ const iter = fibers[Symbol.iterator]();
337
+ const wait = suspend(() => {
338
+ let result = iter.next();
339
+ while (!result.done) {
340
+ if (result.value.unsafePoll()) {
341
+ result = iter.next();
342
+ continue;
343
+ }
344
+ const fiber = result.value;
345
+ return async(resume => {
346
+ fiber.addObserver(_ => {
347
+ resume(wait);
348
+ });
349
+ });
350
+ }
351
+ return exitVoid;
352
+ });
353
+ return wait;
354
+ });
355
+ const identifier = /*#__PURE__*/Symbol.for("effect/Micro/identifier");
356
+ const args = /*#__PURE__*/Symbol.for("effect/Micro/args");
357
+ const evaluate = /*#__PURE__*/Symbol.for("effect/Micro/evaluate");
358
+ const successCont = /*#__PURE__*/Symbol.for("effect/Micro/successCont");
359
+ const failureCont = /*#__PURE__*/Symbol.for("effect/Micro/failureCont");
360
+ const ensureCont = /*#__PURE__*/Symbol.for("effect/Micro/ensureCont");
361
+ const Yield = /*#__PURE__*/Symbol.for("effect/Micro/Yield");
362
+ const microVariance = {
363
+ _A: identity,
364
+ _E: identity,
365
+ _R: identity
366
+ };
367
+ const MicroProto = {
368
+ ...Effectable.EffectPrototype,
369
+ _op: "Micro",
370
+ [TypeId]: microVariance,
371
+ pipe() {
372
+ return pipeArguments(this, arguments);
373
+ },
374
+ [Symbol.iterator]() {
375
+ return new SingleShotGen(new YieldWrap(this));
376
+ },
377
+ toJSON() {
378
+ return {
379
+ _id: "effect/Micro",
380
+ op: this[identifier],
381
+ ...(args in this ? {
382
+ args: this[args]
383
+ } : undefined)
384
+ };
385
+ },
386
+ toString() {
387
+ return format(this);
388
+ },
389
+ [NodeInspectSymbol]() {
390
+ return format(this);
391
+ }
392
+ };
393
+ function defaultEvaluate(_fiber) {
394
+ return exitDie(`Micro.evaluate: Not implemented`);
395
+ }
396
+ const makePrimitiveProto = options => ({
397
+ ...MicroProto,
398
+ [identifier]: options.op,
399
+ [evaluate]: options.eval ?? defaultEvaluate,
400
+ [successCont]: options.contA,
401
+ [failureCont]: options.contE,
402
+ [ensureCont]: options.ensure
403
+ });
404
+ const makePrimitive = options => {
405
+ const Proto = makePrimitiveProto(options);
406
+ return function () {
407
+ const self = Object.create(Proto);
408
+ self[args] = options.single === false ? arguments : arguments[0];
409
+ return self;
410
+ };
411
+ };
412
+ const makeExit = options => {
413
+ const Proto = {
414
+ ...makePrimitiveProto(options),
415
+ [MicroExitTypeId]: MicroExitTypeId,
416
+ _tag: options.op,
417
+ get [options.prop]() {
418
+ return this[args];
419
+ },
420
+ toJSON() {
421
+ return {
422
+ _id: "effect/Micro/Exit",
423
+ _tag: options.op,
424
+ [options.prop]: this[args]
425
+ };
426
+ },
427
+ [Equal.symbol](that) {
428
+ return isMicroExit(that) && that._tag === options.op && Equal.equals(this[args], that[args]);
429
+ },
430
+ [Hash.symbol]() {
431
+ return Hash.cached(this, Hash.combine(Hash.string(options.op))(Hash.hash(this[args])));
432
+ }
433
+ };
434
+ return function (value) {
435
+ const self = Object.create(Proto);
436
+ self[args] = value;
437
+ self[successCont] = undefined;
438
+ self[failureCont] = undefined;
439
+ self[ensureCont] = undefined;
440
+ return self;
441
+ };
442
+ };
248
443
  /**
249
- * @since 3.4.6
444
+ * Creates a `Micro` effect that will succeed with the specified constant value.
445
+ *
446
+ * @since 3.4.0
250
447
  * @experimental
251
- * @category MicroExit
448
+ * @category constructors
252
449
  */
253
- export const exitIsFail = self => exitIsFailure(self) && self.left._tag === "Fail";
450
+ export const succeed = /*#__PURE__*/makeExit({
451
+ op: "Success",
452
+ prop: "value",
453
+ eval(fiber) {
454
+ const cont = fiber.getCont(successCont);
455
+ return cont ? cont[successCont](this[args], fiber) : fiber.yieldWith(this);
456
+ }
457
+ });
254
458
  /**
459
+ * Creates a `Micro` effect that will fail with the specified `MicroCause`.
460
+ *
255
461
  * @since 3.4.6
256
462
  * @experimental
257
- * @category MicroExit
463
+ * @category constructors
258
464
  */
259
- export const exitIsDie = self => exitIsFailure(self) && self.left._tag === "Die";
465
+ export const failCause = /*#__PURE__*/makeExit({
466
+ op: "Failure",
467
+ prop: "cause",
468
+ eval(fiber) {
469
+ let cont = fiber.getCont(failureCont);
470
+ while (causeIsInterrupt(this[args]) && cont && fiber.interruptible) {
471
+ cont = fiber.getCont(failureCont);
472
+ }
473
+ return cont ? cont[failureCont](this[args], fiber) : fiber.yieldWith(this);
474
+ }
475
+ });
260
476
  /**
261
- * @since 3.4.6
477
+ * Creates a `Micro` effect that will fail with the specified error.
478
+ *
479
+ * This will result in a `CauseFail`, where the error is tracked at the
480
+ * type level.
481
+ *
482
+ * @since 3.4.0
262
483
  * @experimental
263
- * @category MicroExit
484
+ * @category constructors
264
485
  */
265
- export const exitVoid = /*#__PURE__*/exitSucceed(void 0);
266
- // ----------------------------------------------------------------------------
267
- // env
268
- // ----------------------------------------------------------------------------
486
+ export const fail = error => failCause(causeFail(error));
269
487
  /**
488
+ * Creates a `Micro` effect that will succeed with the lazily evaluated value.
489
+ *
490
+ * If the evaluation of the value throws an error, the effect will fail with
491
+ * `CauseDie`.
492
+ *
270
493
  * @since 3.4.0
271
494
  * @experimental
272
- * @category environment
495
+ * @category constructors
273
496
  */
274
- export const EnvTypeId = /*#__PURE__*/Symbol.for("effect/Micro/Env");
275
- const EnvProto = {
276
- [EnvTypeId]: {
277
- _R: identity
278
- },
279
- pipe() {
280
- return pipeArguments(this, arguments);
497
+ export const sync = /*#__PURE__*/makePrimitive({
498
+ op: "Sync",
499
+ eval(fiber) {
500
+ const value = this[args]();
501
+ const cont = fiber.getCont(successCont);
502
+ return cont ? cont[successCont](value, fiber) : fiber.yieldWith(exitSucceed(value));
281
503
  }
282
- };
504
+ });
283
505
  /**
506
+ * Lazily creates a `Micro` effect from the given side-effect.
507
+ *
284
508
  * @since 3.4.0
285
509
  * @experimental
286
- * @category environment
510
+ * @category constructors
287
511
  */
288
- export const envMake = refs => {
289
- const self = Object.create(EnvProto);
290
- self.refs = refs;
291
- return self;
292
- };
512
+ export const suspend = /*#__PURE__*/makePrimitive({
513
+ op: "Suspend",
514
+ eval(_fiber) {
515
+ return this[args]();
516
+ }
517
+ });
293
518
  /**
519
+ * Pause the execution of the current `Micro` effect, and resume it on the next
520
+ * scheduler tick.
521
+ *
294
522
  * @since 3.4.0
295
523
  * @experimental
296
- * @category environment
524
+ * @category constructors
297
525
  */
298
- export const envUnsafeMakeEmpty = () => {
299
- const controller = new AbortController();
300
- const refs = Object.create(null);
301
- refs[currentAbortController.key] = controller;
302
- refs[currentAbortSignal.key] = controller.signal;
303
- refs[currentScheduler.key] = new MicroSchedulerDefault();
304
- return envMake(refs);
305
- };
526
+ export const yieldNowWith = /*#__PURE__*/makePrimitive({
527
+ op: "Yield",
528
+ eval(fiber) {
529
+ let resumed = false;
530
+ fiber.getRef(CurrentScheduler).scheduleTask(() => {
531
+ if (resumed) return;
532
+ fiber.evaluate(exitVoid);
533
+ }, this[args] ?? 0);
534
+ return fiber.yieldWith(() => {
535
+ resumed = true;
536
+ });
537
+ }
538
+ });
306
539
  /**
540
+ * Pause the execution of the current `Micro` effect, and resume it on the next
541
+ * scheduler tick.
542
+ *
307
543
  * @since 3.4.0
308
544
  * @experimental
309
- * @category environment
545
+ * @category constructors
310
546
  */
311
- export const envGet = /*#__PURE__*/dual(2, (self, ref) => ref.key in self.refs ? self.refs[ref.key] : ref.initial);
547
+ export const yieldNow = /*#__PURE__*/yieldNowWith(0);
312
548
  /**
549
+ * Creates a `Micro` effect that will succeed with `Option.Some` of the value.
550
+ *
313
551
  * @since 3.4.0
314
552
  * @experimental
315
- * @category environment
553
+ * @category constructors
316
554
  */
317
- export const envSet = /*#__PURE__*/dual(3, (self, ref, value) => {
318
- const refs = Object.assign(Object.create(null), self.refs);
319
- refs[ref.key] = value;
320
- return envMake(refs);
321
- });
555
+ export const succeedSome = a => succeed(Option.some(a));
322
556
  /**
557
+ * Creates a `Micro` effect that will succeed with `Option.None`.
558
+ *
323
559
  * @since 3.4.0
324
560
  * @experimental
325
- * @category environment
561
+ * @category constructors
326
562
  */
327
- export const envMutate = /*#__PURE__*/dual(2, (self, f) => envMake(f(Object.assign(Object.create(null), self.refs))));
563
+ export const succeedNone = /*#__PURE__*/succeed( /*#__PURE__*/Option.none());
328
564
  /**
329
- * Access the given `Context.Tag` from the environment.
565
+ * Creates a `Micro` effect that will fail with the lazily evaluated `MicroCause`.
330
566
  *
331
567
  * @since 3.4.0
332
568
  * @experimental
333
- * @category environment
569
+ * @category constructors
334
570
  */
335
- export const service = tag => make(function (env, onExit) {
336
- onExit(exitSucceed(Context.get(envGet(env, currentContext), tag)));
337
- });
571
+ export const failCauseSync = evaluate => suspend(() => failCause(evaluate()));
338
572
  /**
339
- * Access the given `Context.Tag` from the environment, without tracking the
340
- * dependency at the type level.
573
+ * Creates a `Micro` effect that will die with the specified error.
341
574
  *
342
- * It will return an `Option` of the service, depending on whether it is
343
- * available in the environment or not.
575
+ * This will result in a `CauseDie`, where the error is not tracked at
576
+ * the type level.
344
577
  *
345
578
  * @since 3.4.0
346
579
  * @experimental
347
- * @category environment
580
+ * @category constructors
348
581
  */
349
- export const serviceOption = tag => make(function (env, onExit) {
350
- onExit(exitSucceed(Context.getOption(envGet(env, currentContext), tag)));
351
- });
582
+ export const die = defect => exitDie(defect);
352
583
  /**
353
- * Retrieve the current value of the given `EnvRef`.
584
+ * Creates a `Micro` effect that will fail with the lazily evaluated error.
354
585
  *
355
- * @since 3.4.0
586
+ * This will result in a `CauseFail`, where the error is tracked at the
587
+ * type level.
588
+ *
589
+ * @since 3.4.6
356
590
  * @experimental
357
- * @category environment
591
+ * @category constructors
358
592
  */
359
- export const getEnvRef = envRef => make((env, onExit) => onExit(Either.right(envGet(env, envRef))));
593
+ export const failSync = error => suspend(() => fail(error()));
360
594
  /**
361
- * Set the value of the given `EnvRef` for the duration of the effect.
595
+ * Converts an `Option` into a `Micro` effect, that will fail with
596
+ * `NoSuchElementException` if the option is `None`. Otherwise, it will succeed with the
597
+ * value of the option.
362
598
  *
363
599
  * @since 3.4.0
364
600
  * @experimental
365
- * @category environment
601
+ * @category constructors
366
602
  */
367
- export const locally = /*#__PURE__*/dual(3, (self, fiberRef, value) => make((env, onExit) => self[runSymbol](envSet(env, fiberRef, value), onExit)));
603
+ export const fromOption = option => option._tag === "Some" ? succeed(option.value) : fail(new NoSuchElementException({}));
368
604
  /**
369
- * Access the current `Context` from the environment.
605
+ * Converts an `Either` into a `Micro` effect, that will fail with the left side
606
+ * of the either if it is a `Left`. Otherwise, it will succeed with the right
607
+ * side of the either.
370
608
  *
371
609
  * @since 3.4.0
372
610
  * @experimental
373
- * @category environment
611
+ * @category constructors
374
612
  */
375
- export const context = () => getEnvRef(currentContext);
613
+ export const fromEither = either => either._tag === "Right" ? succeed(either.right) : fail(either.left);
614
+ const void_ = /*#__PURE__*/succeed(void 0);
615
+ export {
376
616
  /**
377
- * Merge the given `Context` with the current context.
617
+ * A `Micro` effect that will succeed with `void` (`undefined`).
378
618
  *
379
619
  * @since 3.4.0
380
620
  * @experimental
381
- * @category environment
621
+ * @category constructors
382
622
  */
383
- export const provideContext = /*#__PURE__*/dual(2, (self, provided) => make(function (env, onExit) {
384
- const context = envGet(env, currentContext);
385
- const nextEnv = envSet(env, currentContext, Context.merge(context, provided));
386
- self[runSymbol](nextEnv, onExit);
387
- }));
623
+ void_ as void };
624
+ const try_ = options => suspend(() => {
625
+ try {
626
+ return succeed(options.try());
627
+ } catch (err) {
628
+ return fail(options.catch(err));
629
+ }
630
+ });
631
+ export {
388
632
  /**
389
- * Add the provided service to the current context.
633
+ * The `Micro` equivalent of a try / catch block, which allows you to map
634
+ * thrown errors to a specific error type.
390
635
  *
391
636
  * @since 3.4.0
392
637
  * @experimental
393
- * @category environment
394
- */
395
- export const provideService = /*#__PURE__*/dual(3, (self, tag, service) => make(function (env, onExit) {
396
- const context = envGet(env, currentContext);
397
- const nextEnv = envSet(env, currentContext, Context.add(context, tag, service));
398
- self[runSymbol](nextEnv, onExit);
399
- }));
638
+ * @category constructors
639
+ * @example
640
+ * ```ts
641
+ * import { Micro } from "effect"
642
+ *
643
+ * Micro.try({
644
+ * try: () => throw new Error("boom"),
645
+ * catch: (cause) => new Error("caught", { cause })
646
+ * })
647
+ * ```
648
+ */
649
+ try_ as try };
400
650
  /**
401
- * Create a service using the provided `Micro` effect, and add it to the
402
- * current context.
651
+ * Wrap a `Promise` into a `Micro` effect. Any errors will result in a
652
+ * `CauseDie`.
403
653
  *
404
- * @since 3.4.6
654
+ * @since 3.4.0
405
655
  * @experimental
406
- * @category environment
656
+ * @category constructors
407
657
  */
408
- export const provideServiceEffect = /*#__PURE__*/dual(3, (self, tag, acquire) => flatMap(acquire, service => provideService(self, tag, service)));
409
- const setImmediate = "setImmediate" in globalThis ? globalThis.setImmediate : f => setTimeout(f, 0);
658
+ export const promise = evaluate => asyncOptions(function (resume, signal) {
659
+ evaluate(signal).then(a => resume(succeed(a)), e => resume(die(e)));
660
+ }, evaluate.length !== 0);
410
661
  /**
411
- * @since 3.5.9
662
+ * Wrap a `Promise` into a `Micro` effect. Any errors will be caught and
663
+ * converted into a specific error type.
664
+ *
665
+ * @since 3.4.0
412
666
  * @experimental
413
- * @category scheduler
667
+ * @category constructors
668
+ * @example
669
+ * ```ts
670
+ * import { Micro } from "effect"
671
+ *
672
+ * Micro.tryPromise({
673
+ * try: () => Promise.resolve("success"),
674
+ * catch: (cause) => new Error("caught", { cause })
675
+ * })
676
+ * ```
414
677
  */
415
- export class MicroSchedulerDefault {
416
- tasks = [];
417
- running = false;
418
- /**
419
- * @since 3.5.9
420
- */
421
- scheduleTask(task, _priority) {
422
- this.tasks.push(task);
423
- if (!this.running) {
424
- this.running = true;
425
- setImmediate(this.afterScheduled);
426
- }
427
- }
428
- /**
429
- * @since 3.5.9
430
- */
431
- afterScheduled = () => {
432
- this.running = false;
433
- this.runTasks();
434
- };
435
- /**
436
- * @since 3.5.9
437
- */
438
- runTasks() {
439
- const tasks = this.tasks;
440
- this.tasks = [];
441
- for (let i = 0, len = tasks.length; i < len; i++) {
442
- tasks[i]();
443
- }
444
- }
445
- /**
446
- * @since 3.5.9
447
- */
448
- shouldYield(_env) {
449
- return false;
450
- }
451
- /**
452
- * @since 3.5.9
453
- */
454
- flush() {
455
- while (this.tasks.length > 0) {
456
- this.runTasks();
457
- }
678
+ export const tryPromise = options => asyncOptions(function (resume, signal) {
679
+ try {
680
+ options.try(signal).then(a => resume(succeed(a)), e => resume(fail(options.catch(e))));
681
+ } catch (err) {
682
+ resume(fail(options.catch(err)));
458
683
  }
459
- }
460
- // ========================================================================
461
- // Env refs
462
- // ========================================================================
684
+ }, options.try.length !== 0);
463
685
  /**
686
+ * Create a `Micro` effect using the current `Fiber`.
687
+ *
464
688
  * @since 3.4.0
465
689
  * @experimental
466
- * @category environment
690
+ * @category constructors
467
691
  */
468
- export const EnvRefTypeId = /*#__PURE__*/Symbol.for("effect/Micro/EnvRef");
469
- const EnvRefProto = {
470
- ...MicroProto,
471
- [EnvRefTypeId]: EnvRefTypeId,
472
- [runSymbol](env, onExit) {
473
- getEnvRef(this)[runSymbol](env, onExit);
692
+ export const withFiber = /*#__PURE__*/makePrimitive({
693
+ op: "WithFiber",
694
+ eval(fiber) {
695
+ return this[args](fiber);
474
696
  }
475
- };
697
+ });
476
698
  /**
699
+ * Flush any yielded effects that are waiting to be executed.
700
+ *
477
701
  * @since 3.4.0
478
702
  * @experimental
479
- * @category environment refs
703
+ * @category constructors
480
704
  */
481
- export const envRefMake = (key, initial) => globalValue(key, () => {
482
- const self = Object.create(EnvRefProto);
483
- self.key = key;
484
- self.initial = initial();
485
- return self;
705
+ export const yieldFlush = /*#__PURE__*/withFiber(fiber => {
706
+ fiber.getRef(CurrentScheduler).flush();
707
+ return exitVoid;
708
+ });
709
+ const asyncOptions = /*#__PURE__*/makePrimitive({
710
+ op: "Async",
711
+ single: false,
712
+ eval(fiber) {
713
+ const register = this[args][0];
714
+ let resumed = false;
715
+ let yielded = false;
716
+ const controller = this[args][1] ? new AbortController() : undefined;
717
+ const onCancel = register(effect => {
718
+ if (resumed) return;
719
+ resumed = true;
720
+ if (yielded) {
721
+ fiber.evaluate(effect);
722
+ } else {
723
+ yielded = effect;
724
+ }
725
+ }, controller?.signal);
726
+ if (yielded !== false) return yielded;
727
+ yielded = true;
728
+ fiber._yielded = () => {
729
+ resumed = true;
730
+ };
731
+ if (controller === undefined && onCancel === undefined) {
732
+ return Yield;
733
+ }
734
+ fiber._stack.push(asyncFinalizer(() => {
735
+ resumed = true;
736
+ controller?.abort();
737
+ return onCancel ?? exitVoid;
738
+ }));
739
+ return Yield;
740
+ }
741
+ });
742
+ const asyncFinalizer = /*#__PURE__*/makePrimitive({
743
+ op: "AsyncFinalizer",
744
+ ensure(fiber) {
745
+ if (fiber.interruptible) {
746
+ fiber.interruptible = false;
747
+ fiber._stack.push(setInterruptible(true));
748
+ }
749
+ },
750
+ contE(cause, _fiber) {
751
+ return causeIsInterrupt(cause) ? flatMap(this[args](), () => failCause(cause)) : failCause(cause);
752
+ }
486
753
  });
487
754
  /**
755
+ * Create a `Micro` effect from an asynchronous computation.
756
+ *
757
+ * You can return a cleanup effect that will be run when the effect is aborted.
758
+ * It is also passed an `AbortSignal` that is triggered when the effect is
759
+ * aborted.
760
+ *
488
761
  * @since 3.4.0
489
762
  * @experimental
490
- * @category environment refs
763
+ * @category constructors
491
764
  */
492
- export const currentAbortController = /*#__PURE__*/envRefMake("effect/Micro/currentAbortController", () => undefined);
765
+ export const async = register => asyncOptions(register, register.length >= 2);
493
766
  /**
767
+ * A `Micro` that will never succeed or fail. It wraps `setInterval` to prevent
768
+ * the Javascript runtime from exiting.
769
+ *
494
770
  * @since 3.4.0
495
771
  * @experimental
496
- * @category environment refs
772
+ * @category constructors
497
773
  */
498
- export const currentAbortSignal = /*#__PURE__*/envRefMake("effect/Micro/currentAbortSignal", () => undefined);
774
+ export const never = /*#__PURE__*/async(function () {
775
+ const interval = setInterval(constVoid, 2147483646);
776
+ return sync(() => clearInterval(interval));
777
+ });
499
778
  /**
500
779
  * @since 3.4.0
501
780
  * @experimental
502
- * @category environment refs
781
+ * @category constructors
503
782
  */
504
- export const currentContext = /*#__PURE__*/envRefMake("effect/Micro/currentContext", () => Context.empty());
783
+ export const gen = (...args) => suspend(() => fromIterator(args.length === 1 ? args[0]() : args[1].call(args[0])));
784
+ const fromIterator = /*#__PURE__*/makePrimitive({
785
+ op: "Iterator",
786
+ contA(value, fiber) {
787
+ const state = this[args].next(value);
788
+ if (state.done) return succeed(state.value);
789
+ fiber._stack.push(this);
790
+ return yieldWrapGet(state.value);
791
+ },
792
+ eval(fiber) {
793
+ return this[successCont](undefined, fiber);
794
+ }
795
+ });
796
+ // ----------------------------------------------------------------------------
797
+ // mapping & sequencing
798
+ // ----------------------------------------------------------------------------
505
799
  /**
800
+ * Create a `Micro` effect that will replace the success value of the given
801
+ * effect.
802
+ *
506
803
  * @since 3.4.0
507
804
  * @experimental
508
- * @category environment refs
805
+ * @category mapping & sequencing
509
806
  */
510
- export const currentConcurrency = /*#__PURE__*/envRefMake("effect/Micro/currentConcurrency", () => "unbounded");
807
+ export const as = /*#__PURE__*/dual(2, (self, value) => map(self, _ => value));
511
808
  /**
809
+ * Wrap the success value of this `Micro` effect in an `Option.Some`.
810
+ *
512
811
  * @since 3.4.0
513
812
  * @experimental
514
- * @category environment refs
813
+ * @category mapping & sequencing
515
814
  */
516
- export const currentMaxDepthBeforeYield = /*#__PURE__*/envRefMake("effect/Micro/currentMaxDepthBeforeYield", () => 2048);
517
- const currentInterruptible = /*#__PURE__*/envRefMake("effect/Micro/currentInterruptible", () => true);
815
+ export const asSome = self => map(self, Option.some);
518
816
  /**
817
+ * Swap the error and success types of the `Micro` effect.
818
+ *
519
819
  * @since 3.4.0
520
820
  * @experimental
521
- * @category environment refs
821
+ * @category mapping & sequencing
522
822
  */
523
- export const currentScheduler = /*#__PURE__*/envRefMake("effect/Micro/currentScheduler", () => new MicroSchedulerDefault());
823
+ export const flip = self => matchEffect(self, {
824
+ onFailure: succeed,
825
+ onSuccess: fail
826
+ });
524
827
  /**
525
- * If you have a `Micro` that uses `concurrency: "inherit"`, you can use this
526
- * api to control the concurrency of that `Micro` when it is run.
828
+ * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
829
+ * a single api.
830
+ *
831
+ * It also allows you to pass in a `Micro` effect directly, which will be
832
+ * executed after the current effect.
527
833
  *
528
834
  * @since 3.4.0
529
835
  * @experimental
530
- * @category environment refs
531
- * @example
532
- * ```ts
533
- * import * as Micro from "effect/Micro"
534
- *
535
- * Micro.forEach([1, 2, 3], (n) => Micro.succeed(n), {
536
- * concurrency: "inherit"
537
- * }).pipe(
538
- * Micro.withConcurrency(2) // use a concurrency of 2
539
- * )
540
- * ```
836
+ * @category mapping & sequencing
541
837
  */
542
- export const withConcurrency = /*#__PURE__*/dual(2, (self, concurrency) => locally(self, currentConcurrency, concurrency));
543
- // ----------------------------------------------------------------------------
544
- // constructors
545
- // ----------------------------------------------------------------------------
546
- const microDepthState = /*#__PURE__*/globalValue("effect/Micro/microDepthState", () => ({
547
- depth: 0,
548
- maxDepthBeforeYield: currentMaxDepthBeforeYield.initial
838
+ export const andThen = /*#__PURE__*/dual(2, (self, f) => flatMap(self, a => {
839
+ const value = isMicro(f) ? f : typeof f === "function" ? f(a) : f;
840
+ return isMicro(value) ? value : succeed(value);
549
841
  }));
550
- const unsafeMake = run => {
551
- const self = Object.create(MicroProto);
552
- self[runSymbol] = run;
553
- return self;
554
- };
555
- const unsafeMakeOptions = (run, checkAbort) => unsafeMake(function execute(env, onExit) {
556
- if (checkAbort && env.refs[currentInterruptible.key] !== false && env.refs[currentAbortSignal.key].aborted) {
557
- return onExit(exitInterrupt);
558
- }
559
- microDepthState.depth++;
560
- if (microDepthState.depth === 1) {
561
- microDepthState.maxDepthBeforeYield = envGet(env, currentMaxDepthBeforeYield);
562
- }
563
- const scheduler = env.refs[currentScheduler.key];
564
- if (microDepthState.depth >= microDepthState.maxDepthBeforeYield || scheduler.shouldYield(env)) {
565
- scheduler.scheduleTask(() => execute(env, onExit), 0);
566
- } else {
567
- try {
568
- run(env, onExit);
569
- } catch (err) {
570
- onExit(exitDie(err));
571
- }
572
- }
573
- microDepthState.depth--;
574
- });
575
842
  /**
576
- * A low-level constructor for creating a `Micro` effect. It takes a function
577
- * that receives an environment and a callback which should be called with the
578
- * result of the effect.
843
+ * Execute a side effect from the success value of the `Micro` effect.
844
+ *
845
+ * It is similar to the `andThen` api, but the success value is ignored.
579
846
  *
580
847
  * @since 3.4.0
581
848
  * @experimental
582
- * @category constructors
849
+ * @category mapping & sequencing
583
850
  */
584
- export const make = run => unsafeMakeOptions(run, true);
851
+ export const tap = /*#__PURE__*/dual(2, (self, f) => flatMap(self, a => {
852
+ const value = isMicro(f) ? f : typeof f === "function" ? f(a) : f;
853
+ return isMicro(value) ? as(value, a) : succeed(a);
854
+ }));
585
855
  /**
586
- * Converts a `MicroExit` into a `Micro` effect.
856
+ * Replace the success value of the `Micro` effect with `void`.
587
857
  *
588
- * @since 3.4.6
858
+ * @since 3.4.0
589
859
  * @experimental
590
- * @category constructors
860
+ * @category mapping & sequencing
591
861
  */
592
- export const fromExit = self => make(function (_env, onExit) {
593
- onExit(self);
594
- });
862
+ export const asVoid = self => flatMap(self, _ => exitVoid);
595
863
  /**
596
- * Converts a lazy `MicroExit` into a `Micro` effect.
864
+ * Access the `MicroExit` of the given `Micro` effect.
597
865
  *
598
866
  * @since 3.4.6
599
867
  * @experimental
600
- * @category constructors
868
+ * @category mapping & sequencing
601
869
  */
602
- export const fromExitSync = self => make(function (_env, onExit) {
603
- onExit(self());
870
+ export const exit = self => matchCause(self, {
871
+ onFailure: exitFailCause,
872
+ onSuccess: exitSucceed
604
873
  });
605
874
  /**
606
- * Creates a `Micro` effect that will succeed with the specified constant value.
875
+ * Replace the error type of the given `Micro` with the full `MicroCause` object.
607
876
  *
608
877
  * @since 3.4.0
609
878
  * @experimental
610
- * @category constructors
879
+ * @category mapping & sequencing
611
880
  */
612
- export const succeed = a => fromExit(exitSucceed(a));
881
+ export const sandbox = self => catchAllCause(self, fail);
613
882
  /**
614
- * Creates a `Micro` effect that will succeed with `Option.Some` of the value.
883
+ * Returns an effect that races all the specified effects,
884
+ * yielding the value of the first effect to succeed with a value. Losers of
885
+ * the race will be interrupted immediately
615
886
  *
616
887
  * @since 3.4.0
617
888
  * @experimental
618
- * @category constructors
889
+ * @category sequencing
619
890
  */
620
- export const succeedSome = a => succeed(Option.some(a));
891
+ export const raceAll = all => withFiber(parent => async(resume => {
892
+ const effects = Arr.fromIterable(all);
893
+ const len = effects.length;
894
+ let doneCount = 0;
895
+ let done = false;
896
+ const fibers = new Set();
897
+ const causes = [];
898
+ const onExit = exit => {
899
+ doneCount++;
900
+ if (exit._tag === "Failure") {
901
+ causes.push(exit.cause);
902
+ if (doneCount >= len) {
903
+ resume(failCause(causes[0]));
904
+ }
905
+ return;
906
+ }
907
+ done = true;
908
+ resume(fibers.size === 0 ? exit : flatMap(uninterruptible(fiberInterruptAll(fibers)), () => exit));
909
+ };
910
+ for (let i = 0; i < len; i++) {
911
+ if (done) break;
912
+ const fiber = unsafeFork(parent, interruptible(effects[i]), true, true);
913
+ fibers.add(fiber);
914
+ fiber.addObserver(exit => {
915
+ fibers.delete(fiber);
916
+ onExit(exit);
917
+ });
918
+ }
919
+ return fiberInterruptAll(fibers);
920
+ }));
621
921
  /**
622
- * Creates a `Micro` effect that will succeed with `Option.None`.
922
+ * Returns an effect that races all the specified effects,
923
+ * yielding the value of the first effect to succeed or fail. Losers of
924
+ * the race will be interrupted immediately
623
925
  *
624
926
  * @since 3.4.0
625
927
  * @experimental
626
- * @category constructors
928
+ * @category sequencing
627
929
  */
628
- export const succeedNone = /*#__PURE__*/succeed( /*#__PURE__*/Option.none());
930
+ export const raceAllFirst = all => withFiber(parent => async(resume => {
931
+ let done = false;
932
+ const fibers = new Set();
933
+ const onExit = exit => {
934
+ done = true;
935
+ resume(fibers.size === 0 ? exit : flatMap(fiberInterruptAll(fibers), () => exit));
936
+ };
937
+ for (const effect of all) {
938
+ if (done) break;
939
+ const fiber = unsafeFork(parent, interruptible(effect), true, true);
940
+ fibers.add(fiber);
941
+ fiber.addObserver(exit => {
942
+ fibers.delete(fiber);
943
+ onExit(exit);
944
+ });
945
+ }
946
+ return fiberInterruptAll(fibers);
947
+ }));
629
948
  /**
630
- * Creates a `Micro` effect that will fail with the specified error.
631
- *
632
- * This will result in a `CauseFail`, where the error is tracked at the
633
- * type level.
949
+ * Returns an effect that races two effects, yielding the value of the first
950
+ * effect to succeed. Losers of the race will be interrupted immediately
634
951
  *
635
952
  * @since 3.4.0
636
953
  * @experimental
637
- * @category constructors
954
+ * @category sequencing
638
955
  */
639
- export const fail = e => fromExit(exitFail(e));
956
+ export const race = /*#__PURE__*/dual(2, (self, that) => raceAll([self, that]));
640
957
  /**
641
- * Creates a `Micro` effect that will fail with the lazily evaluated error.
642
- *
643
- * This will result in a `CauseFail`, where the error is tracked at the
644
- * type level.
958
+ * Returns an effect that races two effects, yielding the value of the first
959
+ * effect to succeed *or* fail. Losers of the race will be interrupted immediately
645
960
  *
646
961
  * @since 3.4.0
647
962
  * @experimental
648
- * @category constructors
963
+ * @category sequencing
649
964
  */
650
- export const failSync = e => make(function (_env, onExit) {
651
- onExit(exitFail(e()));
652
- });
965
+ export const raceFirst = /*#__PURE__*/dual(2, (self, that) => raceAllFirst([self, that]));
653
966
  /**
654
- * Creates a `Micro` effect that will die with the specified error.
655
- *
656
- * This will result in a `CauseDie`, where the error is not tracked at
657
- * the type level.
967
+ * Map the success value of this `Micro` effect to another `Micro` effect, then
968
+ * flatten the result.
658
969
  *
659
970
  * @since 3.4.0
660
971
  * @experimental
661
- * @category constructors
972
+ * @category mapping & sequencing
662
973
  */
663
- export const die = defect => fromExit(exitDie(defect));
664
- /**
665
- * Creates a `Micro` effect that will fail with the specified `MicroCause`.
666
- *
667
- * @since 3.4.6
668
- * @experimental
669
- * @category constructors
670
- */
671
- export const failCause = cause => fromExit(exitFailCause(cause));
672
- /**
673
- * Creates a `Micro` effect that will fail with the lazily evaluated `MicroCause`.
674
- *
675
- * @since 3.4.6
676
- * @experimental
677
- * @category constructors
678
- */
679
- export const failCauseSync = cause => fromExitSync(() => exitFailCause(cause()));
680
- /**
681
- * Creates a `Micro` effect that will succeed with the lazily evaluated value.
682
- *
683
- * If the evaluation of the value throws an error, the effect will fail with
684
- * `CauseDie`.
685
- *
686
- * @since 3.4.0
687
- * @experimental
688
- * @category constructors
689
- */
690
- export const sync = evaluate => make(function (_env, onExit) {
691
- onExit(exitSucceed(evaluate()));
974
+ export const flatMap = /*#__PURE__*/dual(2, (self, f) => {
975
+ const onSuccess = Object.create(OnSuccessProto);
976
+ onSuccess[args] = self;
977
+ onSuccess[successCont] = f;
978
+ return onSuccess;
692
979
  });
693
- /**
694
- * Converts an `Option` into a `Micro` effect, that will fail with
695
- * `NoSuchElementException` if the option is `None`. Otherwise, it will succeed with the
696
- * value of the option.
697
- *
698
- * @since 3.4.0
699
- * @experimental
700
- * @category constructors
701
- */
702
- export const fromOption = option => make(function (_env, onExit) {
703
- onExit(option._tag === "Some" ? exitSucceed(option.value) : exitFail(new NoSuchElementException({})));
980
+ const OnSuccessProto = /*#__PURE__*/makePrimitiveProto({
981
+ op: "OnSuccess",
982
+ eval(fiber) {
983
+ fiber._stack.push(this);
984
+ return this[args];
985
+ }
704
986
  });
987
+ // ----------------------------------------------------------------------------
988
+ // mapping & sequencing
989
+ // ----------------------------------------------------------------------------
705
990
  /**
706
- * Converts an `Either` into a `Micro` effect, that will fail with the left side
707
- * of the either if it is a `Left`. Otherwise, it will succeed with the right
708
- * side of the either.
991
+ * Flattens any nested `Micro` effects, merging the error and requirement types.
709
992
  *
710
993
  * @since 3.4.0
711
994
  * @experimental
712
- * @category constructors
995
+ * @category mapping & sequencing
713
996
  */
714
- export const fromEither = either => make(function (_env, onExit) {
715
- onExit(either._tag === "Right" ? either : exitFail(either.left));
716
- });
997
+ export const flatten = self => flatMap(self, identity);
717
998
  /**
718
- * Lazily creates a `Micro` effect from the given side-effect.
999
+ * Transforms the success value of the `Micro` effect with the specified
1000
+ * function.
719
1001
  *
720
1002
  * @since 3.4.0
721
1003
  * @experimental
722
- * @category constructors
1004
+ * @category mapping & sequencing
723
1005
  */
724
- export const suspend = evaluate => make(function (env, onExit) {
725
- evaluate()[runSymbol](env, onExit);
726
- });
727
- const void_ = /*#__PURE__*/succeed(void 0);
728
- export {
1006
+ export const map = /*#__PURE__*/dual(2, (self, f) => flatMap(self, a => succeed(f(a))));
729
1007
  /**
730
- * A `Micro` effect that will succeed with `void` (`undefined`).
731
- *
732
- * @since 3.4.0
1008
+ * @since 3.4.6
733
1009
  * @experimental
734
- * @category constructors
1010
+ * @category MicroExit
735
1011
  */
736
- void_ as void };
1012
+ export const isMicroExit = u => hasProperty(u, MicroExitTypeId);
737
1013
  /**
738
- * Create a `Micro` effect from an asynchronous computation.
739
- *
740
- * You can return a cleanup effect that will be run when the effect is aborted.
741
- * It is also passed an `AbortSignal` that is triggered when the effect is
742
- * aborted.
743
- *
744
- * @since 3.4.0
1014
+ * @since 3.4.6
745
1015
  * @experimental
746
- * @category constructors
1016
+ * @category MicroExit
747
1017
  */
748
- export const async = register => make(function (env, onExit) {
749
- let resumed = false;
750
- const controller = register.length > 1 ? new AbortController() : undefined;
751
- const signal = envGet(env, currentAbortSignal);
752
- let cleanup = undefined;
753
- function onAbort() {
754
- if (cleanup) {
755
- resume(uninterruptible(andThen(cleanup, fromExit(exitInterrupt))));
756
- } else {
757
- resume(fromExit(exitInterrupt));
758
- }
759
- if (controller !== undefined) {
760
- controller.abort();
761
- }
762
- }
763
- function resume(effect) {
764
- if (resumed) {
765
- return;
766
- }
767
- resumed = true;
768
- signal.removeEventListener("abort", onAbort);
769
- effect[runSymbol](env, onExit);
770
- }
771
- cleanup = controller === undefined ? register(resume) : register(resume, controller.signal);
772
- if (resumed) return;
773
- signal.addEventListener("abort", onAbort);
774
- });
775
- const try_ = options => make(function (_env, onExit) {
776
- try {
777
- onExit(exitSucceed(options.try()));
778
- } catch (err) {
779
- onExit(exitFail(options.catch(err)));
780
- }
781
- });
782
- export {
1018
+ export const exitSucceed = succeed;
783
1019
  /**
784
- * The `Micro` equivalent of a try / catch block, which allows you to map
785
- * thrown errors to a specific error type.
786
- *
787
- * @since 3.4.0
1020
+ * @since 3.4.6
788
1021
  * @experimental
789
- * @category constructors
790
- * @example
791
- * ```ts
792
- * import { Micro } from "effect"
793
- *
794
- * Micro.try({
795
- * try: () => throw new Error("boom"),
796
- * catch: (cause) => new Error("caught", { cause })
797
- * })
798
- * ```
1022
+ * @category MicroExit
799
1023
  */
800
- try_ as try };
1024
+ export const exitFailCause = failCause;
801
1025
  /**
802
- * Wrap a `Promise` into a `Micro` effect. Any errors will result in a
803
- * `CauseDie`.
804
- *
805
- * @since 3.4.0
1026
+ * @since 3.4.6
806
1027
  * @experimental
807
- * @category constructors
1028
+ * @category MicroExit
808
1029
  */
809
- export const promise = evaluate => async(function (resume, signal) {
810
- evaluate(signal).then(a => resume(succeed(a)), e => resume(die(e)));
811
- });
1030
+ export const exitInterrupt = /*#__PURE__*/exitFailCause( /*#__PURE__*/causeInterrupt());
812
1031
  /**
813
- * Wrap a `Promise` into a `Micro` effect. Any errors will be caught and
814
- * converted into a specific error type.
815
- *
816
- * @since 3.4.0
1032
+ * @since 3.4.6
817
1033
  * @experimental
818
- * @category constructors
819
- * @example
820
- * ```ts
821
- * import { Micro } from "effect"
822
- *
823
- * Micro.tryPromise({
824
- * try: () => Promise.resolve("success"),
825
- * catch: (cause) => new Error("caught", { cause })
826
- * })
827
- * ```
1034
+ * @category MicroExit
828
1035
  */
829
- export const tryPromise = options => async(function (resume, signal) {
830
- try {
831
- options.try(signal).then(a => resume(succeed(a)), e => resume(fail(options.catch(e))));
832
- } catch (err) {
833
- resume(fail(options.catch(err)));
834
- }
835
- });
1036
+ export const exitFail = e => exitFailCause(causeFail(e));
836
1037
  /**
837
- * Pause the execution of the current `Micro` effect, and resume it on the next
838
- * iteration of the event loop.
839
- *
840
- * You can specify a priority for the task, which will determine when it is
841
- * executed relative to other tasks.
842
- *
843
- * @since 3.4.0
1038
+ * @since 3.4.6
844
1039
  * @experimental
845
- * @category constructors
1040
+ * @category MicroExit
846
1041
  */
847
- export const yieldWithPriority = priority => make(function (env, onExit) {
848
- envGet(env, currentScheduler).scheduleTask(() => onExit(exitVoid), priority);
849
- });
1042
+ export const exitDie = defect => exitFailCause(causeDie(defect));
850
1043
  /**
851
- * Pause the execution of the current `Micro` effect, and resume it on the next
852
- * iteration of the event loop.
853
- *
854
- * @since 3.4.0
1044
+ * @since 3.4.6
855
1045
  * @experimental
856
- * @category constructors
1046
+ * @category MicroExit
857
1047
  */
858
- export const yieldNow = /*#__PURE__*/yieldWithPriority(0);
1048
+ export const exitIsSuccess = self => self._tag === "Success";
859
1049
  /**
860
- * Flush any yielded effects that are waiting to be executed.
861
- *
862
- * @since 3.4.0
1050
+ * @since 3.4.6
863
1051
  * @experimental
864
- * @category constructors
1052
+ * @category MicroExit
865
1053
  */
866
- export const yieldFlush = /*#__PURE__*/make(function (env, onExit) {
867
- envGet(env, currentScheduler).flush();
868
- onExit(exitVoid);
869
- });
1054
+ export const exitIsFailure = self => self._tag === "Failure";
870
1055
  /**
871
- * A `Micro` that will never succeed or fail. It wraps `setInterval` to prevent
872
- * the Javascript runtime from exiting.
873
- *
874
- * @since 3.4.0
1056
+ * @since 3.4.6
875
1057
  * @experimental
876
- * @category constructors
1058
+ * @category MicroExit
877
1059
  */
878
- export const never = /*#__PURE__*/async(function () {
879
- const interval = setInterval(constVoid, 2147483646);
880
- return sync(() => clearInterval(interval));
881
- });
1060
+ export const exitIsInterrupt = self => exitIsFailure(self) && self.cause._tag === "Interrupt";
882
1061
  /**
883
- * @since 3.4.0
1062
+ * @since 3.4.6
884
1063
  * @experimental
885
- * @category constructors
1064
+ * @category MicroExit
886
1065
  */
887
- export const gen = (...args) => make(function (env, onExit) {
888
- const iterator = args.length === 1 ? args[0]() : args[1].call(args[0]);
889
- let running = false;
890
- let value = undefined;
891
- function run() {
892
- running = true;
893
- try {
894
- let shouldContinue = true;
895
- while (shouldContinue) {
896
- const result = iterator.next(value);
897
- if (result.done) {
898
- return onExit(exitSucceed(result.value));
899
- }
900
- shouldContinue = false;
901
- yieldWrapGet(result.value)[runSymbol](env, function (exit) {
902
- if (exit._tag === "Left") {
903
- onExit(exit);
904
- } else {
905
- shouldContinue = true;
906
- value = exit.right;
907
- if (!running) run();
908
- }
909
- });
910
- }
911
- } catch (err) {
912
- onExit(exitDie(err));
913
- }
914
- running = false;
915
- }
916
- run();
917
- });
918
- // ----------------------------------------------------------------------------
919
- // mapping & sequencing
920
- // ----------------------------------------------------------------------------
1066
+ export const exitIsFail = self => exitIsFailure(self) && self.cause._tag === "Fail";
921
1067
  /**
922
- * Flattens any nested `Micro` effects, merging the error and requirement types.
923
- *
924
- * @since 3.4.0
1068
+ * @since 3.4.6
925
1069
  * @experimental
926
- * @category mapping & sequencing
1070
+ * @category MicroExit
927
1071
  */
928
- export const flatten = self => make(function (env, onExit) {
929
- self[runSymbol](env, exit => exit._tag === "Left" ? onExit(exit) : exit.right[runSymbol](env, onExit));
930
- });
1072
+ export const exitIsDie = self => exitIsFailure(self) && self.cause._tag === "Die";
931
1073
  /**
932
- * Transforms the success value of the `Micro` effect with the specified
933
- * function.
934
- *
935
- * @since 3.4.0
1074
+ * @since 3.4.6
936
1075
  * @experimental
937
- * @category mapping & sequencing
1076
+ * @category MicroExit
938
1077
  */
939
- export const map = /*#__PURE__*/dual(2, (self, f) => make(function (env, onExit) {
940
- self[runSymbol](env, function (exit) {
941
- onExit(exit._tag === "Left" ? exit : exitSucceed(f(exit.right)));
942
- });
943
- }));
1078
+ export const exitVoid = /*#__PURE__*/exitSucceed(void 0);
944
1079
  /**
945
- * Create a `Micro` effect that will replace the success value of the given
946
- * effect.
947
- *
948
- * @since 3.4.0
1080
+ * @since 3.11.0
949
1081
  * @experimental
950
- * @category mapping & sequencing
1082
+ * @category MicroExit
951
1083
  */
952
- export const as = /*#__PURE__*/dual(2, (self, value) => map(self, _ => value));
1084
+ export const exitVoidAll = exits => {
1085
+ for (const exit of exits) {
1086
+ if (exit._tag === "Failure") {
1087
+ return exit;
1088
+ }
1089
+ }
1090
+ return exitVoid;
1091
+ };
1092
+ const setImmediate = "setImmediate" in globalThis ? globalThis.setImmediate : f => setTimeout(f, 0);
953
1093
  /**
954
- * Wrap the success value of this `Micro` effect in an `Option.Some`.
955
- *
956
- * @since 3.4.0
1094
+ * @since 3.5.9
957
1095
  * @experimental
958
- * @category mapping & sequencing
1096
+ * @category scheduler
959
1097
  */
960
- export const asSome = self => map(self, Option.some);
1098
+ export class MicroSchedulerDefault {
1099
+ tasks = [];
1100
+ running = false;
1101
+ /**
1102
+ * @since 3.5.9
1103
+ */
1104
+ scheduleTask(task, _priority) {
1105
+ this.tasks.push(task);
1106
+ if (!this.running) {
1107
+ this.running = true;
1108
+ setImmediate(this.afterScheduled);
1109
+ }
1110
+ }
1111
+ /**
1112
+ * @since 3.5.9
1113
+ */
1114
+ afterScheduled = () => {
1115
+ this.running = false;
1116
+ this.runTasks();
1117
+ };
1118
+ /**
1119
+ * @since 3.5.9
1120
+ */
1121
+ runTasks() {
1122
+ const tasks = this.tasks;
1123
+ this.tasks = [];
1124
+ for (let i = 0, len = tasks.length; i < len; i++) {
1125
+ tasks[i]();
1126
+ }
1127
+ }
1128
+ /**
1129
+ * @since 3.5.9
1130
+ */
1131
+ shouldYield(fiber) {
1132
+ return fiber.currentOpCount >= fiber.getRef(MaxOpsBeforeYield);
1133
+ }
1134
+ /**
1135
+ * @since 3.5.9
1136
+ */
1137
+ flush() {
1138
+ while (this.tasks.length > 0) {
1139
+ this.runTasks();
1140
+ }
1141
+ }
1142
+ }
961
1143
  /**
962
- * Map the success value of this `Micro` effect to another `Micro` effect, then
963
- * flatten the result.
1144
+ * Access the given `Context.Tag` from the environment.
964
1145
  *
965
1146
  * @since 3.4.0
966
1147
  * @experimental
967
- * @category mapping & sequencing
1148
+ * @category environment
968
1149
  */
969
- export const flatMap = /*#__PURE__*/dual(2, (self, f) => make(function (env, onExit) {
970
- self[runSymbol](env, function (exit) {
971
- if (exit._tag === "Left") {
972
- return onExit(exit);
973
- }
974
- f(exit.right)[runSymbol](env, onExit);
975
- });
976
- }));
1150
+ export const service = tag => withFiber(fiber => succeed(Context.unsafeGet(fiber.context, tag)));
977
1151
  /**
978
- * Swap the error and success types of the `Micro` effect.
1152
+ * Access the given `Context.Tag` from the environment, without tracking the
1153
+ * dependency at the type level.
1154
+ *
1155
+ * It will return an `Option` of the service, depending on whether it is
1156
+ * available in the environment or not.
979
1157
  *
980
1158
  * @since 3.4.0
981
1159
  * @experimental
982
- * @category mapping & sequencing
1160
+ * @category environment
983
1161
  */
984
- export const flip = self => matchEffect(self, {
985
- onFailure: succeed,
986
- onSuccess: fail
987
- });
1162
+ export const serviceOption = tag => withFiber(fiber => succeed(Context.getOption(fiber.context, tag)));
988
1163
  /**
989
- * A more flexible version of `flatMap`, that combines `map` and `flatMap` into
990
- * a single api.
991
- *
992
- * It also allows you to pass in a `Micro` effect directly, which will be
993
- * executed after the current effect.
1164
+ * Update the Context with the given mapping function.
994
1165
  *
995
- * @since 3.4.0
1166
+ * @since 3.11.0
996
1167
  * @experimental
997
- * @category mapping & sequencing
1168
+ * @category environment
998
1169
  */
999
- export const andThen = /*#__PURE__*/dual(2, (self, f) => make(function (env, onExit) {
1000
- self[runSymbol](env, function (exit) {
1001
- if (exit._tag === "Left") {
1002
- return onExit(exit);
1003
- } else if (envGet(env, currentAbortSignal).aborted) {
1004
- return onExit(exitInterrupt);
1005
- }
1006
- const value = isMicro(f) ? f : typeof f === "function" ? f(exit.right) : f;
1007
- if (isMicro(value)) {
1008
- value[runSymbol](env, onExit);
1009
- } else {
1010
- onExit(exitSucceed(value));
1011
- }
1170
+ export const updateContext = /*#__PURE__*/dual(2, (self, f) => withFiber(fiber => {
1171
+ const prev = fiber.context;
1172
+ fiber.context = f(prev);
1173
+ return onExit(self, () => {
1174
+ fiber.context = prev;
1175
+ return void_;
1012
1176
  });
1013
1177
  }));
1014
1178
  /**
1015
- * Execute a side effect from the success value of the `Micro` effect.
1179
+ * Update the service for the given `Context.Tag` in the environment.
1016
1180
  *
1017
- * It is similar to the `andThen` api, but the success value is ignored.
1018
- *
1019
- * @since 3.4.0
1181
+ * @since 3.11.0
1020
1182
  * @experimental
1021
- * @category mapping & sequencing
1183
+ * @category environment
1022
1184
  */
1023
- export const tap = /*#__PURE__*/dual(2, (self, f) => make(function (env, onExit) {
1024
- self[runSymbol](env, function (selfExit) {
1025
- if (selfExit._tag === "Left") {
1026
- return onExit(selfExit);
1027
- } else if (envGet(env, currentAbortSignal).aborted) {
1028
- return onExit(exitInterrupt);
1029
- }
1030
- const value = isMicro(f) ? f : typeof f === "function" ? f(selfExit.right) : f;
1031
- if (isMicro(value)) {
1032
- value[runSymbol](env, function (tapExit) {
1033
- if (tapExit._tag === "Left") {
1034
- return onExit(tapExit);
1035
- }
1036
- onExit(selfExit);
1037
- });
1038
- } else {
1039
- onExit(selfExit);
1040
- }
1185
+ export const updateService = /*#__PURE__*/dual(3, (self, tag, f) => withFiber(fiber => {
1186
+ const prev = Context.unsafeGet(fiber.context, tag);
1187
+ fiber.context = Context.add(fiber.context, tag, f(prev));
1188
+ return onExit(self, () => {
1189
+ fiber.context = Context.add(fiber.context, tag, prev);
1190
+ return void_;
1041
1191
  });
1042
1192
  }));
1043
1193
  /**
1044
- * Replace the success value of the `Micro` effect with `void`.
1194
+ * Access the current `Context` from the environment.
1045
1195
  *
1046
1196
  * @since 3.4.0
1047
1197
  * @experimental
1048
- * @category mapping & sequencing
1198
+ * @category environment
1049
1199
  */
1050
- export const asVoid = self => map(self, _ => void 0);
1200
+ export const context = () => getContext;
1201
+ const getContext = /*#__PURE__*/withFiber(fiber => succeed(fiber.context));
1051
1202
  /**
1052
- * Access the `MicroExit` of the given `Micro` effect.
1203
+ * Merge the given `Context` with the current context.
1053
1204
  *
1054
- * @since 3.4.6
1205
+ * @since 3.4.0
1055
1206
  * @experimental
1056
- * @category mapping & sequencing
1207
+ * @category environment
1057
1208
  */
1058
- export const exit = self => make(function (env, onExit) {
1059
- self[runSymbol](env, function (exit) {
1060
- onExit(exitSucceed(exit));
1061
- });
1062
- });
1209
+ export const provideContext = /*#__PURE__*/dual(2, (self, provided) => updateContext(self, Context.merge(provided)));
1063
1210
  /**
1064
- * Replace the error type of the given `Micro` with the full `MicroCause` object.
1211
+ * Add the provided service to the current context.
1065
1212
  *
1066
1213
  * @since 3.4.0
1067
1214
  * @experimental
1068
- * @category mapping & sequencing
1215
+ * @category environment
1069
1216
  */
1070
- export const sandbox = self => catchAllCause(self, cause => fail(cause));
1071
- function forkSignal(env) {
1072
- const controller = new AbortController();
1073
- const parentSignal = envGet(env, currentAbortSignal);
1074
- function onAbort() {
1075
- controller.abort();
1076
- parentSignal.removeEventListener("abort", onAbort);
1077
- }
1078
- parentSignal.addEventListener("abort", onAbort);
1079
- const envWithSignal = envMutate(env, function (refs) {
1080
- refs[currentAbortController.key] = controller;
1081
- refs[currentAbortSignal.key] = controller.signal;
1082
- return refs;
1083
- });
1084
- return [envWithSignal, onAbort];
1085
- }
1217
+ export const provideService = /*#__PURE__*/dual(3, (self, tag, service) => updateContext(self, Context.add(tag, service)));
1086
1218
  /**
1087
- * Returns an effect that races all the specified effects,
1088
- * yielding the value of the first effect to succeed with a value. Losers of
1089
- * the race will be interrupted immediately
1219
+ * Create a service using the provided `Micro` effect, and add it to the
1220
+ * current context.
1090
1221
  *
1091
- * @since 3.4.0
1222
+ * @since 3.4.6
1092
1223
  * @experimental
1093
- * @category sequencing
1224
+ * @category environment
1094
1225
  */
1095
- export const raceAll = all => make(function (env, onExit) {
1096
- const [envWithSignal, onAbort] = forkSignal(env);
1097
- const effects = Array.from(all);
1098
- let len = effects.length;
1099
- let index = 0;
1100
- let done = 0;
1101
- let exit = undefined;
1102
- const causes = [];
1103
- function onDone(exit_) {
1104
- done++;
1105
- if (exit_._tag === "Right" && exit === undefined) {
1106
- len = index;
1107
- exit = exit_;
1108
- onAbort();
1109
- } else if (exit_._tag === "Left") {
1110
- causes.push(exit_.left);
1111
- }
1112
- if (done >= len) {
1113
- onExit(exit ?? Either.left(causes[0]));
1114
- }
1115
- }
1116
- for (; index < len; index++) {
1117
- effects[index][runSymbol](envWithSignal, onDone);
1118
- }
1119
- });
1226
+ export const provideServiceEffect = /*#__PURE__*/dual(3, (self, tag, acquire) => flatMap(acquire, service => provideService(self, tag, service)));
1227
+ // ========================================================================
1228
+ // References
1229
+ // ========================================================================
1120
1230
  /**
1121
- * Returns an effect that races all the specified effects,
1122
- * yielding the value of the first effect to succeed or fail. Losers of
1123
- * the race will be interrupted immediately
1124
- *
1125
- * @since 3.4.0
1231
+ * @since 3.11.0
1126
1232
  * @experimental
1127
- * @category sequencing
1233
+ * @category references
1128
1234
  */
1129
- export const raceAllFirst = all => make(function (env, onExit) {
1130
- const [envWithSignal, onAbort] = forkSignal(env);
1131
- const effects = Array.from(all);
1132
- let len = effects.length;
1133
- let index = 0;
1134
- let done = 0;
1135
- let exit = undefined;
1136
- const causes = [];
1137
- function onDone(exit_) {
1138
- done++;
1139
- if (exit === undefined) {
1140
- len = index;
1141
- exit = exit_;
1142
- onAbort();
1143
- }
1144
- if (done >= len) {
1145
- onExit(exit ?? Either.left(causes[0]));
1146
- }
1147
- }
1148
- for (; index < len; index++) {
1149
- effects[index][runSymbol](envWithSignal, onDone);
1150
- }
1151
- });
1235
+ export class MaxOpsBeforeYield extends /*#__PURE__*/Context.Reference()("effect/Micro/currentMaxOpsBeforeYield", {
1236
+ defaultValue: () => 2048
1237
+ }) {}
1152
1238
  /**
1153
- * Returns an effect that races two effects, yielding the value of the first
1154
- * effect to succeed. Losers of the race will be interrupted immediately
1155
- *
1156
- * @since 3.4.0
1239
+ * @since 3.11.0
1157
1240
  * @experimental
1158
- * @category sequencing
1241
+ * @category environment refs
1159
1242
  */
1160
- export const race = /*#__PURE__*/dual(2, (self, that) => raceAll([self, that]));
1243
+ export class CurrentConcurrency extends /*#__PURE__*/Context.Reference()("effect/Micro/currentConcurrency", {
1244
+ defaultValue: () => "unbounded"
1245
+ }) {}
1161
1246
  /**
1162
- * Returns an effect that races two effects, yielding the value of the first
1163
- * effect to succeed *or* fail. Losers of the race will be interrupted immediately
1247
+ * @since 3.11.0
1248
+ * @experimental
1249
+ * @category environment refs
1250
+ */
1251
+ export class CurrentScheduler extends /*#__PURE__*/Context.Reference()("effect/Micro/currentScheduler", {
1252
+ defaultValue: () => new MicroSchedulerDefault()
1253
+ }) {}
1254
+ /**
1255
+ * If you have a `Micro` that uses `concurrency: "inherit"`, you can use this
1256
+ * api to control the concurrency of that `Micro` when it is run.
1164
1257
  *
1165
1258
  * @since 3.4.0
1166
1259
  * @experimental
1167
- * @category sequencing
1260
+ * @category environment refs
1261
+ * @example
1262
+ * import * as Micro from "effect/Micro"
1263
+ *
1264
+ * Micro.forEach([1, 2, 3], (n) => Micro.succeed(n), {
1265
+ * concurrency: "inherit"
1266
+ * }).pipe(
1267
+ * Micro.withConcurrency(2) // use a concurrency of 2
1268
+ * )
1168
1269
  */
1169
- export const raceFirst = /*#__PURE__*/dual(2, (self, that) => raceAllFirst([self, that]));
1270
+ export const withConcurrency = /*#__PURE__*/dual(2, (self, concurrency) => provideService(self, CurrentConcurrency, concurrency));
1170
1271
  // ----------------------------------------------------------------------------
1171
1272
  // zipping
1172
1273
  // ----------------------------------------------------------------------------
@@ -1188,15 +1289,11 @@ export const zip = /*#__PURE__*/dual(args => isMicro(args[1]), (self, that, opti
1188
1289
  * @experimental
1189
1290
  * @category zipping
1190
1291
  */
1191
- export const zipWith = /*#__PURE__*/dual(args => isMicro(args[1]), (self, that, f, options) => {
1192
- if (options?.concurrent) {
1193
- // Use `all` exclusively for concurrent cases, as it introduces additional overhead due to the management of concurrency
1194
- return map(all([self, that], {
1195
- concurrency: "unbounded"
1196
- }), ([a, a2]) => f(a, a2));
1197
- }
1198
- return flatMap(self, a => map(that, a2 => f(a, a2)));
1199
- });
1292
+ export const zipWith = /*#__PURE__*/dual(args => isMicro(args[1]), (self, that, f, options) => options?.concurrent
1293
+ // Use `all` exclusively for concurrent cases, as it introduces additional overhead due to the management of concurrency
1294
+ ? map(all([self, that], {
1295
+ concurrency: 2
1296
+ }), ([a, a2]) => f(a, a2)) : flatMap(self, a => map(that, a2 => f(a, a2))));
1200
1297
  // ----------------------------------------------------------------------------
1201
1298
  // filtering & conditionals
1202
1299
  // ----------------------------------------------------------------------------
@@ -1231,7 +1328,7 @@ export const filterOrFail = /*#__PURE__*/dual(args => isMicro(args[0]), (self, r
1231
1328
  * @experimental
1232
1329
  * @category filtering & conditionals
1233
1330
  */
1234
- export const when = /*#__PURE__*/dual(2, (self, condition) => flatMap(isMicro(condition) ? condition : sync(condition), pass => pass ? asSome(self) : succeed(Option.none())));
1331
+ export const when = /*#__PURE__*/dual(2, (self, condition) => flatMap(isMicro(condition) ? condition : sync(condition), pass => pass ? asSome(self) : succeedNone));
1235
1332
  // ----------------------------------------------------------------------------
1236
1333
  // repetition
1237
1334
  // ----------------------------------------------------------------------------
@@ -1245,14 +1342,14 @@ export const when = /*#__PURE__*/dual(2, (self, condition) => flatMap(isMicro(co
1245
1342
  * @experimental
1246
1343
  * @category repetition
1247
1344
  */
1248
- export const repeatExit = /*#__PURE__*/dual(2, (self, options) => make(function (env, onExit) {
1345
+ export const repeatExit = /*#__PURE__*/dual(2, (self, options) => suspend(() => {
1249
1346
  const startedAt = options.schedule ? Date.now() : 0;
1250
1347
  let attempt = 0;
1251
- self[runSymbol](env, function loop(exit) {
1348
+ const loop = flatMap(exit(self), exit => {
1252
1349
  if (options.while !== undefined && !options.while(exit)) {
1253
- return onExit(exit);
1350
+ return exit;
1254
1351
  } else if (options.times !== undefined && attempt >= options.times) {
1255
- return onExit(exit);
1352
+ return exit;
1256
1353
  }
1257
1354
  attempt++;
1258
1355
  let delayEffect = yieldNow;
@@ -1260,17 +1357,13 @@ export const repeatExit = /*#__PURE__*/dual(2, (self, options) => make(function
1260
1357
  const elapsed = Date.now() - startedAt;
1261
1358
  const duration = options.schedule(attempt, elapsed);
1262
1359
  if (Option.isNone(duration)) {
1263
- return onExit(exit);
1360
+ return exit;
1264
1361
  }
1265
1362
  delayEffect = sleep(duration.value);
1266
1363
  }
1267
- delayEffect[runSymbol](env, function (exit) {
1268
- if (exit._tag === "Left") {
1269
- return onExit(exit);
1270
- }
1271
- self[runSymbol](env, loop);
1272
- });
1364
+ return flatMap(delayEffect, () => loop);
1273
1365
  });
1366
+ return loop;
1274
1367
  }));
1275
1368
  /**
1276
1369
  * Repeat the given `Micro` effect using the provided options. Only successful
@@ -1282,8 +1375,26 @@ export const repeatExit = /*#__PURE__*/dual(2, (self, options) => make(function
1282
1375
  */
1283
1376
  export const repeat = /*#__PURE__*/dual(args => isMicro(args[0]), (self, options) => repeatExit(self, {
1284
1377
  ...options,
1285
- while: exit => exit._tag === "Right" && (options?.while === undefined || options.while(exit.right))
1378
+ while: exit => exit._tag === "Success" && (options?.while === undefined || options.while(exit.value))
1286
1379
  }));
1380
+ /**
1381
+ * Replicates the given effect `n` times.
1382
+ *
1383
+ * @since 3.11.0
1384
+ * @experimental
1385
+ * @category repetition
1386
+ */
1387
+ export const replicate = /*#__PURE__*/dual(2, (self, n) => Array.from({
1388
+ length: n
1389
+ }, () => self));
1390
+ /**
1391
+ * Performs this effect the specified number of times and collects the
1392
+ * results.
1393
+ *
1394
+ * @since 3.11.0
1395
+ * @category repetition
1396
+ */
1397
+ export const replicateEffect = /*#__PURE__*/dual(args => isMicro(args[0]), (self, n, options) => all(replicate(self, n), options));
1287
1398
  /**
1288
1399
  * Repeat the given `Micro` effect forever, only stopping if the effect fails.
1289
1400
  *
@@ -1373,7 +1484,19 @@ export const scheduleIntersect = /*#__PURE__*/dual(2, (self, that) => (attempt,
1373
1484
  * @experimental
1374
1485
  * @category error handling
1375
1486
  */
1376
- export const catchAllCause = /*#__PURE__*/dual(2, (self, f) => catchCauseIf(self, constTrue, f));
1487
+ export const catchAllCause = /*#__PURE__*/dual(2, (self, f) => {
1488
+ const onFailure = Object.create(OnFailureProto);
1489
+ onFailure[args] = self;
1490
+ onFailure[failureCont] = f;
1491
+ return onFailure;
1492
+ });
1493
+ const OnFailureProto = /*#__PURE__*/makePrimitiveProto({
1494
+ op: "OnFailure",
1495
+ eval(fiber) {
1496
+ fiber._stack.push(this);
1497
+ return this[args];
1498
+ }
1499
+ });
1377
1500
  /**
1378
1501
  * Selectively catch a `MicroCause` object of the given `Micro` effect,
1379
1502
  * using the provided predicate to determine if the failure should be caught.
@@ -1382,15 +1505,7 @@ export const catchAllCause = /*#__PURE__*/dual(2, (self, f) => catchCauseIf(self
1382
1505
  * @experimental
1383
1506
  * @category error handling
1384
1507
  */
1385
- export const catchCauseIf = /*#__PURE__*/dual(3, (self, predicate, f) => make(function (env, onExit) {
1386
- self[runSymbol](env, function (exit) {
1387
- if (exit._tag === "Right" || !predicate(exit.left)) {
1388
- onExit(exit);
1389
- } else {
1390
- f(exit.left)[runSymbol](env, onExit);
1391
- }
1392
- });
1393
- }));
1508
+ export const catchCauseIf = /*#__PURE__*/dual(3, (self, predicate, f) => catchAllCause(self, cause => predicate(cause) ? f(cause) : failCause(cause)));
1394
1509
  /**
1395
1510
  * Catch the error of the given `Micro` effect, allowing you to recover from it.
1396
1511
  *
@@ -1400,7 +1515,7 @@ export const catchCauseIf = /*#__PURE__*/dual(3, (self, predicate, f) => make(fu
1400
1515
  * @experimental
1401
1516
  * @category error handling
1402
1517
  */
1403
- export const catchAll = /*#__PURE__*/dual(2, (self, f) => catchAllCause(self, cause => causeIsFail(cause) ? f(cause.error) : failCause(cause)));
1518
+ export const catchAll = /*#__PURE__*/dual(2, (self, f) => catchCauseIf(self, causeIsFail, cause => f(cause.error)));
1404
1519
  /**
1405
1520
  * Catch any unexpected errors of the given `Micro` effect, allowing you to recover from them.
1406
1521
  *
@@ -1524,7 +1639,7 @@ export const ignoreLogged = self => matchEffect(self, {
1524
1639
  * @category error handling
1525
1640
  */
1526
1641
  export const option = self => match(self, {
1527
- onFailure: _ => Option.none(),
1642
+ onFailure: Option.none,
1528
1643
  onSuccess: Option.some
1529
1644
  });
1530
1645
  /**
@@ -1549,7 +1664,7 @@ export const either = self => match(self, {
1549
1664
  */
1550
1665
  export const retry = /*#__PURE__*/dual(args => isMicro(args[0]), (self, options) => repeatExit(self, {
1551
1666
  ...options,
1552
- while: exit => exit._tag === "Left" && exit.left._tag === "Fail" && (options?.while === undefined || options.while(exit.left.error))
1667
+ while: exit => exit._tag === "Failure" && exit.cause._tag === "Fail" && (options?.while === undefined || options.while(exit.cause.error))
1553
1668
  }));
1554
1669
  /**
1555
1670
  * Add a stack trace to any failures that occur in the effect. The trace will be
@@ -1576,11 +1691,7 @@ export const withTrace = function () {
1576
1691
  const lineMatch = line.match(/\((.*)\)$/);
1577
1692
  return causeWithTrace(cause, `at ${name} (${lineMatch ? lineMatch[1] : line})`);
1578
1693
  }
1579
- const f = name => self => unsafeMakeOptions(function (env, onExit) {
1580
- self[runSymbol](env, function (exit) {
1581
- onExit(exit._tag === "Left" ? Either.left(generate(name, exit.left)) : exit);
1582
- });
1583
- }, false);
1694
+ const f = name => self => onError(self, cause => failCause(generate(name, cause)));
1584
1695
  if (arguments.length === 2) {
1585
1696
  return f(arguments[1])(arguments[0]);
1586
1697
  }
@@ -1594,16 +1705,20 @@ export const withTrace = function () {
1594
1705
  * @experimental
1595
1706
  * @category pattern matching
1596
1707
  */
1597
- export const matchCauseEffect = /*#__PURE__*/dual(2, (self, options) => make(function (env, onExit) {
1598
- self[runSymbol](env, function (exit) {
1599
- try {
1600
- const next = exit._tag === "Left" ? options.onFailure(exit.left) : options.onSuccess(exit.right);
1601
- next[runSymbol](env, onExit);
1602
- } catch (err) {
1603
- onExit(exitDie(err));
1604
- }
1605
- });
1606
- }));
1708
+ export const matchCauseEffect = /*#__PURE__*/dual(2, (self, options) => {
1709
+ const primitive = Object.create(OnSuccessAndFailureProto);
1710
+ primitive[args] = self;
1711
+ primitive[successCont] = options.onSuccess;
1712
+ primitive[failureCont] = options.onFailure;
1713
+ return primitive;
1714
+ });
1715
+ const OnSuccessAndFailureProto = /*#__PURE__*/makePrimitiveProto({
1716
+ op: "OnSuccessAndFailure",
1717
+ eval(fiber) {
1718
+ fiber._stack.push(this);
1719
+ return this[args];
1720
+ }
1721
+ });
1607
1722
  /**
1608
1723
  * @since 3.4.6
1609
1724
  * @experimental
@@ -1641,12 +1756,12 @@ export const match = /*#__PURE__*/dual(2, (self, options) => matchEffect(self, {
1641
1756
  * @experimental
1642
1757
  * @category delays & timeouts
1643
1758
  */
1644
- export const sleep = millis => async(function (resume) {
1645
- const timeout = setTimeout(function () {
1759
+ export const sleep = millis => async(resume => {
1760
+ const timeout = setTimeout(() => {
1646
1761
  resume(void_);
1647
1762
  }, millis);
1648
1763
  return sync(() => {
1649
- return clearTimeout(timeout);
1764
+ clearTimeout(timeout);
1650
1765
  });
1651
1766
  });
1652
1767
  /**
@@ -1747,7 +1862,7 @@ class MicroScopeImpl {
1747
1862
  _tag: "Closed",
1748
1863
  exit: microExit
1749
1864
  };
1750
- return flatMap(forEach(finalizers, finalizer => exit(finalizer(microExit))), exits => asVoid(fromExit(Either.all(exits))));
1865
+ return flatMap(forEach(finalizers, finalizer => exit(finalizer(microExit))), exitVoidAll);
1751
1866
  }
1752
1867
  return void_;
1753
1868
  });
@@ -1804,7 +1919,7 @@ export const provideScope = /*#__PURE__*/dual(2, (self, scope) => provideService
1804
1919
  * @experimental
1805
1920
  * @category resources & finalization
1806
1921
  */
1807
- export const scoped = self => suspend(function () {
1922
+ export const scoped = self => suspend(() => {
1808
1923
  const scope = new MicroScopeImpl();
1809
1924
  return onExit(provideService(self, MicroScope, scope), exit => scope.close(exit));
1810
1925
  });
@@ -1833,36 +1948,27 @@ export const addFinalizer = finalizer => flatMap(scope, scope => scope.addFinali
1833
1948
  * @experimental
1834
1949
  * @category resources & finalization
1835
1950
  */
1836
- export const onExit = /*#__PURE__*/dual(2, (self, f) => onExitIf(self, constTrue, f));
1951
+ export const onExit = /*#__PURE__*/dual(2, (self, f) => uninterruptibleMask(restore => matchCauseEffect(restore(self), {
1952
+ onFailure: cause => flatMap(f(exitFailCause(cause)), () => failCause(cause)),
1953
+ onSuccess: a => flatMap(f(exitSucceed(a)), () => succeed(a))
1954
+ })));
1837
1955
  /**
1838
- * When the `Micro` effect is completed, run the given finalizer effect if it
1839
- * matches the specified predicate.
1956
+ * Regardless of the result of the this `Micro` effect, run the finalizer effect.
1840
1957
  *
1841
- * @since 3.4.6
1958
+ * @since 3.4.0
1842
1959
  * @experimental
1843
1960
  * @category resources & finalization
1844
1961
  */
1845
- export const onExitIf = /*#__PURE__*/dual(3, (self, refinement, f) => uninterruptibleMask(restore => make(function (env, onExit) {
1846
- restore(self)[runSymbol](env, function (exit) {
1847
- if (!refinement(exit)) {
1848
- return onExit(exit);
1849
- }
1850
- f(exit)[runSymbol](env, function (finalizerExit) {
1851
- if (finalizerExit._tag === "Left") {
1852
- return onExit(finalizerExit);
1853
- }
1854
- onExit(exit);
1855
- });
1856
- });
1857
- })));
1962
+ export const ensuring = /*#__PURE__*/dual(2, (self, finalizer) => onExit(self, _ => finalizer));
1858
1963
  /**
1859
- * Regardless of the result of the this `Micro` effect, run the finalizer effect.
1964
+ * When the `Micro` effect is completed, run the given finalizer effect if it
1965
+ * matches the specified predicate.
1860
1966
  *
1861
- * @since 3.4.0
1967
+ * @since 3.4.6
1862
1968
  * @experimental
1863
1969
  * @category resources & finalization
1864
1970
  */
1865
- export const ensuring = /*#__PURE__*/dual(2, (self, finalizer) => onExit(self, _ => finalizer));
1971
+ export const onExitIf = /*#__PURE__*/dual(3, (self, refinement, f) => onExit(self, exit => refinement(exit) ? f(exit) : exitVoid));
1866
1972
  /**
1867
1973
  * When the `Micro` effect fails, run the given finalizer effect with the
1868
1974
  * `MicroCause` of the executed effect.
@@ -1871,7 +1977,7 @@ export const ensuring = /*#__PURE__*/dual(2, (self, finalizer) => onExit(self, _
1871
1977
  * @experimental
1872
1978
  * @category resources & finalization
1873
1979
  */
1874
- export const onError = /*#__PURE__*/dual(2, (self, f) => onExitIf(self, exitIsFailure, exit => f(exit.left)));
1980
+ export const onError = /*#__PURE__*/dual(2, (self, f) => onExitIf(self, exitIsFailure, exit => f(exit.cause)));
1875
1981
  /**
1876
1982
  * If this `Micro` effect is aborted, run the finalizer effect.
1877
1983
  *
@@ -1888,7 +1994,7 @@ export const onInterrupt = /*#__PURE__*/dual(2, (self, finalizer) => onExitIf(se
1888
1994
  * @experimental
1889
1995
  * @category resources & finalization
1890
1996
  */
1891
- export const acquireUseRelease = (acquire, use, release) => uninterruptibleMask(restore => flatMap(acquire, a => flatMap(exit(restore(use(a))), exit => andThen(release(a, exit), fromExit(exit)))));
1997
+ export const acquireUseRelease = (acquire, use, release) => uninterruptibleMask(restore => flatMap(acquire, a => flatMap(exit(restore(use(a))), exit => andThen(release(a, exit), exit))));
1892
1998
  // ----------------------------------------------------------------------------
1893
1999
  // interruption
1894
2000
  // ----------------------------------------------------------------------------
@@ -1899,27 +2005,45 @@ export const acquireUseRelease = (acquire, use, release) => uninterruptibleMask(
1899
2005
  * @experimental
1900
2006
  * @category interruption
1901
2007
  */
1902
- export const interrupt = /*#__PURE__*/make(function (env, onExit) {
1903
- const controller = envGet(env, currentAbortController);
1904
- controller.abort();
1905
- onExit(exitInterrupt);
2008
+ export const interrupt = /*#__PURE__*/failCause( /*#__PURE__*/causeInterrupt());
2009
+ /**
2010
+ * Flag the effect as uninterruptible, which means that when the effect is
2011
+ * interrupted, it will be allowed to continue running until completion.
2012
+ *
2013
+ * @since 3.4.0
2014
+ * @experimental
2015
+ * @category flags
2016
+ */
2017
+ export const uninterruptible = self => withFiber(fiber => {
2018
+ if (!fiber.interruptible) return self;
2019
+ fiber.interruptible = false;
2020
+ fiber._stack.push(setInterruptible(true));
2021
+ return self;
2022
+ });
2023
+ const setInterruptible = /*#__PURE__*/makePrimitive({
2024
+ op: "SetInterruptible",
2025
+ ensure(fiber) {
2026
+ fiber.interruptible = this[args];
2027
+ if (fiber._interrupted && fiber.interruptible) {
2028
+ return () => exitInterrupt;
2029
+ }
2030
+ }
1906
2031
  });
1907
2032
  /**
1908
- * Wrap the given `Micro` effect in an uninterruptible region, preventing the
1909
- * effect from being aborted.
2033
+ * Flag the effect as interruptible, which means that when the effect is
2034
+ * interrupted, it will be interrupted immediately.
1910
2035
  *
1911
2036
  * @since 3.4.0
1912
2037
  * @experimental
1913
- * @category interruption
2038
+ * @category flags
1914
2039
  */
1915
- export const uninterruptible = self => unsafeMakeOptions(function (env, onExit) {
1916
- const nextEnv = envMutate(env, function (env) {
1917
- env[currentInterruptible.key] = false;
1918
- env[currentAbortSignal.key] = new AbortController().signal;
1919
- return env;
1920
- });
1921
- self[runSymbol](nextEnv, onExit);
1922
- }, false);
2040
+ export const interruptible = self => withFiber(fiber => {
2041
+ if (fiber.interruptible) return self;
2042
+ fiber.interruptible = true;
2043
+ fiber._stack.push(setInterruptible(false));
2044
+ if (fiber._interrupted) return exitInterrupt;
2045
+ return self;
2046
+ });
1923
2047
  /**
1924
2048
  * Wrap the given `Micro` effect in an uninterruptible region, preventing the
1925
2049
  * effect from being aborted.
@@ -1941,36 +2065,11 @@ export const uninterruptible = self => unsafeMakeOptions(function (env, onExit)
1941
2065
  * )
1942
2066
  * ```
1943
2067
  */
1944
- export const uninterruptibleMask = f => unsafeMakeOptions((env, onExit) => {
1945
- const isInterruptible = envGet(env, currentInterruptible);
1946
- const effect = isInterruptible ? f(interruptible) : f(identity);
1947
- const nextEnv = isInterruptible ? envMutate(env, function (env) {
1948
- env[currentInterruptible.key] = false;
1949
- env[currentAbortSignal.key] = new AbortController().signal;
1950
- return env;
1951
- }) : env;
1952
- effect[runSymbol](nextEnv, onExit);
1953
- }, false);
1954
- /**
1955
- * Wrap the given `Micro` effect in an interruptible region, allowing the effect
1956
- * to be aborted.
1957
- *
1958
- * @since 3.4.0
1959
- * @experimental
1960
- * @category interruption
1961
- */
1962
- export const interruptible = self => make((env, onExit) => {
1963
- const isInterruptible = envGet(env, currentInterruptible);
1964
- let newEnv = env;
1965
- if (!isInterruptible) {
1966
- const controller = envGet(env, currentAbortController);
1967
- newEnv = envMutate(env, function (env) {
1968
- env[currentInterruptible.key] = true;
1969
- env[currentAbortSignal.key] = controller.signal;
1970
- return env;
1971
- });
1972
- }
1973
- self[runSymbol](newEnv, onExit);
2068
+ export const uninterruptibleMask = f => withFiber(fiber => {
2069
+ if (!fiber.interruptible) return f(identity);
2070
+ fiber.interruptible = false;
2071
+ fiber._stack.push(setInterruptible(true));
2072
+ return f(interruptible);
1974
2073
  });
1975
2074
  /**
1976
2075
  * Runs all the provided effects in sequence respecting the structure provided in input.
@@ -1997,6 +2096,29 @@ export const all = (arg, options) => {
1997
2096
  }), out);
1998
2097
  });
1999
2098
  };
2099
+ /**
2100
+ * @since 3.11.0
2101
+ * @experimental
2102
+ * @category collecting & elements
2103
+ */
2104
+ export const whileLoop = /*#__PURE__*/makePrimitive({
2105
+ op: "While",
2106
+ contA(value, fiber) {
2107
+ this[args].step(value);
2108
+ if (this[args].while()) {
2109
+ fiber._stack.push(this);
2110
+ return this[args].body();
2111
+ }
2112
+ return exitVoid;
2113
+ },
2114
+ eval(fiber) {
2115
+ if (this[args].while()) {
2116
+ fiber._stack.push(this);
2117
+ return this[args].body();
2118
+ }
2119
+ return exitVoid;
2120
+ }
2121
+ });
2000
2122
  /**
2001
2123
  * For each element of the provided iterable, run the effect and collect the results.
2002
2124
  *
@@ -2010,58 +2132,76 @@ export const all = (arg, options) => {
2010
2132
  * @experimental
2011
2133
  * @category collecting & elements
2012
2134
  */
2013
- export const forEach = (iterable, f, options) => make(function (env, onExit) {
2014
- const concurrencyOption = options?.concurrency === "inherit" ? envGet(env, currentConcurrency) : options?.concurrency ?? 1;
2135
+ export const forEach = (iterable, f, options) => withFiber(parent => {
2136
+ const concurrencyOption = options?.concurrency === "inherit" ? parent.getRef(CurrentConcurrency) : options?.concurrency ?? 1;
2015
2137
  const concurrency = concurrencyOption === "unbounded" ? Number.POSITIVE_INFINITY : Math.max(1, concurrencyOption);
2016
- // abort
2017
- const [envWithSignal, onAbort] = forkSignal(env);
2018
- // iterate
2019
- let result = undefined;
2020
- const items = Array.from(iterable);
2138
+ const items = Arr.fromIterable(iterable);
2021
2139
  let length = items.length;
2022
2140
  if (length === 0) {
2023
- return onExit(Either.right(options?.discard ? undefined : []));
2141
+ return options?.discard ? void_ : succeed([]);
2024
2142
  }
2025
2143
  const out = options?.discard ? undefined : new Array(length);
2026
2144
  let index = 0;
2027
- let inProgress = 0;
2028
- let doneCount = 0;
2029
- let pumping = false;
2030
- function pump() {
2031
- pumping = true;
2032
- while (inProgress < concurrency && index < length) {
2033
- const currentIndex = index;
2034
- const item = items[currentIndex];
2035
- index++;
2036
- inProgress++;
2037
- try {
2038
- f(item, currentIndex)[runSymbol](envWithSignal, function (exit) {
2039
- if (exit._tag === "Left") {
2040
- if (result === undefined) {
2041
- result = exit;
2042
- length = index;
2043
- onAbort();
2145
+ if (concurrency === 1) {
2146
+ return as(whileLoop({
2147
+ while: () => index < items.length,
2148
+ body: () => f(items[index], index),
2149
+ step: out ? b => out[index++] = b : _ => index++
2150
+ }), out);
2151
+ }
2152
+ return async(resume => {
2153
+ const fibers = new Set();
2154
+ let result = undefined;
2155
+ let inProgress = 0;
2156
+ let doneCount = 0;
2157
+ let pumping = false;
2158
+ let interrupted = false;
2159
+ function pump() {
2160
+ pumping = true;
2161
+ while (inProgress < concurrency && index < length) {
2162
+ const currentIndex = index;
2163
+ const item = items[currentIndex];
2164
+ index++;
2165
+ inProgress++;
2166
+ try {
2167
+ const child = unsafeFork(parent, f(item, currentIndex), true, true);
2168
+ fibers.add(child);
2169
+ child.addObserver(exit => {
2170
+ fibers.delete(child);
2171
+ if (interrupted) {
2172
+ return;
2173
+ } else if (exit._tag === "Failure") {
2174
+ if (result === undefined) {
2175
+ result = exit;
2176
+ length = index;
2177
+ fibers.forEach(fiber => fiber.unsafeInterrupt());
2178
+ }
2179
+ } else if (out !== undefined) {
2180
+ out[currentIndex] = exit.value;
2044
2181
  }
2045
- } else if (out !== undefined) {
2046
- out[currentIndex] = exit.right;
2047
- }
2048
- doneCount++;
2049
- inProgress--;
2050
- if (doneCount === length) {
2051
- onExit(result ?? Either.right(out));
2052
- } else if (!pumping && inProgress < concurrency) {
2053
- pump();
2054
- }
2055
- });
2056
- } catch (err) {
2057
- result = exitDie(err);
2058
- length = index;
2059
- onAbort();
2182
+ doneCount++;
2183
+ inProgress--;
2184
+ if (doneCount === length) {
2185
+ resume(result ?? succeed(out));
2186
+ } else if (!pumping && inProgress < concurrency) {
2187
+ pump();
2188
+ }
2189
+ });
2190
+ } catch (err) {
2191
+ result = exitDie(err);
2192
+ length = index;
2193
+ fibers.forEach(fiber => fiber.unsafeInterrupt());
2194
+ }
2060
2195
  }
2196
+ pumping = false;
2061
2197
  }
2062
- pumping = false;
2063
- }
2064
- pump();
2198
+ pump();
2199
+ return suspend(() => {
2200
+ interrupted = true;
2201
+ index = length;
2202
+ return fiberInterruptAll(fibers);
2203
+ });
2204
+ });
2065
2205
  });
2066
2206
  /**
2067
2207
  * Effectfully filter the elements of the provided iterable.
@@ -2134,92 +2274,8 @@ export {
2134
2274
  */
2135
2275
  let_ as let };
2136
2276
  // ----------------------------------------------------------------------------
2137
- // handle & forking
2277
+ // fibers & forking
2138
2278
  // ----------------------------------------------------------------------------
2139
- /**
2140
- * @since 3.4.0
2141
- * @experimental
2142
- * @category handle & forking
2143
- */
2144
- export const HandleTypeId = /*#__PURE__*/Symbol.for("effect/Micro/Handle");
2145
- /**
2146
- * @since 3.4.0
2147
- * @experimental
2148
- * @category handle & forking
2149
- */
2150
- export const isHandle = u => typeof u === "object" && u !== null && HandleTypeId in u;
2151
- class HandleImpl extends Class {
2152
- parentSignal;
2153
- [HandleTypeId];
2154
- observers = /*#__PURE__*/new Set();
2155
- _exit = undefined;
2156
- _controller;
2157
- isRoot;
2158
- constructor(parentSignal, controller) {
2159
- super();
2160
- this.parentSignal = parentSignal;
2161
- this[HandleTypeId] = HandleTypeId;
2162
- this.isRoot = controller !== undefined;
2163
- this._controller = controller ?? new AbortController();
2164
- if (!this.isRoot) {
2165
- parentSignal.addEventListener("abort", this.unsafeInterrupt);
2166
- }
2167
- }
2168
- unsafePoll() {
2169
- return this._exit ?? null;
2170
- }
2171
- unsafeInterrupt = () => {
2172
- this._controller.abort();
2173
- };
2174
- emit(exit) {
2175
- if (this._exit) {
2176
- return;
2177
- }
2178
- this._exit = exit;
2179
- if (!this.isRoot) {
2180
- this.parentSignal.removeEventListener("abort", this.unsafeInterrupt);
2181
- }
2182
- this.observers.forEach(observer => observer(exit));
2183
- this.observers.clear();
2184
- }
2185
- addObserver(observer) {
2186
- if (this._exit) {
2187
- return observer(this._exit);
2188
- }
2189
- this.observers.add(observer);
2190
- }
2191
- removeObserver(observer) {
2192
- this.observers.delete(observer);
2193
- }
2194
- get await() {
2195
- return suspend(() => {
2196
- if (this._exit) {
2197
- return succeed(this._exit);
2198
- }
2199
- return async(resume => {
2200
- function observer(exit) {
2201
- resume(succeed(exit));
2202
- }
2203
- this.addObserver(observer);
2204
- return sync(() => {
2205
- this.removeObserver(observer);
2206
- });
2207
- });
2208
- });
2209
- }
2210
- get join() {
2211
- return flatMap(this.await, fromExit);
2212
- }
2213
- get interrupt() {
2214
- return suspend(() => {
2215
- this.unsafeInterrupt();
2216
- return this.await;
2217
- });
2218
- }
2219
- asMicro() {
2220
- return this.join;
2221
- }
2222
- }
2223
2279
  /**
2224
2280
  * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
2225
2281
  * aborted.
@@ -2230,21 +2286,23 @@ class HandleImpl extends Class {
2230
2286
  * @experimental
2231
2287
  * @category handle & forking
2232
2288
  */
2233
- export const fork = self => make(function (env, onExit) {
2234
- const signal = envGet(env, currentAbortSignal);
2235
- const handle = new HandleImpl(signal);
2236
- const nextEnv = envMutate(env, map => {
2237
- map[currentAbortController.key] = handle._controller;
2238
- map[currentAbortSignal.key] = handle._controller.signal;
2239
- return map;
2240
- });
2241
- envGet(env, currentScheduler).scheduleTask(() => {
2242
- self[runSymbol](nextEnv, exit => {
2243
- handle.emit(exit);
2244
- });
2245
- }, 0);
2246
- onExit(Either.right(handle));
2289
+ export const fork = self => withFiber(fiber => {
2290
+ fiberMiddleware.interruptChildren ??= fiberInterruptChildren;
2291
+ return succeed(unsafeFork(fiber, self));
2247
2292
  });
2293
+ const unsafeFork = (parent, effect, immediate = false, daemon = false) => {
2294
+ const child = new FiberImpl(parent.context, parent.interruptible);
2295
+ if (!daemon) {
2296
+ parent.children().add(child);
2297
+ child.addObserver(() => parent.children().delete(child));
2298
+ }
2299
+ if (immediate) {
2300
+ child.evaluate(effect);
2301
+ } else {
2302
+ parent.getRef(CurrentScheduler).scheduleTask(() => child.evaluate(effect), 0);
2303
+ }
2304
+ return child;
2305
+ };
2248
2306
  /**
2249
2307
  * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
2250
2308
  * aborted.
@@ -2255,21 +2313,7 @@ export const fork = self => make(function (env, onExit) {
2255
2313
  * @experimental
2256
2314
  * @category handle & forking
2257
2315
  */
2258
- export const forkDaemon = self => make(function (env, onExit) {
2259
- const controller = new AbortController();
2260
- const handle = new HandleImpl(controller.signal, controller);
2261
- const nextEnv = envMutate(env, map => {
2262
- map[currentAbortController.key] = controller;
2263
- map[currentAbortSignal.key] = controller.signal;
2264
- return map;
2265
- });
2266
- envGet(env, currentScheduler).scheduleTask(() => {
2267
- self[runSymbol](nextEnv, exit => {
2268
- handle.emit(exit);
2269
- });
2270
- }, 0);
2271
- onExit(Either.right(handle));
2272
- });
2316
+ export const forkDaemon = self => withFiber(fiber => succeed(unsafeFork(fiber, self, false, true)));
2273
2317
  /**
2274
2318
  * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
2275
2319
  * aborted.
@@ -2280,7 +2324,7 @@ export const forkDaemon = self => make(function (env, onExit) {
2280
2324
  * @experimental
2281
2325
  * @category handle & forking
2282
2326
  */
2283
- export const forkIn = /*#__PURE__*/dual(2, (self, scope) => uninterruptibleMask(restore => flatMap(scope.fork, scope => tap(restore(forkDaemon(onExit(self, exit => scope.close(exit)))), fiber => scope.addFinalizer(_ => asVoid(fiber.interrupt))))));
2327
+ export const forkIn = /*#__PURE__*/dual(2, (self, scope) => uninterruptibleMask(restore => flatMap(scope.fork, scope => tap(restore(forkDaemon(onExit(self, exit => scope.close(exit)))), fiber => scope.addFinalizer(_ => fiberInterrupt(fiber))))));
2284
2328
  /**
2285
2329
  * Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
2286
2330
  * aborted.
@@ -2320,29 +2364,20 @@ export const forkScoped = self => flatMap(scope, scope => forkIn(self, scope));
2320
2364
  * ```
2321
2365
  */
2322
2366
  export const runFork = (effect, options) => {
2323
- const controller = new AbortController();
2324
- const refs = Object.create(null);
2325
- refs[currentAbortController.key] = controller;
2326
- refs[currentAbortSignal.key] = controller.signal;
2327
- refs[currentScheduler.key] = options?.scheduler ?? new MicroSchedulerDefault();
2328
- const env = envMake(refs);
2329
- const handle = new HandleImpl(controller.signal, controller);
2330
- effect[runSymbol](envSet(env, currentAbortSignal, handle._controller.signal), exit => {
2331
- handle.emit(exit);
2332
- if (options?.signal) {
2333
- options.signal.removeEventListener("abort", handle.unsafeInterrupt);
2334
- }
2335
- });
2367
+ const fiber = new FiberImpl(CurrentScheduler.context(options?.scheduler ?? new MicroSchedulerDefault()));
2368
+ fiber.evaluate(effect);
2336
2369
  if (options?.signal) {
2337
2370
  if (options.signal.aborted) {
2338
- handle.unsafeInterrupt();
2371
+ fiber.unsafeInterrupt();
2339
2372
  } else {
2340
- options.signal.addEventListener("abort", handle.unsafeInterrupt, {
2373
+ const abort = () => fiber.unsafeInterrupt();
2374
+ options.signal.addEventListener("abort", abort, {
2341
2375
  once: true
2342
2376
  });
2377
+ fiber.addObserver(() => options.signal.removeEventListener("abort", abort));
2343
2378
  }
2344
2379
  }
2345
- return handle;
2380
+ return fiber;
2346
2381
  };
2347
2382
  /**
2348
2383
  * Execute the `Micro` effect and return a `Promise` that resolves with the
@@ -2365,10 +2400,10 @@ export const runPromiseExit = (effect, options) => new Promise((resolve, _reject
2365
2400
  * @category execution
2366
2401
  */
2367
2402
  export const runPromise = (effect, options) => runPromiseExit(effect, options).then(exit => {
2368
- if (exit._tag === "Left") {
2369
- throw exit.left;
2403
+ if (exit._tag === "Failure") {
2404
+ throw exit.cause;
2370
2405
  }
2371
- return exit.right;
2406
+ return exit.value;
2372
2407
  });
2373
2408
  /**
2374
2409
  * Attempt to execute the `Micro` effect synchronously and return the `MicroExit`.
@@ -2382,15 +2417,11 @@ export const runPromise = (effect, options) => runPromiseExit(effect, options).t
2382
2417
  */
2383
2418
  export const runSyncExit = effect => {
2384
2419
  const scheduler = new MicroSchedulerDefault();
2385
- const handle = runFork(effect, {
2420
+ const fiber = runFork(effect, {
2386
2421
  scheduler
2387
2422
  });
2388
2423
  scheduler.flush();
2389
- const exit = handle.unsafePoll();
2390
- if (exit === null) {
2391
- return exitDie(handle);
2392
- }
2393
- return exit;
2424
+ return fiber._exit ?? exitDie(fiber);
2394
2425
  };
2395
2426
  /**
2396
2427
  * Attempt to execute the `Micro` effect synchronously and return the success
@@ -2402,24 +2433,24 @@ export const runSyncExit = effect => {
2402
2433
  */
2403
2434
  export const runSync = effect => {
2404
2435
  const exit = runSyncExit(effect);
2405
- if (exit._tag === "Left") {
2406
- throw exit.left;
2407
- }
2408
- return exit.right;
2436
+ if (exit._tag === "Failure") throw exit.cause;
2437
+ return exit.value;
2409
2438
  };
2410
2439
  const YieldableError = /*#__PURE__*/function () {
2411
- class YieldableError extends globalThis.Error {
2412
- [runSymbol](_env, onExit) {
2413
- onExit(exitFail(this));
2414
- }
2440
+ class YieldableError extends globalThis.Error {}
2441
+ Object.assign(YieldableError.prototype, MicroProto, StructuralPrototype, {
2442
+ [identifier]: "Failure",
2443
+ [evaluate]() {
2444
+ return fail(this);
2445
+ },
2415
2446
  toString() {
2416
2447
  return this.message ? `${this.name}: ${this.message}` : this.name;
2417
- }
2448
+ },
2418
2449
  toJSON() {
2419
2450
  return {
2420
2451
  ...this
2421
2452
  };
2422
- }
2453
+ },
2423
2454
  [NodeInspectSymbol]() {
2424
2455
  const stack = this.stack;
2425
2456
  if (stack) {
@@ -2427,8 +2458,7 @@ const YieldableError = /*#__PURE__*/function () {
2427
2458
  }
2428
2459
  return this.toString();
2429
2460
  }
2430
- }
2431
- Object.assign(YieldableError.prototype, MicroProto, StructuralPrototype);
2461
+ });
2432
2462
  return YieldableError;
2433
2463
  }();
2434
2464
  /**