1import * as Arr from "../Array.ts"
2import type * as Cause from "../Cause.ts"
3import type * as Clock from "../Clock.ts"
4import type * as Console from "../Console.ts"
5import * as Context from "../Context.ts"
6import * as Duration from "../Duration.ts"
7import type * as Effect from "../Effect.ts"
8import * as Equal from "../Equal.ts"
9import type * as Exit from "../Exit.ts"
10import type * as Fiber from "../Fiber.ts"
11import * as Filter from "../Filter.ts"
12import { formatJson } from "../Formatter.ts"
13import type { LazyArg } from "../Function.ts"
14import { constant, constFalse, constTrue, constUndefined, constVoid, dual, identity } from "../Function.ts"
15import * as Hash from "../Hash.ts"
16import { toJson, toStringUnknown } from "../Inspectable.ts"
17import * as Iterable from "../Iterable.ts"
18import type * as _Latch from "../Latch.ts"
19import type * as Logger from "../Logger.ts"
20import type * as LogLevel from "../LogLevel.ts"
21import * as Option from "../Option.ts"
22import * as Order from "../Order.ts"
23import { pipeArguments } from "../Pipeable.ts"
24import type * as Predicate from "../Predicate.ts"
25import { hasProperty, isIterable, isString, isTagged } from "../Predicate.ts"
26import { currentFiberTypeId, redact } from "../Redactable.ts"
27import type { StackFrame } from "../References.ts"
28import * as Result from "../Result.ts"
29import * as Scheduler from "../Scheduler.ts"
30import type * as Scope from "../Scope.ts"
31import * as Tracer from "../Tracer.ts"
32import type {
33 Concurrency,
34 EqualsWith,
35 ExcludeReason,
36 ExcludeTag,
37 ExtractReason,
38 ExtractTag,
39 NarrowReason,
40 NoInfer,
41 OmitReason,
42 ReasonOf,
43 ReasonTags,
44 Simplify,
45 Tags,
46 unassigned
47} from "../Types.ts"
48import { internalCall } from "../Utils.ts"
49import type { Primitive } from "./core.ts"
50import {
51 args,
52 causeAnnotate,
53 causeCombine,
54 causeEmpty,
55 causeFromReasons,
56 CauseImpl,
57 constEmptyAnnotations,
58 contA,
59 contAll,
60 contE,
61 evaluate,
62 exitDie,
63 exitFail,
64 exitFailCause,
65 exitSucceed,
66 ExitTypeId,
67 Fail,
68 InterruptorStackTrace,
69 isCause,
70 isDieReason,
71 isEffect,
72 isFailReason,
73 isInterruptReason,
74 isNoSuchElementError,
75 makePrimitive,
76 makePrimitiveProto,
77 NoSuchElementError,
78 ReasonBase,
79 StackTraceKey as CauseStackTrace,
80 TaggedError,
81 withFiber,
82 Yield
83} from "./core.ts"
84import * as doNotation from "./doNotation.ts"
85import * as InternalMetric from "./metric.ts"
86import * as InternalRecord from "./record.ts"
87import {
88 CurrentErrorReporters,
89 CurrentLogAnnotations,
90 CurrentLogLevel,
91 CurrentLogSpans,
92 CurrentStackFrame,
93 MinimumLogLevel,
94 TracerEnabled,
95 TracerSpanAnnotations,
96 TracerSpanLinks,
97 TracerTimingEnabled
98} from "./references.ts"
99import { getStackTraceLimit, setStackTraceLimit } from "./stackTraceLimit.ts"
100import { addSpanStackTrace, makeStackCleaner } from "./tracer.ts"
101
102// ----------------------------------------------------------------------------
103// Cause
104// ----------------------------------------------------------------------------
105
106/** @internal */
107export class Interrupt extends ReasonBase<"Interrupt"> implements Cause.Interrupt {
108 declare readonly fiberId: number | undefined
109 constructor(
110 fiberId: number | undefined,
111 annotations = constEmptyAnnotations
112 ) {
113 super("Interrupt", annotations, "Interrupted")
114 this.fiberId = fiberId
115 }
116 override toString() {
117 return `Interrupt(${this.fiberId})`
118 }
119 toJSON(): unknown {
120 return {
121 _tag: "Interrupt",
122 fiberId: this.fiberId
123 }
124 }
125 [Equal.symbol](that: any): boolean {
126 return (
127 isInterruptReason(that) &&
128 this.fiberId === that.fiberId &&
129 this.annotations === that.annotations
130 )
131 }
132 [Hash.symbol](): number {
133 return Hash.combine(Hash.string(`${this._tag}:${this.fiberId}`))(
134 Hash.random(this.annotations)
135 )
136 }
137}
138
139/** @internal */
140export const makeInterruptReason = (fiberId?: number | undefined): Cause.Interrupt => new Interrupt(fiberId)
141
142/** @internal */
143export const causeInterrupt = (
144 fiberId?: number | undefined
145): Cause.Cause<never> => new CauseImpl([new Interrupt(fiberId)])
146
147/** @internal */
148export const hasFails = <E>(self: Cause.Cause<E>): boolean => self.reasons.some(isFailReason)
149
150/** @internal */
151export const findFail = <E>(self: Cause.Cause<E>): Result.Result<Cause.Fail<E>, Cause.Cause<never>> => {
152 const reason = self.reasons.find(isFailReason)
153 return reason ? Result.succeed(reason) : Result.fail(self as Cause.Cause<never>)
154}
155
156/** @internal */
157export const findError = <E>(self: Cause.Cause<E>): Result.Result<E, Cause.Cause<never>> => {
158 for (let i = 0; i < self.reasons.length; i++) {
159 const reason = self.reasons[i]
160 if (reason._tag === "Fail") {
161 return Result.succeed(reason.error)
162 }
163 }
164 return Result.fail(self as Cause.Cause<never>)
165}
166
167/** @internal */
168export const findErrorOption = Filter.toOption(findError)
169
170/** @internal */
171export const hasDies = <E>(self: Cause.Cause<E>): boolean => self.reasons.some(isDieReason)
172
173/** @internal */
174export const findDie = <E>(self: Cause.Cause<E>): Result.Result<Cause.Die, Cause.Cause<E>> => {
175 const reason = self.reasons.find(isDieReason)
176 return reason ? Result.succeed(reason) : Result.fail(self)
177}
178
179/** @internal */
180export const findDefect = <E>(self: Cause.Cause<E>): Result.Result<unknown, Cause.Cause<E>> => {
181 const reason = self.reasons.find(isDieReason)
182 return reason ? Result.succeed(reason.defect) : Result.fail(self)
183}
184
185/** @internal */
186export const hasInterrupts = <E>(self: Cause.Cause<E>): boolean => self.reasons.some(isInterruptReason)
187
188/** @internal */
189export const findInterrupt = <E>(self: Cause.Cause<E>): Result.Result<Cause.Interrupt, Cause.Cause<E>> => {
190 const reason = self.reasons.find(isInterruptReason)
191 return reason ? Result.succeed(reason) : Result.fail(self)
192}
193
194/** @internal */
195export const causeFilterInterruptors = <E>(
196 self: Cause.Cause<E>
197): Result.Result<Set<number>, Cause.Cause<E>> => {
198 let interruptors: Set<number> | undefined
199 for (let i = 0; i < self.reasons.length; i++) {
200 const f = self.reasons[i]
201 if (f._tag !== "Interrupt") continue
202 interruptors ??= new Set()
203 if (f.fiberId !== undefined) {
204 interruptors.add(f.fiberId)
205 }
206 }
207 return interruptors ? Result.succeed(interruptors) : Result.fail(self)
208}
209
210/** @internal */
211export const causeInterruptors = <E>(self: Cause.Cause<E>): ReadonlySet<number> => {
212 const result = causeFilterInterruptors(self)
213 return Result.isFailure(result) ? emptySet : result.success
214}
215const emptySet = new Set<number>()
216
217/** @internal */
218export const hasInterruptsOnly = <E>(self: Cause.Cause<E>): boolean =>
219 self.reasons.length > 0 && self.reasons.every(isInterruptReason)
220
221/** @internal */
222export const reasonAnnotations = <E>(
223 self: Cause.Reason<E>
224): Context.Context<never> => Context.makeUnsafe(self.annotations)
225
226/** @internal */
227export const causeAnnotations = <E>(
228 self: Cause.Cause<E>
229): Context.Context<never> => {
230 const map = new Map<string, unknown>()
231 for (const f of self.reasons) {
232 if (f.annotations.size > 0) {
233 for (const [key, value] of f.annotations) {
234 map.set(key, value)
235 }
236 }
237 }
238 return Context.makeUnsafe(map)
239}
240
241/** @internal */
242export const causeMap: {
243 <E, E2>(f: (error: NoInfer<E>) => E2): (self: Cause.Cause<E>) => Cause.Cause<E2>
244 <E, E2>(self: Cause.Cause<E>, f: (error: NoInfer<E>) => E2): Cause.Cause<E2>
245} = dual(
246 2,
247 <E, E2>(self: Cause.Cause<E>, f: (error: NoInfer<E>) => E2): Cause.Cause<E2> => {
248 let hasFail = false
249 const failures = self.reasons.map((failure) => {
250 if (isFailReason(failure)) {
251 hasFail = true
252 return new Fail(f(failure.error), failure.annotations)
253 }
254 return failure
255 })
256 return hasFail ? causeFromReasons(failures) : self as any
257 }
258)
259
260/** @internal */
261export const causeSquash = <E>(self: Cause.Cause<E>): unknown => {
262 let die: Cause.Die | undefined
263 for (const reason of self.reasons) {
264 if (reason._tag === "Fail") return reason.error
265 if (reason._tag === "Die") die ??= reason
266 }
267 if (die !== undefined) return die.defect
268 if (self.reasons.length > 0) return new globalThis.Error("All fibers interrupted without error")
269 return new globalThis.Error("Empty cause")
270}
271
272/** @internal */
273export const causePrettyErrors = <E>(self: Cause.Cause<E>, options?: {
274 readonly includeCauseInStack?: boolean | undefined
275}): Array<Error> => {
276 const errors: Array<Error> = []
277 const interrupts: Array<Cause.Interrupt> = []
278 if (self.reasons.length === 0) return errors
279
280 const prevStackLimit = getStackTraceLimit()
281 if (prevStackLimit !== 0) setStackTraceLimit(1)
282
283 try {
284 for (const failure of self.reasons) {
285 if (failure._tag === "Interrupt") {
286 interrupts.push(failure)
287 continue
288 }
289 errors.push(
290 causePrettyError(
291 failure._tag === "Die" ? failure.defect : failure.error as any,
292 failure.annotations,
293 options
294 )
295 )
296 }
297 if (errors.length === 0) {
298 const cause = new Error("The fiber was interrupted by:")
299 cause.name = "InterruptCause"
300 cause.stack = interruptCauseStack(cause, interrupts)
301 const error = new globalThis.Error("All fibers interrupted without error", { cause })
302 error.name = "InterruptError"
303 error.stack = `${error.name}: ${error.message}`
304 errors.push(causePrettyError(error, interrupts[0].annotations, options))
305 }
306 } finally {
307 if (prevStackLimit !== 0) setStackTraceLimit(prevStackLimit)
308 }
309
310 return errors
311}
312
313/** @internal */
314export const causePrettyError = (
315 original: Record<string, unknown> | Error,
316 annotations?: ReadonlyMap<string, unknown>,
317 options?: {
318 readonly includeCauseInStack?: boolean | undefined
319 }
320): Error => {
321 const kind = typeof original
322 let error: Error
323 if (original && kind === "object") {
324 error = new globalThis.Error(causePrettyMessage(original), {
325 cause: original.cause ? causePrettyError(original.cause as any) : undefined
326 })
327 if (typeof original.name === "string") {
328 error.name = original.name
329 }
330 if (typeof original.stack === "string") {
331 error.stack = cleanErrorStack(original.stack, error, annotations)
332 } else {
333 const stack = `${error.name}: ${error.message}`
334 error.stack = annotations ? addStackAnnotations(stack, annotations) : stack
335 }
336 if (options?.includeCauseInStack) {
337 error.stack = renderPrettyError(error)!
338 }
339 for (const key of Object.keys(original)) {
340 if (!(key in error)) {
341 ;(error as any)[key] = (original as any)[key]
342 }
343 }
344 } else {
345 error = new globalThis.Error(
346 !original ? `Unknown error: ${original}` : kind === "string" ? original as any : formatJson(original)
347 )
348 }
349 return error
350}
351
352const causePrettyMessage = (u: Record<string, unknown> | Error): string => {
353 if (typeof u.message === "string") {
354 return u.message
355 } else if (
356 typeof u.toString === "function"
357 && u.toString !== Object.prototype.toString
358 && u.toString !== Array.prototype.toString
359 ) {
360 try {
361 return u.toString()
362 } catch {
363 // something's off, rollback to json
364 }
365 }
366 return formatJson(u)
367}
368
369const locationRegExp = /\((.*)\)/g
370
371const cleanErrorStack = (
372 stack: string,
373 error: Error,
374 annotations: ReadonlyMap<string, unknown> | undefined
375): string => {
376 const message = `${error.name}: ${error.message}`
377 const lines = (stack.startsWith(message) ? stack.slice(message.length) : stack).split("\n")
378 const out: Array<string> = [message]
379 for (let i = 1; i < lines.length; i++) {
380 if (/Generator\.next|~effect\/(?:Effect|Utils)/.test(lines[i])) {
381 break
382 }
383 out.push(lines[i])
384 }
385 return annotations ? addStackAnnotations(out.join("\n"), annotations) : out.join("\n")
386}
387
388const addStackAnnotations = (stack: string, annotations: ReadonlyMap<string, unknown>) => {
389 const frame = annotations?.get(CauseStackTrace.key) as StackFrame | undefined
390 if (frame) {
391 stack = `${stack}\n${currentStackTrace(frame)}`
392 }
393 return stack
394}
395
396const interruptCauseStack = (error: Error, interrupts: Array<Cause.Interrupt>): string => {
397 const out: Array<string> = [`${error.name}: ${error.message}`]
398 for (const current of interrupts) {
399 const fiberId = current.fiberId !== undefined ? `#${current.fiberId}` : "unknown"
400 const frame = current.annotations.get(InterruptorStackTrace.key) as StackFrame | undefined
401 out.push(` at fiber (${fiberId})`)
402 if (frame) out.push(currentStackTrace(frame))
403 }
404 return out.join("\n")
405}
406
407const currentStackTrace = (frame: StackFrame): string => {
408 const out: Array<string> = []
409 let current: StackFrame | undefined = frame
410 let i = 0
411 while (current && i < 10) {
412 const stack = current.stack()
413 if (stack) {
414 const locationMatchAll = stack.matchAll(locationRegExp)
415 let match = false
416 for (const [, location] of locationMatchAll) {
417 match = true
418 out.push(` at ${current.name} (${location})`)
419 }
420 if (!match) {
421 out.push(` at ${current.name} (${stack.replace(/^at /, "")})`)
422 }
423 } else {
424 out.push(` at ${current.name}`)
425 }
426 current = current.parent
427 i++
428 }
429 return out.join("\n")
430}
431
432/** @internal */
433export const causePretty = <E>(cause: Cause.Cause<E>): string =>
434 causePrettyErrors<E>(cause).map(renderPrettyError).join("\n")
435
436const renderPrettyError = (e: Error): string | undefined =>
437 e.cause ? `${e.stack} {\n${renderErrorCause(e.cause as Error, " ")}\n}` : e.stack
438
439const renderErrorCause = (cause: Error, prefix: string) => {
440 const lines = cause.stack!.split("\n")
441 let stack = `${prefix}[cause]: ${lines[0]}`
442 for (let i = 1, len = lines.length; i < len; i++) {
443 stack += `\n${prefix}${lines[i]}`
444 }
445 if (cause.cause) {
446 stack += ` {\n${renderErrorCause(cause.cause as Error, `${prefix} `)}\n${prefix}}`
447 }
448 return stack
449}
450
451// ----------------------------------------------------------------------------
452// Fiber
453// ----------------------------------------------------------------------------
454
455/** @internal */
456export const FiberTypeId = "~effect/Fiber" as const
457
458const fiberVariance = {
459 _A: identity,
460 _E: identity
461}
462
463const fiberIdStore = { id: 0 }
464
465interface AsyncContext {
466 runInAsyncScope<This, Arg, R>(fn: (this: This, arg: Arg) => R, thisArg: This, arg: Arg): R
467}
468
469const AsyncResource: (new(type: string) => AsyncContext) | undefined = (() => {
470 try {
471 return (globalThis as any).process?.getBuiltinModule?.("node:async_hooks")?.AsyncResource
472 } catch {
473 return undefined
474 }
475})()
476
477const captureAsyncContext = (): AsyncContext | undefined =>
478 AsyncResource === undefined ? undefined : new AsyncResource("effect/Fiber")
479
480/** @internal */
481export const getCurrentFiber = (): Fiber.Fiber<any, any> | undefined => (globalThis as any)[currentFiberTypeId]
482
483/** @internal */
484export class FiberImpl<A = any, E = any> implements Fiber.Fiber<A, E> {
485 constructor(
486 context: Context.Context<never>,
487 interruptible: boolean = true
488 ) {
489 this.setContext(context)
490 this.id = ++fiberIdStore.id
491 this.currentOpCount = 0
492 this.interruptible = interruptible
493 this._stack = []
494 this._observers = undefined
495 this._exit = undefined
496 this._children = undefined
497 this._interruptedCause = undefined
498 this._yielded = undefined
499 this._running = false
500 this._deferredInterrupt = false
501 this._parent = undefined
502 this._asyncContext = undefined
503 this.cache.runtimeMetrics?.recordFiberStart(this.context)
504 }
505
506 get [FiberTypeId](): Fiber.Fiber.Variance<A, E> {
507 return fiberVariance
508 }
509
510 declare readonly id: number
511 declare interruptible: boolean
512 declare currentOpCount: number
513 declare readonly _stack: Array<Primitive>
514 declare _observers: Array<(exit: Exit.Exit<A, E>) => void> | undefined
515 declare _exit: Exit.Exit<A, E> | undefined
516 declare _children: Set<FiberImpl<any, any>> | undefined
517 declare _interruptedCause: Cause.Cause<never> | undefined
518 declare _yielded: Exit.Exit<any, any> | (() => void) | undefined
519 declare _running: boolean
520 declare _deferredInterrupt: boolean
521 declare _parent: FiberImpl<any, any> | undefined
522 declare _asyncContext: AsyncContext | undefined
523
524 // set in setContext
525 declare context: Context.Context<never>
526 declare cache: Fiber.Fiber.Cache
527
528 declare _dispatcher: Scheduler.SchedulerDispatcher | undefined
529 get currentDispatcher(): Scheduler.SchedulerDispatcher {
530 return this._dispatcher ??= this.cache.scheduler.makeDispatcher()
531 }
532
533 getRef<X>(ref: Context.Reference<X>): X {
534 return Context.get(this.context, ref)
535 }
536 addObserver(cb: (exit: Exit.Exit<A, E>) => void): () => void {
537 if (this._exit) {
538 cb(this._exit)
539 return constVoid
540 }
541 if (this._observers === undefined) {
542 this._observers = [cb]
543 } else {
544 this._observers.push(cb)
545 }
546 return () => this.removeObserver(cb)
547 }
548 removeObserver(cb: (exit: Exit.Exit<A, E>) => void): void {
549 if (this._exit || this._observers === undefined) return
550 const index = this._observers.indexOf(cb)
551 if (index >= 0) {
552 this._observers.splice(index, 1)
553 }
554 }
555 interruptUnsafe(fiberId?: number | undefined, annotations?: Context.Context<never> | undefined): void {
556 if (this._exit) {
557 return
558 }
559 let cause = causeInterrupt(fiberId)
560 if (this.cache.stackFrame) {
561 cause = causeAnnotate(cause, Context.make(CauseStackTrace, this.cache.stackFrame))
562 }
563 if (annotations) {
564 cause = causeAnnotate(cause, annotations)
565 }
566 this._interruptedCause = this._interruptedCause
567 ? causeCombine(this._interruptedCause, cause)
568 : cause
569 if (this.interruptible) {
570 if (this._running) {
571 this._deferredInterrupt = true
572 } else {
573 this.evaluate(failCause(this._interruptedCause) as any)
574 }
575 }
576 }
577 pollUnsafe(): Exit.Exit<A, E> | undefined {
578 return this._exit
579 }
580 evaluate(effect: Primitive): void {
581 if (this._exit) {
582 return
583 } else if (this._asyncContext !== undefined) {
584 const asyncContext = this._asyncContext
585 this._asyncContext = undefined
586 return asyncContext.runInAsyncScope(this.evaluate, this, effect)
587 } else if (this._yielded !== undefined) {
588 const yielded = this._yielded as () => void
589 this._yielded = undefined
590 yielded()
591 }
592 const exit = this.runLoop(effect)
593 if (exit === Yield) {
594 this._asyncContext = captureAsyncContext()
595 return
596 }
597 // the interruptChildren middleware is added in Effect.forkChild, so it can be
598 // tree-shaken if not used
599 const interruptChildren = fiberMiddleware.interruptChildren &&
600 fiberMiddleware.interruptChildren(this)
601 if (interruptChildren !== undefined) {
602 return this.evaluate(flatMap(interruptChildren, () => exit) as any)
603 }
604
605 this._exit = exit
606 this.cache.runtimeMetrics?.recordFiberEnd(this.context, this._exit)
607 if (this._parent) {
608 this._parent._children?.delete(this)
609 this._parent = undefined
610 }
611 if (this._observers !== undefined) {
612 const observers = this._observers
613 this._observers = undefined
614 for (let i = 0; i < observers.length; i++) {
615 observers[i](exit)
616 }
617 }
618 this._stack.length = 0
619 this._children = undefined
620 this.context = Context.empty()
621 }
622 runLoop(effect: Primitive): Exit.Exit<A, E> | Yield {
623 const prevFiber = (globalThis as any)[currentFiberTypeId]
624 ;(globalThis as any)[currentFiberTypeId] = this
625 const prevRunning = this._running
626 this._running = true
627 let yielding = false
628 let current: Primitive | Yield = effect
629 this.currentOpCount = 0
630 try {
631 while (true) {
632 if (this._deferredInterrupt) {
633 this._deferredInterrupt = false
634 current = failCause(this._interruptedCause!) as any
635 }
636 this.currentOpCount++
637 // Refresh the cache because a primitive can replace the fiber context.
638 const cache = this.cache
639 if (
640 !yielding &&
641 !cache.preventYield &&
642 cache.scheduler.shouldYield(this as any)
643 ) {
644 yielding = true
645 const prev = current
646 current = flatMap(yieldNow, () => prev as any) as any
647 }
648 current = cache.tracerContext
649 ? cache.tracerContext(current as any, this)
650 : (current as any)[evaluate](this)
651 if (current === Yield) {
652 const yielded = this._yielded!
653 if (ExitTypeId in yielded) {
654 this._deferredInterrupt = false
655 this._yielded = undefined
656 return yielded
657 } else if (this._deferredInterrupt) {
658 this._yielded = undefined
659 yielded()
660 continue
661 }
662 return Yield
663 }
664 }
665 } catch (error) {
666 if (!hasProperty(current, evaluate)) {
667 return exitDie(`Fiber.runLoop: Not a valid effect: ${String(current)}`)
668 }
669 return this.runLoop(exitDie(error) as any)
670 } finally {
671 this._running = prevRunning
672 ;(globalThis as any)[currentFiberTypeId] = prevFiber
673 }
674 }
675 getCont<S extends contA | contE>(symbol: S):
676 | (Primitive & Record<S, (value: any, fiber: FiberImpl) => Primitive>)
677 | undefined
678 {
679 if (this._deferredInterrupt) {
680 this._deferredInterrupt = false
681 return deferredInterruptCont
682 }
683 while (true) {
684 const op = this._stack.pop()
685 if (!op) return undefined
686 const all = op[contAll]
687 if (all !== undefined) {
688 const cont = all.call(op, this)
689 if (cont) {
690 ;(cont as any)[symbol] = cont
691 return cont as any
692 }
693 }
694 if (op[symbol]) return op as any
695 }
696 }
697 // Passes a success value straight to the next continuation instead of
698 // returning an Exit for the run loop to unwrap. Each call counts as an
699 // operation, and every `maxInlineSteps`th call returns an Exit instead, so
700 // continuations calling continuations never nest deeper than that.
701 succeedWith(value: unknown): Primitive | Yield {
702 if ((++this.currentOpCount & (maxInlineSteps - 1)) === 0) {
703 return exitSucceed(value) as any
704 }
705 const cont = this.getCont(contA)
706 return cont ? cont[contA](value, this) : this.yieldWith(exitSucceed(value))
707 }
708 yieldWith(value: Exit.Exit<any, any> | (() => void)): Yield {
709 this._yielded = value
710 return Yield
711 }
712 children(): Set<Fiber.Fiber<any, any>> {
713 return (this._children ??= new Set())
714 }
715 pipe() {
716 return pipeArguments(this, arguments)
717 }
718 setContext(context: Context.Context<never>): void {
719 const previous = this.context
720 this.context = context
721 // Every key cached below opts in to Context caching, so contexts related
722 // only by non-caching adds cannot have changed any of them
723 if (previous !== undefined && Context.hasSameCache(previous, context)) return
724 // Contexts sharing a cacheRoot resolve every cached key identically, so
725 // the derived cache object is computed once per root and shared by all
726 // fibers running with that root (forked fibers reuse the parent's).
727 const root: any = (context as any).cacheRoot
728 const cache: Fiber.Fiber.Cache = root._fiberCache ??= makeFiberContextCache(context)
729 if (this.cache?.scheduler !== cache.scheduler) {
730 this._dispatcher = undefined
731 }
732 this.cache = cache
733 }
734 get currentSpanLocal(): Tracer.Span | undefined {
735 const span = this.cache.span
736 return span?._tag === "Span" ? span : undefined
737 }
738}
739
740const makeFiberContextCache = (context: Context.Context<never>): Fiber.Fiber.Cache => {
741 // The string-keyed lookups keep the Tracer key values (and the native
742 // tracer behind Tracer.Tracer's default) out of every bundle
743 const currentTracer = Context.getOrUndefinedUnsafe<Tracer.Tracer>(context, Tracer.TracerKey)
744 return {
745 scheduler: Context.get(context, Scheduler.Scheduler),
746 tracer: currentTracer,
747 tracerContext: currentTracer ? currentTracer["context"] : undefined,
748 tracerEnabled: Context.get(context, TracerEnabled),
749 span: Context.getOrUndefinedUnsafe(context, Tracer.ParentSpanKey),
750 logLevel: Context.get(context, CurrentLogLevel),
751 minimumLogLevel: Context.get(context, MinimumLogLevel),
752 stackFrame: Context.get(context, CurrentStackFrame),
753 runtimeMetrics: Context.getOrUndefinedUnsafe(context, InternalMetric.FiberRuntimeMetricsKey),
754 maxOpsBeforeYield: Context.get(context, Scheduler.MaxOpsBeforeYield),
755 preventYield: Context.get(context, Scheduler.PreventSchedulerYield)
756 }
757}
758
759const deferredInterruptCont: any = {
760 [contA](_value: unknown, fiber: FiberImpl) {
761 return failCause(fiber._interruptedCause!)
762 },
763 [contE](_cause: unknown, fiber: FiberImpl) {
764 return failCause(fiber._interruptedCause!)
765 }
766}
767
768// must be a power of two
769const maxInlineSteps = 32
770
771const fiberMiddleware = {
772 interruptChildren: undefined as
773 | ((fiber: FiberImpl) => Effect.Effect<void> | undefined)
774 | undefined
775}
776
777const fiberStackAnnotations = (fiber: Fiber.Fiber<any, any>) => {
778 if (!fiber.cache.stackFrame) return undefined
779 const annotations = new Map<string, unknown>()
780 annotations.set(InterruptorStackTrace.key, fiber.cache.stackFrame)
781 return Context.makeUnsafe(annotations)
782}
783
784const fiberInterruptChildren = (fiber: FiberImpl) => {
785 if (fiber._children === undefined || fiber._children.size === 0) {
786 return undefined
787 }
788 return fiberInterruptAll(fiber._children)
789}
790
791/** @internal */
792export const fiberAwait = <A, E>(
793 self: Fiber.Fiber<A, E>
794): Effect.Effect<Exit.Exit<A, E>> => {
795 const impl = self as FiberImpl<A, E>
796 if (impl._exit) return succeed(impl._exit)
797 return callback((resume) => {
798 if (impl._exit) return resume(succeed(impl._exit))
799 return sync(self.addObserver((exit) => resume(succeed(exit))))
800 })
801}
802
803/** @internal */
804export const fiberAwaitAll = <Fiber extends Fiber.Fiber<any, any>>(
805 self: Iterable<Fiber>
806): Effect.Effect<
807 Array<
808 Exit.Exit<
809 Fiber extends Fiber.Fiber<infer _A, infer _E> ? _A : never,
810 Fiber extends Fiber.Fiber<infer _A, infer _E> ? _E : never
811 >
812 >
813> =>
814 callback((resume) => {
815 const iter = self[Symbol.iterator]() as Iterator<FiberImpl>
816 const exits: Array<Exit.Exit<any, any>> = []
817 let cancel: (() => void) | undefined = undefined
818 function loop() {
819 let result = iter.next()
820 while (!result.done) {
821 if (result.value._exit) {
822 exits.push(result.value._exit)
823 result = iter.next()
824 continue
825 }
826 cancel = result.value.addObserver((exit) => {
827 exits.push(exit)
828 loop()
829 })
830 return
831 }
832 resume(succeed(exits))
833 }
834 loop()
835 return sync(() => cancel?.())
836 })
837
838/** @internal */
839export const fiberJoin = <A, E>(self: Fiber.Fiber<A, E>): Effect.Effect<A, E> => {
840 const impl = self as FiberImpl<A, E>
841 if (impl._exit) return impl._exit
842 return callback((resume) => {
843 if (impl._exit) return resume(impl._exit)
844 return sync(self.addObserver(resume))
845 })
846}
847
848/** @internal */
849export const fiberJoinAll = <A extends Iterable<Fiber.Fiber<any, any>>>(self: A): Effect.Effect<
850 Arr.ReadonlyArray.With<A, A extends Iterable<Fiber.Fiber<infer _A, infer _E>> ? _A : never>,
851 A extends Iterable<Fiber.Fiber<infer _A, infer _E>> ? _E : never
852> =>
853 callback((resume) => {
854 const fibers = Array.from(self) as Array<FiberImpl>
855 if (fibers.length === 0) return resume(succeed(Arr.empty() as any))
856 const out = new Array<any>(fibers.length) as Arr.NonEmptyArray<any>
857 const observers = Arr.empty<(exit: Exit.Exit<any, any>) => void>()
858 const removeObservers = () => {
859 for (let i = 0; i < observers.length; i++) {
860 fibers[i].removeObserver(observers[i])
861 }
862 }
863 let done = 0
864 let failed = false
865 for (let i = 0; i < fibers.length; i++) {
866 if (failed) break
867 const observer = (exit: Exit.Exit<any, any>) => {
868 done++
869 if (exit._tag === "Failure") {
870 failed = true
871 removeObservers()
872 return resume(exit as any)
873 }
874 out[i] = exit.value
875 if (done === fibers.length) {
876 resume(succeed(out))
877 }
878 }
879 observers.push(observer)
880 fibers[i].addObserver(observer)
881 }
882 return sync(() => {
883 failed = true
884 removeObservers()
885 })
886 })
887
888/** @internal */
889export const fiberInterrupt = <A, E>(
890 self: Fiber.Fiber<A, E>
891): Effect.Effect<void> => withFiber((fiber) => fiberInterruptAs(self, fiber.id))
892
893/** @internal */
894export const fiberInterruptAs: {
895 (
896 fiberId: number | undefined,
897 annotations?: Context.Context<never> | undefined
898 ): <A, E>(self: Fiber.Fiber<A, E>) => Effect.Effect<void>
899 <A, E>(
900 self: Fiber.Fiber<A, E>,
901 fiberId: number | undefined,
902 annotations?: Context.Context<never> | undefined
903 ): Effect.Effect<void>
904} = dual(
905 (args) => hasProperty(args[0], FiberTypeId),
906 <A, E>(
907 self: Fiber.Fiber<A, E>,
908 fiberId: number | undefined,
909 annotations?: Context.Context<never> | undefined
910 ): Effect.Effect<void> =>
911 withFiber((parent) => {
912 let ann = fiberStackAnnotations(parent)
913 ann = ann && annotations ? Context.merge(ann, annotations) : ann ?? annotations
914 self.interruptUnsafe(fiberId, ann)
915 return asVoid(fiberAwait(self))
916 })
917)
918
919/** @internal */
920export const fiberInterruptAll = <A extends Iterable<Fiber.Fiber<any, any>>>(
921 fibers: A
922): Effect.Effect<void> =>
923 withFiber((parent) => {
924 const annotations = fiberStackAnnotations(parent)
925 let fiberArr = Arr.empty<Fiber.Fiber<any, any>>()
926 for (const fiber of fibers) {
927 fiber.interruptUnsafe(parent.id, annotations)
928 fiberArr.push(fiber)
929 }
930 return asVoid(fiberAwaitAll(fiberArr))
931 })
932
933/** @internal */
934export const fiberInterruptAllAs: {
935 (fiberId: number): <A extends Iterable<Fiber.Fiber<any, any>>>(fibers: A) => Effect.Effect<void>
936 <A extends Iterable<Fiber.Fiber<any, any>>>(fibers: A, fiberId: number): Effect.Effect<void>
937} = dual(2, <A extends Iterable<Fiber.Fiber<any, any>>>(
938 fibers: A,
939 fiberId: number
940): Effect.Effect<void> =>
941 withFiber((parent) => {
942 const annotations = fiberStackAnnotations(parent)
943 const fiberArr = Arr.empty<Fiber.Fiber<any, any>>()
944 for (const fiber of fibers) {
945 fiber.interruptUnsafe(fiberId, annotations)
946 fiberArr.push(fiber)
947 }
948 return asVoid(fiberAwaitAll(fiberArr))
949 }))
950
951/** @internal */
952export const succeed: <A>(value: A) => Effect.Effect<A> = exitSucceed
953
954/** @internal */
955export const failCause: <E>(cause: Cause.Cause<E>) => Effect.Effect<never, E> = exitFailCause
956
957/** @internal */
958export const fail: <E>(error: E) => Effect.Effect<never, E> = exitFail
959
960/** @internal */
961export const sync: <A>(thunk: LazyArg<A>) => Effect.Effect<A> = makePrimitive({
962 op: "Sync",
963 [evaluate](fiber): Primitive | Yield {
964 const value = this[args]()
965 const cont = fiber.getCont(contA)
966 return cont ? cont[contA](value, fiber) : fiber.yieldWith(exitSucceed(value))
967 }
968})
969
970/** @internal */
971export const suspend: <A, E, R>(
972 evaluate: LazyArg<Effect.Effect<A, E, R>>
973) => Effect.Effect<A, E, R> = makePrimitive({
974 op: "Suspend",
975 [evaluate](_fiber) {
976 return this[args]()
977 }
978})
979
980/** @internal */
981export const fromOption: <
982 Arg extends Option.Option<unknown> | LazyArg<unknown>,
983 Rest extends [] | [onNone: LazyArg<unknown> | undefined] = []
984>(
985 arg: Arg & (Rest extends [] ? unknown : Option.Option<unknown>),
986 ...rest: Rest
987) => [Arg] extends [Option.Option<infer A>] ? Effect.Effect<
988 A,
989 Rest extends [LazyArg<infer E>] ? E
990 : Rest extends [undefined] ? Cause.NoSuchElementError
991 : Rest extends [LazyArg<infer E> | undefined] ? E | Cause.NoSuchElementError
992 : Cause.NoSuchElementError
993 >
994 : [Arg] extends [LazyArg<infer E>] ? <A>(option: Option.Option<A>) => Effect.Effect<A, E>
995 : never = dual(
996 (args) => args.length >= 2 || Option.isOption(args[0]),
997 <A, E>(option: Option.Option<A>, onNone?: LazyArg<E>): Effect.Effect<A, Cause.NoSuchElementError | E> =>
998 Option.isNone(option)
999 ? fail(onNone ? onNone() : new NoSuchElementError("Effect.fromOption: Option.none"))
1000 : succeed(option.value)
1001 )
1002
1003/** @internal */
1004export const fromResult: <A, E>(result: Result.Result<A, E>) => Effect.Effect<A, E> = Result.match({
1005 onFailure: fail,
1006 onSuccess: succeed
1007})
1008
1009/** @internal */
1010export const fromNullishOr = <A>(value: A): Effect.Effect<NonNullable<A>, Cause.NoSuchElementError> =>
1011 value == null ? fail(new NoSuchElementError()) : succeed(value)
1012
1013/** @internal */
1014export const yieldNowWith: (priority?: number) => Effect.Effect<void> = makePrimitive({
1015 op: "Yield",
1016 [evaluate](fiber) {
1017 let resumed = false
1018 fiber.currentDispatcher.scheduleTask(() => {
1019 if (resumed) return
1020 fiber.evaluate(exitVoid as any)
1021 }, this[args] ?? 0)
1022 return fiber.yieldWith(() => {
1023 resumed = true
1024 })
1025 }
1026})
1027
1028/** @internal */
1029export const yieldNow: Effect.Effect<void> = yieldNowWith(0)
1030
1031/** @internal */
1032export const succeedSome = <A>(a: A): Effect.Effect<Option.Option<A>> => succeed(Option.some(a))
1033
1034/** @internal */
1035export const succeedNone: Effect.Effect<Option.Option<never>> = succeed(
1036 Option.none()
1037)
1038
1039/** @internal */
1040export const transposeOption = <A = never, E = never, R = never>(
1041 self: Option.Option<Effect.Effect<A, E, R>>
1042): Effect.Effect<Option.Option<A>, E, R> => Option.isNone(self) ? succeedNone : map(self.value, Option.some)
1043
1044/** @internal */
1045export const failCauseSync = <E>(
1046 evaluate: LazyArg<Cause.Cause<E>>
1047): Effect.Effect<never, E> => suspend(() => failCause(evaluate()))
1048
1049/** @internal */
1050export const die = (defect: unknown): Effect.Effect<never> => exitDie(defect)
1051
1052/** @internal */
1053export const failSync = <E>(error: LazyArg<E>): Effect.Effect<never, E> => suspend(() => fail(error()))
1054
1055/** @internal */
1056const void_: Effect.Effect<void> = succeed(void 0)
1057/** @internal */
1058export { void_ as void }
1059
1060/** @internal */
1061const try_ = <A, E = Cause.UnknownError>(
1062 options: {
1063 readonly try: LazyArg<A>
1064 readonly catch: (error: unknown) => E
1065 } | LazyArg<A>
1066): Effect.Effect<A, E> => {
1067 const evaluate = typeof options === "function" ? options : options.try
1068 const catcher = typeof options === "function"
1069 ? ((cause: unknown) => new UnknownError(cause, "An error occurred in Effect.try"))
1070 : options.catch
1071 return suspend(() => {
1072 try {
1073 return succeed(evaluate())
1074 } catch (err) {
1075 return fail(catcher(err) as E)
1076 }
1077 })
1078}
1079/** @internal */
1080export { try_ as try }
1081
1082/** @internal */
1083export const promise = <A>(
1084 evaluate: (signal: AbortSignal) => PromiseLike<A>
1085): Effect.Effect<A> =>
1086 callbackOptions<A>(function(resume, signal) {
1087 evaluate(signal!).then(
1088 (a) => resume(succeed(a)),
1089 (e) => resume(die(e))
1090 )
1091 }, evaluate.length !== 0)
1092
1093/** @internal */
1094export const tryPromise = <A, E = Cause.UnknownError>(
1095 options: {
1096 readonly try: (signal: AbortSignal) => PromiseLike<A>
1097 readonly catch: (error: unknown) => E
1098 } | ((signal: AbortSignal) => PromiseLike<A>)
1099): Effect.Effect<A, E> => {
1100 const f = typeof options === "function" ? options : options.try
1101 const catcher = typeof options === "function"
1102 ? ((cause: unknown) => new UnknownError(cause, "An error occurred in Effect.tryPromise"))
1103 : options.catch
1104 return callbackOptions<A, E>(function(resume, signal) {
1105 // Defer the catcher until the fiber restores its async context.
1106 const failWithCatch = (cause: unknown) =>
1107 suspend(() => {
1108 try {
1109 return fail(internalCall(() => catcher(cause)) as E)
1110 } catch (err) {
1111 return die(err)
1112 }
1113 })
1114 try {
1115 f(signal!).then(
1116 (a) => resume(succeed(a)),
1117 (e) => resume(failWithCatch(e))
1118 )
1119 } catch (err) {
1120 resume(failWithCatch(err))
1121 }
1122 }, f.length !== 0)
1123}
1124
1125/** @internal */
1126export const withFiberId = <A, E, R>(
1127 f: (fiberId: number) => Effect.Effect<A, E, R>
1128): Effect.Effect<A, E, R> => withFiber((fiber) => f(fiber.id))
1129
1130/** @internal */
1131export const fiber = withFiber(succeed)
1132
1133/** @internal */
1134export const fiberId = withFiberId(succeed)
1135
1136const callbackOptions: <A, E = never, R = never>(
1137 register: (
1138 this: Scheduler.Scheduler,
1139 resume: (effect: Effect.Effect<A, E, R>) => void,
1140 signal?: AbortSignal
1141 ) => void | Effect.Effect<void, E, R>,
1142 withSignal: boolean
1143) => Effect.Effect<A, E, R> = (function() {
1144 const Proto = makePrimitiveProto({
1145 op: "Async",
1146 [evaluate](this: any, fiber) {
1147 let resumed = false
1148 let yielded: boolean | Primitive = false
1149 const controller = this.withSignal ? new AbortController() : undefined
1150 const onCancel = this.register.call(fiber.cache.scheduler, (effect: Effect.Effect<any, any, any>) => {
1151 if (resumed) return
1152 resumed = true
1153 if (yielded) {
1154 fiber.evaluate(effect as any)
1155 } else {
1156 yielded = effect as any
1157 }
1158 }, controller?.signal)
1159 if (yielded !== false) return yielded
1160 yielded = true
1161 fiber._yielded = () => {
1162 resumed = true
1163 }
1164 if (controller === undefined && onCancel === undefined) {
1165 return Yield
1166 }
1167 fiber._stack.push(
1168 asyncFinalizer(() => {
1169 resumed = true
1170 controller?.abort()
1171 return onCancel ?? exitVoid
1172 })
1173 )
1174 return Yield
1175 }
1176 })
1177 const AsyncImpl = function(this: any, register: any, withSignal: boolean) {
1178 this.register = register
1179 this.withSignal = withSignal
1180 } as unknown as PrimitiveCtor<[register: any, withSignal: boolean]>
1181 AsyncImpl.prototype = Proto
1182 return function(register: any, withSignal: boolean) {
1183 return new AsyncImpl(register, withSignal)
1184 } as any
1185})()
1186
1187const asyncFinalizer: (
1188 onInterrupt: () => Effect.Effect<void, any, any>
1189) => Primitive = makePrimitive({
1190 op: "AsyncFinalizer",
1191 [contAll](fiber) {
1192 if (fiber.interruptible) {
1193 fiber.interruptible = false
1194 fiber._stack.push(setInterruptibleTrue)
1195 }
1196 },
1197 [contE](cause, _fiber) {
1198 return hasInterrupts(cause)
1199 ? flatMap(combineFinalizerCause(exitFailCause(cause), this[args]()), () => failCause(cause))
1200 : failCause(cause)
1201 }
1202})
1203
1204/** @internal */
1205export const callback = <A, E = never, R = never>(
1206 register: (
1207 this: Scheduler.Scheduler,
1208 resume: (effect: Effect.Effect<A, E, R>) => void,
1209 signal: AbortSignal
1210 ) => void | Effect.Effect<void, E, R>
1211): Effect.Effect<A, E, R> => callbackOptions(register as any, register.length >= 2)
1212
1213/** @internal */
1214export const never: Effect.Effect<never> = callback<never>(constVoid)
1215
1216/** @internal */
1217export const gen = <
1218 Self,
1219 Eff extends Effect.Effect<any, any, any>,
1220 AEff
1221>(
1222 ...args:
1223 | [options: { readonly self: Self }, body: (this: Self) => Generator<Eff, AEff, never>]
1224 | [body: () => Generator<Eff, AEff, never>]
1225): Effect.Effect<
1226 AEff,
1227 [Eff] extends [never] ? never
1228 : [Eff] extends [Effect.Effect<infer _A, infer E, infer _R>] ? E
1229 : never,
1230 [Eff] extends [never] ? never
1231 : [Eff] extends [Effect.Effect<infer _A, infer _E, infer R>] ? R
1232 : never
1233> => {
1234 if (args.length === 1) {
1235 const body = args[0]
1236 return suspend(() => fromIteratorUnsafe(body()))
1237 }
1238 const [options, body] = args
1239 return suspend(() => fromIteratorUnsafe(body.call(options.self) as any))
1240}
1241
1242/** @internal */
1243export const fnUntraced: Effect.fn.Untraced = (
1244 body: Function,
1245 ...pipeables: Array<any>
1246) => {
1247 const fn = pipeables.length === 0
1248 ? function(this: any) {
1249 return suspend(() => fromIteratorUnsafe(body.apply(this, arguments)))
1250 }
1251 : function(this: any) {
1252 let effect = suspend(() => fromIteratorUnsafe(body.apply(this, arguments)))
1253 for (let i = 0; i < pipeables.length; i++) {
1254 effect = pipeables[i](effect, ...arguments)
1255 }
1256 return effect
1257 }
1258 return defineFunctionLength(body.length, fn)
1259}
1260
1261const defineFunctionLength = <F extends Function>(length: number, fn: F): F =>
1262 Object.defineProperty(fn, "length", {
1263 value: length,
1264 configurable: true
1265 })
1266
1267const fnStackCleaner = makeStackCleaner(2)
1268
1269/** @internal */
1270export const fn: typeof Effect.fn = function() {
1271 const nameFirst = typeof arguments[0] === "string"
1272 const name = nameFirst ? arguments[0] : "Effect.fn"
1273 const spanOptions = nameFirst ? arguments[1] : undefined
1274
1275 const prevLimit = getStackTraceLimit()
1276 let defError: Error | undefined
1277 if (prevLimit !== 0) {
1278 setStackTraceLimit(2)
1279 defError = new globalThis.Error()
1280 setStackTraceLimit(prevLimit)
1281 }
1282
1283 if (nameFirst) {
1284 return (body: Function | { readonly self: any }, ...pipeables: Array<Function>) =>
1285 makeFn(name, body, defError, pipeables, nameFirst, spanOptions)
1286 }
1287
1288 return makeFn(
1289 name,
1290 arguments[0],
1291 defError,
1292 Array.prototype.slice.call(arguments, 1),
1293 nameFirst,
1294 spanOptions
1295 )
1296} as any
1297
1298const makeFn = (
1299 name: string,
1300 bodyOrOptions: Function | { readonly self: any },
1301 defError: Error | undefined,
1302 pipeables: Array<Function>,
1303 addSpan: boolean,
1304 spanOptions: Tracer.SpanOptionsNoTrace | undefined
1305) => {
1306 const body = typeof bodyOrOptions === "function"
1307 ? bodyOrOptions
1308 : (pipeables.shift()!).bind(bodyOrOptions.self)
1309 const definitionName = `${name} (definition)`
1310 const definitionStack = defError ? fnStackCleaner(() => defError.stack) : constUndefined
1311
1312 return defineFunctionLength(body.length, function(this: any, ...args: Array<any>) {
1313 let result = suspend(() => {
1314 const iter = body.apply(this, arguments)
1315 return isEffect(iter) ? iter : fromIteratorUnsafe(iter)
1316 })
1317 for (let i = 0; i < pipeables.length; i++) {
1318 result = pipeables[i](result, ...args)
1319 }
1320 if (!isEffect(result)) {
1321 return result
1322 }
1323 const prevLimit = getStackTraceLimit()
1324 let callError: Error | undefined
1325 if (prevLimit !== 0) {
1326 setStackTraceLimit(2)
1327 callError = new globalThis.Error()
1328 setStackTraceLimit(prevLimit)
1329 }
1330 return updateService(
1331 addSpan ?
1332 useSpan(name, spanOptions!, (span) => provideParentSpan(result, span)) :
1333 result,
1334 CurrentStackFrame,
1335 (prev) => ({
1336 name,
1337 stack: callError ? fnStackCleaner(() => callError.stack) : constUndefined,
1338 parent: {
1339 name: definitionName,
1340 stack: definitionStack,
1341 parent: prev
1342 }
1343 })
1344 )
1345 })
1346}
1347
1348/** @internal */
1349export const fnUntracedEager: Effect.fn.Untraced = (
1350 body: Function,
1351 ...pipeables: Array<any>
1352) =>
1353 defineFunctionLength(
1354 body.length,
1355 pipeables.length === 0
1356 ? function(this: any) {
1357 return fromIteratorEagerUnsafe(() => body.apply(this, arguments))
1358 }
1359 : function(this: any) {
1360 let effect = fromIteratorEagerUnsafe(() => body.apply(this, arguments))
1361 for (const pipeable of pipeables) {
1362 effect = pipeable(effect, ...arguments)
1363 }
1364 return effect
1365 }
1366 )
1367
1368const fromIteratorEagerUnsafe = (
1369 evaluate: () => Iterator<Effect.Effect<any, any, any>>
1370): Effect.Effect<any, any, any> => {
1371 try {
1372 const iterator = evaluate()
1373 let value: any = undefined
1374
1375 // Try to resolve synchronously in a loop
1376 while (true) {
1377 const state = iterator.next(value)
1378
1379 if (state.done) {
1380 return succeed(state.value)
1381 }
1382
1383 const primitive = state.value as any
1384
1385 if (primitive && primitive._tag === "Success") {
1386 value = primitive.value
1387 continue
1388 } else if (primitive && primitive._tag === "Failure") {
1389 return state.value
1390 } else {
1391 let isFirstExecution = true
1392
1393 return suspend(() => {
1394 if (isFirstExecution) {
1395 isFirstExecution = false
1396 return flatMap(state.value, (value) => fromIteratorUnsafe(iterator, value))
1397 } else {
1398 return suspend(() => fromIteratorUnsafe(evaluate()))
1399 }
1400 })
1401 }
1402 }
1403 } catch (error) {
1404 return die(error)
1405 }
1406}
1407
1408const fromIteratorUnsafe: (
1409 iterator: Iterator<Effect.Effect<any, any, any>>,
1410 initial?: undefined
1411) => Effect.Effect<any, any, any> = (function() {
1412 const Proto = makePrimitiveProto({
1413 op: "Iterator",
1414 [contA](this: any, value, fiber) {
1415 const iter = this.iterator
1416 while (true) {
1417 const state = iter.next(value)
1418 if (state.done) return succeed(state.value)
1419 if (!effectIsExit(state.value)) {
1420 fiber._stack.push(this)
1421 return state.value
1422 } else if (state.value._tag === "Failure") {
1423 return state.value
1424 }
1425 value = state.value.value
1426 }
1427 },
1428 [evaluate](this: any, fiber: FiberImpl) {
1429 return this[contA](this.initial, fiber)
1430 }
1431 })
1432 const IteratorImpl = function(this: any, iterator: any, initial: any) {
1433 this.iterator = iterator
1434 this.initial = initial
1435 } as unknown as PrimitiveCtor<[iterator: any, initial: any]>
1436 IteratorImpl.prototype = Proto
1437 return function(iterator: any, initial?: undefined) {
1438 return new IteratorImpl(iterator, initial)
1439 } as any
1440})()
1441
1442// ----------------------------------------------------------------------------
1443// mapping & sequencing
1444// ----------------------------------------------------------------------------
1445
1446/** @internal */
1447export const as: {
1448 <A, B>(
1449 value: B
1450 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E, R>
1451 <A, E, R, B>(self: Effect.Effect<A, E, R>, value: B): Effect.Effect<B, E, R>
1452} = dual(
1453 2,
1454 <A, E, R, B>(
1455 self: Effect.Effect<A, E, R>,
1456 value: B
1457 ): Effect.Effect<B, E, R> => new ContImpl(self, returnPayload, succeed(value))
1458)
1459
1460const evaluateCont = function(this: any, fiber: FiberImpl): Primitive {
1461 fiber._stack.push(this)
1462 return this[args]
1463}
1464
1465interface PrimitiveCtor<Args extends Array<any>> {
1466 new(...args: Args): Primitive & Effect.Effect<any, any, any>
1467 prototype: any
1468}
1469
1470const OnSuccessProto = makePrimitiveProto({
1471 op: "OnSuccess",
1472 [evaluate]: evaluateCont
1473})
1474
1475// A success continuation with an extra payload slot. The stored continuation
1476// receives the primitive as `this` and reads `this.payload`, so combinators
1477// like map / as / tap / andThen / flatMap can share module-level continuation
1478// functions instead of allocating a closure per call.
1479const ContImpl = function(
1480 this: any,
1481 self: Effect.Effect<any, any, any>,
1482 cont: (this: { readonly payload: any }, value: any, fiber: FiberImpl) => unknown,
1483 payload: unknown
1484) {
1485 this[args] = self
1486 this[contA] = cont
1487 this.payload = payload
1488} as unknown as PrimitiveCtor<
1489 [
1490 self: Effect.Effect<any, any, any>,
1491 cont: (this: { readonly payload: any }, value: any, fiber: FiberImpl) => unknown,
1492 payload: unknown
1493 ]
1494>
1495ContImpl.prototype = OnSuccessProto
1496
1497const returnPayload = function(this: { readonly payload: any }) {
1498 return this.payload
1499}
1500const succeedPayload = function(this: { readonly payload: any }, _value: unknown, fiber: FiberImpl) {
1501 return fiber.succeedWith(this.payload)
1502}
1503// V8 includes the property name of a stored continuation in its stack trace.
1504// Other engines need an explicit frame for the stack cleaner to cut at.
1505const continuationMarksStack = (() => {
1506 const marker = "~effect/Effect/stackProbe"
1507 const probe = {
1508 [marker]: function stackProbe() {
1509 return new Error().stack
1510 }
1511 }
1512 return probe[marker]()?.includes("[as " + marker + "]") === true
1513})()
1514const mapCont = function(this: { readonly payload: any }, value: any, fiber: FiberImpl) {
1515 const f = this.payload
1516 return fiber.succeedWith(continuationMarksStack ? f(value) : internalCall(() => f(value)))
1517}
1518const andThenCont = function(this: { readonly payload: any }, value: any) {
1519 const f = this.payload
1520 return f(value)
1521}
1522const tapCont = function(this: { readonly payload: any }, value: any) {
1523 const f = this.payload
1524 return new ContImpl(f(value), succeedPayload, value)
1525}
1526const tapEffectCont = function(this: { readonly payload: any }, value: any) {
1527 return new ContImpl(this.payload, succeedPayload, value)
1528}
1529
1530/** @internal */
1531export const asSome = <A, E, R>(
1532 self: Effect.Effect<A, E, R>
1533): Effect.Effect<Option.Option<A>, E, R> => map(self, Option.some)
1534
1535/** @internal */
1536export const flip = <A, E, R>(
1537 self: Effect.Effect<A, E, R>
1538): Effect.Effect<E, A, R> =>
1539 matchEffect(self, {
1540 onFailure: succeed,
1541 onSuccess: fail
1542 })
1543
1544/** @internal */
1545export const andThen: {
1546 <A, B, E2, R2>(
1547 f: (a: A) => Effect.Effect<B, E2, R2>
1548 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E | E2, R | R2>
1549 <B, E2, R2>(
1550 f: Effect.Effect<B, E2, R2>
1551 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E | E2, R | R2>
1552 <A, E, R, B, E2, R2>(
1553 self: Effect.Effect<A, E, R>,
1554 f: (a: A) => Effect.Effect<B, E2, R2>
1555 ): Effect.Effect<B, E | E2, R | R2>
1556 <A, E, R, B, E2, R2>(
1557 self: Effect.Effect<A, E, R>,
1558 f: Effect.Effect<B, E2, R2>
1559 ): Effect.Effect<B, E | E2, R | R2>
1560} = dual(
1561 2,
1562 <A, E, R, B, E2, R2>(
1563 self: Effect.Effect<A, E, R>,
1564 f: ((a: A) => Effect.Effect<B, E2, R2>) | Effect.Effect<B, E2, R2>
1565 ): Effect.Effect<B, E | E2, R | R2> => new ContImpl(self, isEffect(f) ? returnPayload : andThenCont, f)
1566)
1567
1568/** @internal */
1569export const tap: {
1570 <A, B, E2, R2>(
1571 f: (a: NoInfer<A>) => Effect.Effect<B, E2, R2>
1572 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2>
1573 <B, E2, R2>(
1574 f: Effect.Effect<B, E2, R2>
1575 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2>
1576 <A, E, R, B, E2, R2>(
1577 self: Effect.Effect<A, E, R>,
1578 f: (a: NoInfer<A>) => Effect.Effect<B, E2, R2>
1579 ): Effect.Effect<A, E | E2, R | R2>
1580 <A, E, R, B, E2, R2>(
1581 self: Effect.Effect<A, E, R>,
1582 f: Effect.Effect<B, E2, R2>
1583 ): Effect.Effect<A, E | E2, R | R2>
1584} = dual(
1585 2,
1586 <A, E, R, B, E2, R2>(
1587 self: Effect.Effect<A, E, R>,
1588 f: ((a: A) => Effect.Effect<B, E2, R2>) | Effect.Effect<B, E2, R2>
1589 ): Effect.Effect<A, E | E2, R | R2> => new ContImpl(self, isEffect(f) ? tapEffectCont : tapCont, f)
1590)
1591
1592/** @internal */
1593export const asVoid = <A, E, R>(
1594 self: Effect.Effect<A, E, R>
1595): Effect.Effect<void, E, R> => new ContImpl(self, returnPayload, exitVoid)
1596
1597/** @internal */
1598export const sandbox = <A, E, R>(
1599 self: Effect.Effect<A, E, R>
1600): Effect.Effect<A, Cause.Cause<E>, R> => catchCause(self, fail)
1601
1602/** @internal */
1603export const raceAll = <Eff extends Effect.Effect<any, any, any>>(
1604 all: Iterable<Eff>,
1605 options?: {
1606 readonly onWinner?: (options: {
1607 readonly fiber: Fiber.Fiber<any, any>
1608 readonly index: number
1609 readonly parentFiber: Fiber.Fiber<any, any>
1610 }) => void
1611 }
1612): Effect.Effect<
1613 Effect.Success<Eff>,
1614 Effect.Error<Eff>,
1615 Effect.Services<Eff>
1616> =>
1617 withFiber((parent) => {
1618 const fibers = new Set<Fiber.Fiber<any, any>>()
1619 // Read fibers on exit to include losers forked after the race settles.
1620 onExitUnsafe(parent, () => fibers.size === 0 ? undefined : fiberInterruptAll(fibers))
1621 return callback((resume) => {
1622 const effects = Arr.fromIterable(all)
1623 const len = effects.length
1624 let doneCount = 0
1625 let done = false
1626 const failures: Array<Cause.Reason<any>> = []
1627 const onExit = (exit: Exit.Exit<any, any>, fiber: Fiber.Fiber<any, any>, i: number) => {
1628 doneCount++
1629 if (exit._tag === "Failure") {
1630 failures.push(...exit.cause.reasons)
1631 if (doneCount >= len) {
1632 resume(failCause(causeFromReasons(failures)))
1633 }
1634 return
1635 }
1636 const isWinner = !done
1637 done = true
1638 resume(exit)
1639 if (isWinner && options?.onWinner) {
1640 options.onWinner({ fiber, index: i, parentFiber: parent })
1641 }
1642 }
1643
1644 for (let i = 0; i < len; i++) {
1645 const fiber = forkUnsafe(parent, effects[i], true, true, false)
1646 fibers.add(fiber)
1647 fiber.addObserver((exit) => {
1648 fibers.delete(fiber)
1649 onExit(exit, fiber, i)
1650 })
1651 if (done) break
1652 }
1653 })
1654 })
1655
1656/** @internal */
1657export const raceAllFirst = <Eff extends Effect.Effect<any, any, any>>(
1658 all: Iterable<Eff>,
1659 options?: {
1660 readonly onWinner?: (options: {
1661 readonly fiber: Fiber.Fiber<any, any>
1662 readonly index: number
1663 readonly parentFiber: Fiber.Fiber<any, any>
1664 }) => void
1665 }
1666): Effect.Effect<
1667 Effect.Success<Eff>,
1668 Effect.Error<Eff>,
1669 Effect.Services<Eff>
1670> =>
1671 withFiber((parent) => {
1672 const fibers = new Set<Fiber.Fiber<any, any>>()
1673 onExitUnsafe(parent, () => fibers.size === 0 ? undefined : fiberInterruptAll(fibers))
1674 return callback((resume) => {
1675 let done = false
1676 let i = 0
1677 for (const effect of all) {
1678 if (done) break
1679 const index = i++
1680 const fiber = forkUnsafe(parent, effect, true, true, false)
1681 fibers.add(fiber)
1682 fiber.addObserver((exit) => {
1683 fibers.delete(fiber)
1684 const isWinner = !done
1685 done = true
1686 resume(exit)
1687 if (isWinner && options?.onWinner) {
1688 options.onWinner({ fiber, index, parentFiber: parent })
1689 }
1690 })
1691 }
1692 })
1693 })
1694
1695/** @internal */
1696export const race: {
1697 <A2, E2, R2>(
1698 that: Effect.Effect<A2, E2, R2>,
1699 options?: {
1700 readonly onWinner?: (options: {
1701 readonly fiber: Fiber.Fiber<any, any>
1702 readonly index: number
1703 readonly parentFiber: Fiber.Fiber<any, any>
1704 }) => void
1705 }
1706 ): <A, E, R>(
1707 self: Effect.Effect<A, E, R>
1708 ) => Effect.Effect<A | A2, E | E2, R | R2>
1709 <A, E, R, A2, E2, R2>(
1710 self: Effect.Effect<A, E, R>,
1711 that: Effect.Effect<A2, E2, R2>,
1712 options?: {
1713 readonly onWinner?: (options: {
1714 readonly fiber: Fiber.Fiber<any, any>
1715 readonly index: number
1716 readonly parentFiber: Fiber.Fiber<any, any>
1717 }) => void
1718 }
1719 ): Effect.Effect<A | A2, E | E2, R | R2>
1720} = dual(
1721 (args) => isEffect(args[1]),
1722 <A, E, R, A2, E2, R2>(
1723 self: Effect.Effect<A, E, R>,
1724 that: Effect.Effect<A2, E2, R2>,
1725 options?: {
1726 readonly onWinner?: (options: {
1727 readonly fiber: Fiber.Fiber<any, any>
1728 readonly index: number
1729 readonly parentFiber: Fiber.Fiber<any, any>
1730 }) => void
1731 }
1732 ): Effect.Effect<A | A2, E | E2, R | R2> => raceAll([self, that], options)
1733)
1734
1735/** @internal */
1736export const raceFirst: {
1737 <A2, E2, R2>(
1738 that: Effect.Effect<A2, E2, R2>,
1739 options?: {
1740 readonly onWinner?: (options: {
1741 readonly fiber: Fiber.Fiber<any, any>
1742 readonly index: number
1743 readonly parentFiber: Fiber.Fiber<any, any>
1744 }) => void
1745 }
1746 ): <A, E, R>(
1747 self: Effect.Effect<A, E, R>
1748 ) => Effect.Effect<A | A2, E | E2, R | R2>
1749 <A, E, R, A2, E2, R2>(
1750 self: Effect.Effect<A, E, R>,
1751 that: Effect.Effect<A2, E2, R2>,
1752 options?: {
1753 readonly onWinner?: (options: {
1754 readonly fiber: Fiber.Fiber<any, any>
1755 readonly index: number
1756 readonly parentFiber: Fiber.Fiber<any, any>
1757 }) => void
1758 }
1759 ): Effect.Effect<A | A2, E | E2, R | R2>
1760} = dual(
1761 (args) => isEffect(args[1]),
1762 <A, E, R, A2, E2, R2>(
1763 self: Effect.Effect<A, E, R>,
1764 that: Effect.Effect<A2, E2, R2>,
1765 options?: {
1766 readonly onWinner?: (options: {
1767 readonly fiber: Fiber.Fiber<any, any>
1768 readonly index: number
1769 readonly parentFiber: Fiber.Fiber<any, any>
1770 }) => void
1771 }
1772 ): Effect.Effect<A | A2, E | E2, R | R2> => raceAllFirst([self, that], options)
1773)
1774
1775/** @internal */
1776export const flatMap: {
1777 <A, B, E2, R2>(
1778 f: (a: A) => Effect.Effect<B, E2, R2>
1779 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E | E2, R | R2>
1780 <A, E, R, B, E2, R2>(
1781 self: Effect.Effect<A, E, R>,
1782 f: (a: A) => Effect.Effect<B, E2, R2>
1783 ): Effect.Effect<B, E | E2, R | R2>
1784} = dual(
1785 2,
1786 <A, E, R, B, E2, R2>(
1787 self: Effect.Effect<A, E, R>,
1788 f: (a: A) => Effect.Effect<B, E2, R2>
1789 ): Effect.Effect<B, E | E2, R | R2> => new ContImpl(self, andThenCont, f)
1790)
1791
1792/** @internal */
1793export const matchCauseEffectEager: {
1794 <E, A2, E2, R2, A, A3, E3, R3>(options: {
1795 readonly onFailure: (cause: Cause.Cause<E>) => Effect.Effect<A2, E2, R2>
1796 readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3>
1797 }): <R>(
1798 self: Effect.Effect<A, E, R>
1799 ) => Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R>
1800 <A, E, R, A2, E2, R2, A3, E3, R3>(
1801 self: Effect.Effect<A, E, R>,
1802 options: {
1803 readonly onFailure: (cause: Cause.Cause<E>) => Effect.Effect<A2, E2, R2>
1804 readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3>
1805 }
1806 ): Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R>
1807} = dual(
1808 2,
1809 <A, E, R, A2, E2, R2, A3, E3, R3>(
1810 self: Effect.Effect<A, E, R>,
1811 options: {
1812 readonly onFailure: (cause: Cause.Cause<E>) => Effect.Effect<A2, E2, R2>
1813 readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3>
1814 }
1815 ): Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R> => {
1816 if (effectIsExit(self)) {
1817 return self._tag === "Success"
1818 ? options.onSuccess(self.value)
1819 : options.onFailure(self.cause)
1820 }
1821 return matchCauseEffect(self, options)
1822 }
1823)
1824
1825/** @internal */
1826export const effectIsExit = <A, E, R>(effect: Effect.Effect<A, E, R>): effect is Exit.Exit<A, E> =>
1827 (effect as any)[ExitTypeId] !== undefined
1828
1829/** @internal */
1830export const flatMapEager: {
1831 <A, B, E2, R2>(
1832 f: (a: A) => Effect.Effect<B, E2, R2>
1833 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E | E2, R | R2>
1834 <A, E, R, B, E2, R2>(
1835 self: Effect.Effect<A, E, R>,
1836 f: (a: A) => Effect.Effect<B, E2, R2>
1837 ): Effect.Effect<B, E | E2, R | R2>
1838} = dual(
1839 2,
1840 <A, E, R, B, E2, R2>(
1841 self: Effect.Effect<A, E, R>,
1842 f: (a: A) => Effect.Effect<B, E2, R2>
1843 ): Effect.Effect<B, E | E2, R | R2> => {
1844 if (effectIsExit(self)) {
1845 return self._tag === "Success" ? f(self.value) : self as Exit.Exit<never, E>
1846 }
1847 return flatMap(self, f)
1848 }
1849)
1850
1851// ----------------------------------------------------------------------------
1852// mapping & sequencing
1853// ----------------------------------------------------------------------------
1854
1855/** @internal */
1856export const flatten = <A, E, R, E2, R2>(
1857 self: Effect.Effect<Effect.Effect<A, E, R>, E2, R2>
1858): Effect.Effect<A, E | E2, R | R2> => flatMap(self, identity)
1859
1860/** @internal */
1861export const map: {
1862 <A, B>(
1863 f: (a: A) => B
1864 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E, R>
1865 <A, E, R, B>(
1866 self: Effect.Effect<A, E, R>,
1867 f: (a: A) => B
1868 ): Effect.Effect<B, E, R>
1869} = dual(
1870 2,
1871 <A, E, R, B>(
1872 self: Effect.Effect<A, E, R>,
1873 f: (a: A) => B
1874 ): Effect.Effect<B, E, R> => new ContImpl(self, mapCont, f)
1875)
1876
1877/** @internal */
1878export const mapEager: {
1879 <A, B>(
1880 f: (a: A) => B
1881 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E, R>
1882 <A, E, R, B>(
1883 self: Effect.Effect<A, E, R>,
1884 f: (a: A) => B
1885 ): Effect.Effect<B, E, R>
1886} = dual(
1887 2,
1888 <A, E, R, B>(
1889 self: Effect.Effect<A, E, R>,
1890 f: (a: A) => B
1891 ): Effect.Effect<B, E, R> => effectIsExit(self) ? exitMap(self, f) : map(self, f)
1892)
1893
1894/** @internal */
1895export const mapErrorEager: {
1896 <E, E2>(
1897 f: (e: E) => E2
1898 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E2, R>
1899 <A, E, R, E2>(
1900 self: Effect.Effect<A, E, R>,
1901 f: (e: E) => E2
1902 ): Effect.Effect<A, E2, R>
1903} = dual(
1904 2,
1905 <A, E, R, E2>(
1906 self: Effect.Effect<A, E, R>,
1907 f: (e: E) => E2
1908 ): Effect.Effect<A, E2, R> => effectIsExit(self) ? exitMapError(self, f) : mapError(self, f)
1909)
1910
1911/** @internal */
1912export const mapBothEager: {
1913 <E, E2, A, A2>(
1914 options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 }
1915 ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A2, E2, R>
1916 <A, E, R, E2, A2>(
1917 self: Effect.Effect<A, E, R>,
1918 options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 }
1919 ): Effect.Effect<A2, E2, R>
1920} = dual(
1921 2,
1922 <A, E, R, E2, A2>(
1923 self: Effect.Effect<A, E, R>,
1924 options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 }
1925 ): Effect.Effect<A2, E2, R> => effectIsExit(self) ? exitMapBoth(self, options) : mapBoth(self, options)
1926)
1927
1928/** @internal */
1929export const catchEager: {
1930 <E, B, E2, R2>(
1931 f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2>
1932 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A | B, E2, R | R2>
1933 <A, E, R, B, E2, R2>(
1934 self: Effect.Effect<A, E, R>,
1935 f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2>
1936 ): Effect.Effect<A | B, E2, R | R2>
1937} = dual(
1938 2,
1939 <A, E, R, B, E2, R2>(
1940 self: Effect.Effect<A, E, R>,
1941 f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2>
1942 ): Effect.Effect<A | B, E2, R | R2> => {
1943 if (effectIsExit(self)) {
1944 if (self._tag === "Success") return self as Exit.Exit<A>
1945 const error = findError(self.cause)
1946 if (Result.isFailure(error)) return self as Exit.Exit<never>
1947 return f(error.success)
1948 }
1949 return catch_(self, f)
1950 }
1951)
1952
1953// ----------------------------------------------------------------------------
1954// Exit
1955// ----------------------------------------------------------------------------
1956
1957/** @internal */
1958export const exitInterrupt = (fiberId?: number | undefined): Exit.Exit<never> => exitFailCause(causeInterrupt(fiberId))
1959
1960/** @internal */
1961export const exitIsSuccess = <A, E>(
1962 self: Exit.Exit<A, E>
1963): self is Exit.Success<A, E> => self._tag === "Success"
1964
1965/** @internal */
1966export const exitFilterSuccess = <A, E>(
1967 self: Exit.Exit<A, E>
1968): Result.Result<Exit.Success<A>, Exit.Failure<never, E>> =>
1969 self._tag === "Success" ? Result.succeed(self as any) : Result.fail(self as any)
1970
1971/** @internal */
1972export const exitFilterValue = <A, E>(
1973 self: Exit.Exit<A, E>
1974): Result.Result<A, Exit.Failure<never, E>> =>
1975 self._tag === "Success" ? Result.succeed(self.value) : Result.fail(self as any)
1976
1977/** @internal */
1978export const exitIsFailure = <A, E>(
1979 self: Exit.Exit<A, E>
1980): self is Exit.Failure<A, E> => self._tag === "Failure"
1981
1982/** @internal */
1983export const exitFilterFailure = <A, E>(
1984 self: Exit.Exit<A, E>
1985): Result.Result<Exit.Failure<never, E>, Exit.Success<A>> =>
1986 self._tag === "Failure" ? Result.succeed(self as any) : Result.fail(self as any)
1987
1988/** @internal */
1989export const exitFilterCause = <A, E>(
1990 self: Exit.Exit<A, E>
1991): Result.Result<Cause.Cause<E>, Exit.Success<A>> =>
1992 self._tag === "Failure" ? Result.succeed(self.cause) : Result.fail(self as any)
1993
1994/** @internal */
1995export const exitFindError = Filter.composePassthrough(
1996 exitFilterCause,
1997 findError
1998)
1999
2000/** @internal */
2001export const exitFindDefect = Filter.composePassthrough(
2002 exitFilterCause,
2003 findDefect
2004)
2005
2006/** @internal */
2007export const exitHasInterrupts = <A, E>(
2008 self: Exit.Exit<A, E>
2009): self is Exit.Failure<A, E> => self._tag === "Failure" && hasInterrupts(self.cause)
2010
2011/** @internal */
2012export const exitHasDies = <A, E>(
2013 self: Exit.Exit<A, E>
2014): self is Exit.Failure<A, E> => self._tag === "Failure" && hasDies(self.cause)
2015
2016/** @internal */
2017export const exitHasFails = <A, E>(
2018 self: Exit.Exit<A, E>
2019): self is Exit.Failure<A, E> => self._tag === "Failure" && hasFails(self.cause)
2020
2021/** @internal */
2022export const exitVoid: Exit.Exit<void> = exitSucceed(void 0)
2023
2024/** @internal */
2025export const exitMap: {
2026 <A, B>(f: (a: A) => B): <E>(self: Exit.Exit<A, E>) => Exit.Exit<B, E>
2027 <A, E, B>(self: Exit.Exit<A, E>, f: (a: A) => B): Exit.Exit<B, E>
2028} = dual(
2029 2,
2030 <A, E, B>(self: Exit.Exit<A, E>, f: (a: A) => B): Exit.Exit<B, E> =>
2031 self._tag === "Success" ? exitSucceed(f(self.value)) : (self as any)
2032)
2033
2034/** @internal */
2035export const exitMapError: {
2036 <E, E2>(f: (a: NoInfer<E>) => E2): <A>(self: Exit.Exit<A, E>) => Exit.Exit<A, E2>
2037 <A, E, E2>(self: Exit.Exit<A, E>, f: (a: NoInfer<E>) => E2): Exit.Exit<A, E2>
2038} = dual(
2039 2,
2040 <A, E, E2>(self: Exit.Exit<A, E>, f: (a: NoInfer<E>) => E2): Exit.Exit<A, E2> => {
2041 if (self._tag === "Success") return self as Exit.Exit<A>
2042 const error = findError(self.cause)
2043 if (Result.isFailure(error)) return self as Exit.Exit<never>
2044 return exitFail(f(error.success))
2045 }
2046)
2047
2048/** @internal */
2049export const exitMapBoth: {
2050 <E, E2, A, A2>(
2051 options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 }
2052 ): (self: Exit.Exit<A, E>) => Exit.Exit<A2, E2>
2053 <A, E, E2, A2>(
2054 self: Exit.Exit<A, E>,
2055 options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 }
2056 ): Exit.Exit<A2, E2>
2057} = dual(
2058 2,
2059 <A, E, E2, A2>(
2060 self: Exit.Exit<A, E>,
2061 options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 }
2062 ): Exit.Exit<A2, E2> => {
2063 if (self._tag === "Success") return exitSucceed(options.onSuccess(self.value))
2064 const error = findError(self.cause)
2065 if (Result.isFailure(error)) return self as Exit.Exit<never>
2066 return exitFail(options.onFailure(error.success))
2067 }
2068)
2069
2070/** @internal */
2071export const exitAs: {
2072 <B>(b: B): <A, E>(self: Exit.Exit<A, E>) => Exit.Exit<B, E>
2073 <A, E, B>(self: Exit.Exit<A, E>, b: B): Exit.Exit<B, E>
2074} = dual(
2075 2,
2076 <A, E, B>(self: Exit.Exit<A, E>, b: B): Exit.Exit<B, E> => exitIsSuccess(self) ? exitSucceed(b) : (self as any)
2077)
2078
2079/** @internal */
2080export const exitZipRight: {
2081 <A2, E2>(
2082 that: Exit.Exit<A2, E2>
2083 ): <A, E>(self: Exit.Exit<A, E>) => Exit.Exit<A2, E | E2>
2084 <A, E, A2, E2>(
2085 self: Exit.Exit<A, E>,
2086 that: Exit.Exit<A2, E2>
2087 ): Exit.Exit<A2, E | E2>
2088} = dual(
2089 2,
2090 <A, E, A2, E2>(
2091 self: Exit.Exit<A, E>,
2092 that: Exit.Exit<A2, E2>
2093 ): Exit.Exit<A2, E | E2> => (exitIsSuccess(self) ? that : (self as any))
2094)
2095
2096/** @internal */
2097export const exitMatch: {
2098 <A, E, X1, X2>(options: {
2099 readonly onSuccess: (a: NoInfer<A>) => X1
2100 readonly onFailure: (cause: Cause.Cause<NoInfer<E>>) => X2
2101 }): (self: Exit.Exit<A, E>) => X1 | X2
2102 <A, E, X1, X2>(
2103 self: Exit.Exit<A, E>,
2104 options: {
2105 readonly onSuccess: (a: A) => X1
2106 readonly onFailure: (cause: Cause.Cause<E>) => X2
2107 }
2108 ): X1 | X2
2109} = dual(
2110 2,
2111 <A, E, X1, X2>(
2112 self: Exit.Exit<A, E>,
2113 options: {
2114 readonly onSuccess: (a: A) => X1
2115 readonly onFailure: (cause: Cause.Cause<E>) => X2
2116 }
2117 ): X1 | X2 =>
2118 exitIsSuccess(self)
2119 ? options.onSuccess(self.value)
2120 : options.onFailure(self.cause)
2121)
2122
2123/** @internal */
2124export const exitAsVoid: <A, E>(self: Exit.Exit<A, E>) => Exit.Exit<void, E> = exitAs(void 0)
2125
2126/** @internal */
2127export const exitAsVoidAll = <I extends Iterable<Exit.Exit<any, any>>>(
2128 exits: I
2129): Exit.Exit<
2130 void,
2131 I extends Iterable<Exit.Exit<infer _A, infer _E>> ? _E : never
2132> => {
2133 const failures: Array<Cause.Reason<any>> = []
2134 for (const exit of exits) {
2135 if (exit._tag === "Failure") {
2136 failures.push(...exit.cause.reasons)
2137 }
2138 }
2139 return failures.length === 0 ? exitVoid : exitFailCause(causeFromReasons(failures))
2140}
2141
2142/** @internal */
2143export const exitGetSuccess = <A, E>(self: Exit.Exit<A, E>): Option.Option<A> =>
2144 exitIsSuccess(self) ? Option.some(self.value) : Option.none()
2145
2146/** @internal */
2147export const exitGetCause = <A, E>(self: Exit.Exit<A, E>): Option.Option<Cause.Cause<E>> =>
2148 exitIsFailure(self) ? Option.some(self.cause) : Option.none()
2149
2150/** @internal */
2151export const exitFindErrorOption = <A, E>(self: Exit.Exit<A, E>): Option.Option<E> => {
2152 const error = exitFindError(self)
2153 return Result.isFailure(error) ? Option.none() : Option.some(error.success)
2154}
2155
2156// ----------------------------------------------------------------------------
2157// environment
2158// ----------------------------------------------------------------------------
2159
2160/** @internal */
2161export const service = <I, S>(service: Context.Key<I, S>): Effect.Effect<S, never, I> => service
2162
2163/** @internal */
2164export const serviceOption = <I, S>(
2165 service: Context.Key<I, S>
2166): Effect.Effect<Option.Option<S>> => withFiber((fiber) => succeed(Context.getOption(fiber.context, service)))
2167
2168/** @internal */
2169export const serviceOptional = <I, S>(
2170 service: Context.Key<I, S>
2171): Effect.Effect<S, Cause.NoSuchElementError> =>
2172 withFiber((fiber) => fromOption(Context.getOption(fiber.context, service)))
2173
2174/** @internal */
2175export const updateContext: {
2176 <R2, R>(
2177 f: (context: Context.Context<R2>) => Context.Context<NoInfer<R>>
2178 ): <A, E>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R2>
2179 <A, E, R, R2>(
2180 self: Effect.Effect<A, E, R>,
2181 f: (context: Context.Context<R2>) => Context.Context<NoInfer<R>>
2182 ): Effect.Effect<A, E, R2>
2183} = dual(
2184 2,
2185 <A, E, R, R2>(
2186 self: Effect.Effect<A, E, R>,
2187 f: (context: Context.Context<R2>) => Context.Context<NoInfer<R>>
2188 ): Effect.Effect<A, E, R2> =>
2189 withFiber<A, E, R2>((fiber) => {
2190 const prevContext = fiber.context as Context.Context<R2>
2191 const nextContext = f(prevContext)
2192 if (prevContext === nextContext) return self as any
2193 fiber.setContext(nextContext)
2194 onExitUnsafe(fiber, () => {
2195 fiber.setContext(prevContext)
2196 return undefined
2197 })
2198 return self as any
2199 })
2200)
2201
2202/** @internal */
2203export const updateService: {
2204 <I, A>(
2205 service: Context.Key<I, A>,
2206 f: (value: A) => A
2207 ): <XA, E, R>(self: Effect.Effect<XA, E, R>) => Effect.Effect<XA, E, R | I>
2208 <XA, E, R, I, A>(
2209 self: Effect.Effect<XA, E, R>,
2210 service: Context.Key<I, A>,
2211 f: (value: A) => A
2212 ): Effect.Effect<XA, E, R | I>
2213} = dual(
2214 3,
2215 <XA, E, R, I, A>(
2216 self: Effect.Effect<XA, E, R>,
2217 service: Context.Key<I, A>,
2218 f: (value: A) => A
2219 ): Effect.Effect<XA, E, R | I> =>
2220 updateContext(self, (s) => {
2221 const prev = Context.getUnsafe(s, service)
2222 const next = f(prev)
2223 if (prev === next) return s
2224 return Context.add(s, service, next)
2225 })
2226)
2227
2228/** @internal */
2229export const updateServiceScoped = <I, A>(
2230 service: Context.Key<I, A>,
2231 update: (value: A) => A,
2232 options?: {
2233 readonly reset?: ((original: A, updated: A, current: A) => A) | undefined
2234 } | undefined
2235): Effect.Effect<void, never, I | Scope.Scope> =>
2236 uninterruptible(withFiber((fiber) => {
2237 const original = Context.getUnsafe(fiber.context, service)
2238 const updated = update(original)
2239 fiber.setContext(Context.add(fiber.context, service, updated))
2240 return scopeAddFinalizerExit(Context.getUnsafe(fiber.context, scopeTag), (_) => {
2241 const currentOption = Context.getOption(fiber.context, service)
2242 if (Option.isNone(currentOption)) return void_
2243 const current = currentOption.value
2244 let next: A
2245 if (options?.reset === undefined) {
2246 if (current !== updated) return void_
2247 next = original
2248 } else {
2249 next = options.reset(original, updated, current)
2250 }
2251 fiber.setContext(Context.add(fiber.context, service, next))
2252 return void_
2253 })
2254 }))
2255
2256/** @internal */
2257export const context = <R = never>(): Effect.Effect<Context.Context<R>> => getContext as any
2258const getContext = withFiber((fiber) => succeed(fiber.context))
2259
2260/** @internal */
2261export const contextWith = <R, A, E, R2>(
2262 f: (context: Context.Context<R>) => Effect.Effect<A, E, R2>
2263): Effect.Effect<A, E, R | R2> => withFiber((fiber) => f(fiber.context as Context.Context<R>))
2264
2265/** @internal */
2266export const setContext: {
2267 <R>(
2268 context: Context.Context<R>
2269 ): <A, E>(
2270 self: Effect.Effect<A, E, R>
2271 ) => Effect.Effect<A, E>
2272 <A, E, R>(
2273 self: Effect.Effect<A, E, R>,
2274 context: Context.Context<R>
2275 ): Effect.Effect<A, E>
2276} = dual(
2277 2,
2278 <A, E, R>(
2279 self: Effect.Effect<A, E, R>,
2280 context: Context.Context<R>
2281 ): Effect.Effect<A, E> => updateContext(self, constant(context))
2282)
2283
2284/** @internal */
2285export const provideContext: {
2286 <XR>(
2287 context: Context.Context<XR>
2288 ): <A, E, R>(
2289 self: Effect.Effect<A, E, R>
2290 ) => Effect.Effect<A, E, Exclude<R, XR>>
2291 <A, E, R, XR>(
2292 self: Effect.Effect<A, E, R>,
2293 context: Context.Context<XR>
2294 ): Effect.Effect<A, E, Exclude<R, XR>>
2295} = dual(
2296 2,
2297 <A, E, R, XR>(
2298 self: Effect.Effect<A, E, R>,
2299 context: Context.Context<XR>
2300 ): Effect.Effect<A, E, Exclude<R, XR>> => {
2301 if (effectIsExit(self)) return self as any
2302 return updateContext(self, Context.merge(context)) as any
2303 }
2304)
2305
2306/** @internal */
2307export const provideService: {
2308 <I, S>(
2309 service: Context.Key<I, S>
2310 ): {
2311 (implementation: S): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, I>>
2312 <A, E, R>(self: Effect.Effect<A, E, R>, implementation: S): Effect.Effect<A, E, Exclude<R, I>>
2313 }
2314 <I, S>(
2315 key: Context.Key<I, S>,
2316 implementation: S
2317 ): <A, E, R>(
2318 self: Effect.Effect<A, E, R>
2319 ) => Effect.Effect<A, E, Exclude<R, I>>
2320 <A, E, R, I, S>(
2321 self: Effect.Effect<A, E, R>,
2322 service: Context.Key<I, S>,
2323 implementation: S
2324 ): Effect.Effect<A, E, Exclude<R, I>>
2325} = function(this: any) {
2326 if (arguments.length === 1) {
2327 return dual(2, (self, impl) => provideServiceImpl(self, arguments[0], impl)) as any
2328 }
2329 return dual(3, (self, service, impl) => provideServiceImpl(self, service, impl))
2330 .apply(this, arguments as any) as any
2331}
2332
2333const provideServiceImpl = <A, E, R, I, S>(
2334 self: Effect.Effect<A, E, R>,
2335 service: Context.Key<I, S>,
2336 implementation: S
2337): Effect.Effect<A, E, Exclude<R, I>> => updateContext(self, Context.add(service, implementation)) as any
2338
2339/** @internal */
2340export const provideServiceEffect: {
2341 <I, S, E2, R2>(
2342 service: Context.Key<I, S>,
2343 acquire: Effect.Effect<S, E2, R2>
2344 ): <A, E, R>(
2345 self: Effect.Effect<A, E, R>
2346 ) => Effect.Effect<A, E | E2, Exclude<R, I> | R2>
2347 <A, E, R, I, S, E2, R2>(
2348 self: Effect.Effect<A, E, R>,
2349 service: Context.Key<I, S>,
2350 acquire: Effect.Effect<S, E2, R2>
2351 ): Effect.Effect<A, E | E2, Exclude<R, I> | R2>
2352} = dual(
2353 3,
2354 <A, E, R, I, S, E2, R2>(
2355 self: Effect.Effect<A, E, R>,
2356 service: Context.Key<I, S>,
2357 acquire: Effect.Effect<S, E2, R2>
2358 ): Effect.Effect<A, E | E2, Exclude<R, I> | R2> =>
2359 flatMap(acquire, (implementation) => provideService(self, service, implementation))
2360)
2361
2362// ----------------------------------------------------------------------------
2363// zipping
2364// ----------------------------------------------------------------------------
2365
2366/** @internal */
2367export const zip: {
2368 <A2, E2, R2>(
2369 that: Effect.Effect<A2, E2, R2>,
2370 options?: { readonly concurrent?: boolean | undefined } | undefined
2371 ): <A, E, R>(
2372 self: Effect.Effect<A, E, R>
2373 ) => Effect.Effect<[A, A2], E2 | E, R2 | R>
2374 <A, E, R, A2, E2, R2>(
2375 self: Effect.Effect<A, E, R>,
2376 that: Effect.Effect<A2, E2, R2>,
2377 options?: { readonly concurrent?: boolean | undefined }
2378 ): Effect.Effect<[A, A2], E | E2, R | R2>
2379} = dual(
2380 (args) => isEffect(args[1]),
2381 <A, E, R, A2, E2, R2>(
2382 self: Effect.Effect<A, E, R>,
2383 that: Effect.Effect<A2, E2, R2>,
2384 options?: { readonly concurrent?: boolean | undefined }
2385 ): Effect.Effect<[A, A2], E | E2, R | R2> => zipWith(self, that, (a, a2) => [a, a2], options)
2386)
2387
2388/** @internal */
2389export const zipWith: {
2390 <A2, E2, R2, A, B>(
2391 that: Effect.Effect<A2, E2, R2>,
2392 f: (a: A, b: A2) => B,
2393 options?: { readonly concurrent?: boolean | undefined }
2394 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E2 | E, R2 | R>
2395 <A, E, R, A2, E2, R2, B>(
2396 self: Effect.Effect<A, E, R>,
2397 that: Effect.Effect<A2, E2, R2>,
2398 f: (a: A, b: A2) => B,
2399 options?: { readonly concurrent?: boolean | undefined }
2400 ): Effect.Effect<B, E2 | E, R2 | R>
2401} = dual(
2402 (args) => isEffect(args[1]),
2403 <A, E, R, A2, E2, R2, B>(
2404 self: Effect.Effect<A, E, R>,
2405 that: Effect.Effect<A2, E2, R2>,
2406 f: (a: A, b: A2) => B,
2407 options?: { readonly concurrent?: boolean | undefined }
2408 ): Effect.Effect<B, E2 | E, R2 | R> =>
2409 options?.concurrent
2410 // Use `all` exclusively for concurrent cases, as it introduces additional overhead due to the management of concurrency
2411 ? map(all([self, that], { concurrency: 2 }), ([a, a2]) => f(a, a2))
2412 : flatMap(self, (a) => map(that, (a2) => f(a, a2)))
2413)
2414
2415// ----------------------------------------------------------------------------
2416// filtering & conditionals
2417// ----------------------------------------------------------------------------
2418
2419/** @internal */
2420export const filterOrFail: {
2421 <A, E2, B extends A>(
2422 refinement: Predicate.Refinement<NoInfer<A>, B>,
2423 orFailWith: (a: NoInfer<A>) => E2
2424 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E2 | E, R>
2425 <A, E2>(
2426 predicate: Predicate.Predicate<NoInfer<A>>,
2427 orFailWith: (a: NoInfer<A>) => E2
2428 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E2 | E, R>
2429 <A, B extends A>(
2430 refinement: Predicate.Refinement<NoInfer<A>, B>
2431 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, Cause.NoSuchElementError | E, R>
2432 <A>(
2433 predicate: Predicate.Predicate<NoInfer<A>>
2434 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, Cause.NoSuchElementError | E, R>
2435 <A, E, R, E2, B extends A>(
2436 self: Effect.Effect<A, E, R>,
2437 refinement: Predicate.Refinement<NoInfer<A>, B>,
2438 orFailWith: (a: NoInfer<A>) => E2
2439 ): Effect.Effect<B, E2 | E, R>
2440 <A, E, R, E2>(
2441 self: Effect.Effect<A, E, R>,
2442 predicate: Predicate.Predicate<NoInfer<A>>,
2443 orFailWith: (a: NoInfer<A>) => E2
2444 ): Effect.Effect<A, E2 | E, R>
2445 <A, E, R, B extends A>(
2446 self: Effect.Effect<A, E, R>,
2447 refinement: Predicate.Refinement<NoInfer<A>, B>
2448 ): Effect.Effect<B, E | Cause.NoSuchElementError, R>
2449 <A, E, R>(
2450 self: Effect.Effect<A, E, R>,
2451 predicate: Predicate.Predicate<NoInfer<A>>
2452 ): Effect.Effect<A, E | Cause.NoSuchElementError, R>
2453} = dual((args) => isEffect(args[0]), <A, E, R, E2>(
2454 self: Effect.Effect<A, E, R>,
2455 predicate: Predicate.Predicate<NoInfer<A>>,
2456 orFailWith?: (a: any) => E2
2457): Effect.Effect<any, E | E2 | Cause.NoSuchElementError, R> =>
2458 filterOrElse(
2459 self,
2460 predicate as any,
2461 orFailWith ? (a: any) => fail(orFailWith(a)) : () => fail(new NoSuchElementError() as E2)
2462 ))
2463
2464/** @internal */
2465export const when: {
2466 <E2 = never, R2 = never>(
2467 condition: Effect.Effect<boolean, E2, R2>
2468 ): <A, E, R>(
2469 self: Effect.Effect<A, E, R>
2470 ) => Effect.Effect<Option.Option<A>, E | E2, R | R2>
2471 <A, E, R, E2 = never, R2 = never>(
2472 self: Effect.Effect<A, E, R>,
2473 condition: Effect.Effect<boolean, E2, R2>
2474 ): Effect.Effect<Option.Option<A>, E | E2, R | R2>
2475} = dual(
2476 2,
2477 <A, E, R, E2 = never, R2 = never>(
2478 self: Effect.Effect<A, E, R>,
2479 condition: Effect.Effect<boolean, E2, R2>
2480 ): Effect.Effect<Option.Option<A>, E | E2, R | R2> => flatMap(condition, (pass) => pass ? asSome(self) : succeedNone)
2481)
2482
2483// ----------------------------------------------------------------------------
2484// repetition
2485// ----------------------------------------------------------------------------
2486
2487/** @internal */
2488export const replicate: {
2489 (
2490 n: number
2491 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Array<Effect.Effect<A, E, R>>
2492 <A, E, R>(
2493 self: Effect.Effect<A, E, R>,
2494 n: number
2495 ): Array<Effect.Effect<A, E, R>>
2496} = dual(
2497 2,
2498 <A, E, R>(
2499 self: Effect.Effect<A, E, R>,
2500 n: number
2501 ): Array<Effect.Effect<A, E, R>> => Array.from({ length: n }, () => self)
2502)
2503
2504/** @internal */
2505export const replicateEffect: {
2506 (
2507 n: number,
2508 options?: {
2509 readonly concurrency?: Concurrency | undefined
2510 readonly discard?: false | undefined
2511 }
2512 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Array<A>, E, R>
2513 (
2514 n: number,
2515 options: {
2516 readonly concurrency?: Concurrency | undefined
2517 readonly discard: true
2518 }
2519 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<void, E, R>
2520 <A, E, R>(
2521 self: Effect.Effect<A, E, R>,
2522 n: number,
2523 options?: {
2524 readonly concurrency?: Concurrency | undefined
2525 readonly discard?: false | undefined
2526 }
2527 ): Effect.Effect<Array<A>, E, R>
2528 <A, E, R>(
2529 self: Effect.Effect<A, E, R>,
2530 n: number,
2531 options: {
2532 readonly concurrency?: Concurrency | undefined
2533 readonly discard: true
2534 }
2535 ): Effect.Effect<void, E, R>
2536} = dual(
2537 (args) => isEffect(args[0]),
2538 <A, E, R>(
2539 self: Effect.Effect<A, E, R>,
2540 n: number,
2541 options: {
2542 readonly concurrency?: Concurrency | undefined
2543 readonly discard: true
2544 }
2545 ): Effect.Effect<void, E, R> => all(replicate(self, n), options)
2546)
2547
2548/** @internal */
2549export const forever: {
2550 <
2551 Arg extends Effect.Effect<any, any, any> | {
2552 readonly disableYield?: boolean | undefined
2553 } | undefined = {
2554 readonly disableYield?: boolean | undefined
2555 }
2556 >(
2557 effectOrOptions: Arg,
2558 options?: {
2559 readonly disableYield?: boolean | undefined
2560 } | undefined
2561 ): [Arg] extends [Effect.Effect<infer _A, infer _E, infer _R>] ? Effect.Effect<never, _E, _R>
2562 : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<never, E, R>
2563} = dual((args) => isEffect(args[0]), <A, E, R>(
2564 self: Effect.Effect<A, E, R>,
2565 options?: {
2566 readonly disableYield?: boolean | undefined
2567 }
2568): Effect.Effect<never, E, R> =>
2569 whileLoop({
2570 while: constTrue,
2571 body: constant(options?.disableYield ? self : flatMap(self, (_) => yieldNow)),
2572 step: constVoid
2573 }) as any)
2574
2575// ----------------------------------------------------------------------------
2576// error handling
2577// ----------------------------------------------------------------------------
2578
2579/** @internal */
2580export const catchCause: {
2581 <E, B, E2, R2>(
2582 f: (cause: NoInfer<Cause.Cause<E>>) => Effect.Effect<B, E2, R2>
2583 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A | B, E2, R | R2>
2584 <A, E, R, B, E2, R2>(
2585 self: Effect.Effect<A, E, R>,
2586 f: (cause: NoInfer<Cause.Cause<E>>) => Effect.Effect<B, E2, R2>
2587 ): Effect.Effect<A | B, E2, R | R2>
2588} = dual(
2589 2,
2590 <A, E, R, B, E2, R2>(
2591 self: Effect.Effect<A, E, R>,
2592 f: (cause: NoInfer<Cause.Cause<E>>) => Effect.Effect<B, E2, R2>
2593 ): Effect.Effect<A | B, E2, R | R2> =>
2594 new OnFailureImpl(self, f.length !== 1 ? (cause: Cause.Cause<E>) => f(cause) : f)
2595)
2596const OnFailureProto = makePrimitiveProto({
2597 op: "OnFailure",
2598 [evaluate]: evaluateCont
2599})
2600const OnFailureImpl = function(this: any, self: Effect.Effect<any, any, any>, f: any) {
2601 this[args] = self
2602 this[contE] = f
2603} as unknown as PrimitiveCtor<[self: Effect.Effect<any, any, any>, f: any]>
2604OnFailureImpl.prototype = OnFailureProto
2605
2606/** @internal */
2607export const catchCauseIf: {
2608 <E, B, E2, R2>(
2609 predicate: Predicate.Predicate<Cause.Cause<E>>,
2610 f: (cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2>
2611 ): <A, R>(
2612 self: Effect.Effect<A, E, R>
2613 ) => Effect.Effect<A | B, E | E2, R | R2>
2614 <A, E, R, B, E2, R2>(
2615 self: Effect.Effect<A, E, R>,
2616 predicate: Predicate.Predicate<Cause.Cause<E>>,
2617 f: (cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2>
2618 ): Effect.Effect<A | B, E | E2, R | R2>
2619} = dual(
2620 3,
2621 <A, E, R, B, E2, R2>(
2622 self: Effect.Effect<A, E, R>,
2623 predicate: Predicate.Predicate<Cause.Cause<E>>,
2624 f: (cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2>
2625 ): Effect.Effect<A | B, E | E2, R | R2> =>
2626 catchCause(self, (cause): Effect.Effect<B, E | E2, R2> => {
2627 if (!predicate(cause)) {
2628 return failCause(cause) as any
2629 }
2630 return f(cause)
2631 })
2632)
2633
2634/** @internal */
2635export const catchCauseFilter: {
2636 <E, B, E2, R2, EB, X extends Cause.Cause<any>>(
2637 filter: Filter.Filter<Cause.Cause<E>, EB, X>,
2638 f: (failure: EB, cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2>
2639 ): <A, R>(
2640 self: Effect.Effect<A, E, R>
2641 ) => Effect.Effect<A | B, Cause.Cause.Error<X> | E2, R | R2>
2642 <A, E, R, B, E2, R2, EB, X extends Cause.Cause<any>>(
2643 self: Effect.Effect<A, E, R>,
2644 filter: Filter.Filter<Cause.Cause<E>, EB, X>,
2645 f: (failure: EB, cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2>
2646 ): Effect.Effect<A | B, Cause.Cause.Error<X> | E2, R | R2>
2647} = dual(
2648 3,
2649 <A, E, R, B, E2, R2, EB, X extends Cause.Cause<any>>(
2650 self: Effect.Effect<A, E, R>,
2651 filter: Filter.Filter<Cause.Cause<E>, EB, X>,
2652 f: (failure: EB, cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2>
2653 ): Effect.Effect<A | B, Cause.Cause.Error<X> | E2, R | R2> =>
2654 catchCause(self, (cause): Effect.Effect<B, Cause.Cause.Error<X> | E2, R2> => {
2655 const eb = filter(cause)
2656 return Result.isFailure(eb) ? failCause(eb.failure) : f(eb.success, cause)
2657 })
2658)
2659
2660/** @internal */
2661export const catch_: {
2662 <E, B, E2, R2>(
2663 f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2>
2664 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A | B, E2, R | R2>
2665 <A, E, R, B, E2, R2>(
2666 self: Effect.Effect<A, E, R>,
2667 f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2>
2668 ): Effect.Effect<A | B, E2, R | R2>
2669} = dual(
2670 2,
2671 <A, E, R, B, E2, R2>(
2672 self: Effect.Effect<A, E, R>,
2673 f: (a: NoInfer<E>) => Effect.Effect<B, E2, R2>
2674 ): Effect.Effect<A | B, E2, R | R2> => catchCauseFilter(self, findError as any, (e: any) => f(e)) as any
2675)
2676
2677/** @internal */
2678export const catchNoSuchElement = <A, E, R>(
2679 self: Effect.Effect<A, E, R>
2680): Effect.Effect<Option.Option<A>, Exclude<E, Cause.NoSuchElementError>, R> =>
2681 matchEffect(self, {
2682 onFailure: (error) =>
2683 isNoSuchElementError(error)
2684 ? succeedNone
2685 : fail(error as Exclude<E, Cause.NoSuchElementError>),
2686 onSuccess: succeedSome
2687 })
2688
2689/** @internal */
2690export const catchDefect: {
2691 <E, B, E2, R2>(
2692 f: (defect: unknown) => Effect.Effect<B, E2, R2>
2693 ): <A, R>(
2694 self: Effect.Effect<A, E, R>
2695 ) => Effect.Effect<A | B, E | E2, R | R2>
2696 <A, E, R, B, E2, R2>(
2697 self: Effect.Effect<A, E, R>,
2698 f: (defect: unknown) => Effect.Effect<B, E2, R2>
2699 ): Effect.Effect<A | B, E | E2, R | R2>
2700} = dual(
2701 2,
2702 <A, E, R, B, E2, R2>(
2703 self: Effect.Effect<A, E, R>,
2704 f: (defect: unknown) => Effect.Effect<B, E2, R2>
2705 ): Effect.Effect<A | B, E | E2, R | R2> => catchCauseFilter(self, findDefect as any, f as any) as any
2706)
2707
2708/** @internal */
2709export const tapCause: {
2710 <E, B, E2, R2>(
2711 f: (cause: NoInfer<Cause.Cause<E>>) => Effect.Effect<B, E2, R2>
2712 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2>
2713 <A, E, R, B, E2, R2>(
2714 self: Effect.Effect<A, E, R>,
2715 f: (cause: NoInfer<Cause.Cause<E>>) => Effect.Effect<B, E2, R2>
2716 ): Effect.Effect<A, E | E2, R | R2>
2717} = dual(
2718 2,
2719 <A, E, R, B, E2, R2>(
2720 self: Effect.Effect<A, E, R>,
2721 f: (cause: NoInfer<Cause.Cause<E>>) => Effect.Effect<B, E2, R2>
2722 ): Effect.Effect<A, E | E2, R | R2> => catchCause(self, (cause) => andThen(f(cause), failCause(cause)))
2723)
2724
2725/** @internal */
2726export const tapCauseIf: {
2727 <E, B, E2, R2>(
2728 predicate: Predicate.Predicate<Cause.Cause<E>>,
2729 f: (cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2>
2730 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2>
2731 <A, E, R, B, E2, R2>(
2732 self: Effect.Effect<A, E, R>,
2733 predicate: Predicate.Predicate<Cause.Cause<E>>,
2734 f: (cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2>
2735 ): Effect.Effect<A, E | E2, R | R2>
2736} = dual(
2737 3,
2738 <A, E, R, B, E2, R2>(
2739 self: Effect.Effect<A, E, R>,
2740 predicate: Predicate.Predicate<Cause.Cause<E>>,
2741 f: (cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2>
2742 ): Effect.Effect<A, E | E2, R | R2> =>
2743 catchCauseIf(
2744 self,
2745 predicate,
2746 (cause) => andThen(f(cause), failCause(cause))
2747 )
2748)
2749
2750/** @internal */
2751export const tapCauseFilter: {
2752 <E, B, E2, R2, EB, X extends Cause.Cause<any>>(
2753 filter: Filter.Filter<Cause.Cause<E>, EB, X>,
2754 f: (a: EB, cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2>
2755 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2>
2756 <A, E, R, B, E2, R2, EB, X extends Cause.Cause<any>>(
2757 self: Effect.Effect<A, E, R>,
2758 filter: Filter.Filter<Cause.Cause<E>, EB, X>,
2759 f: (a: EB, cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2>
2760 ): Effect.Effect<A, E | E2, R | R2>
2761} = dual(
2762 3,
2763 <A, E, R, B, E2, R2, EB, X extends Cause.Cause<any>>(
2764 self: Effect.Effect<A, E, R>,
2765 filter: Filter.Filter<Cause.Cause<E>, EB, X>,
2766 f: (a: EB, cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2>
2767 ): Effect.Effect<A, E | E2, R | R2> =>
2768 catchCause(self, (cause) => {
2769 const result = filter(cause)
2770 if (Result.isFailure(result)) {
2771 return failCause(cause)
2772 }
2773 return andThen(f(result.success, cause), failCause(cause))
2774 })
2775)
2776
2777/** @internal */
2778export const tapError: {
2779 <E, B, E2, R2>(
2780 f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2>
2781 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2>
2782 <A, E, R, B, E2, R2>(
2783 self: Effect.Effect<A, E, R>,
2784 f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2>
2785 ): Effect.Effect<A, E | E2, R | R2>
2786} = dual(
2787 2,
2788 <A, E, R, B, E2, R2>(
2789 self: Effect.Effect<A, E, R>,
2790 f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2>
2791 ): Effect.Effect<A, E | E2, R | R2> => tapCauseFilter(self, findError as any, (e: any) => f(e)) as any
2792)
2793
2794/** @internal */
2795export const tapErrorTag: {
2796 <const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>, E, A1, E1, R1>(
2797 k: K,
2798 f: (
2799 e: ExtractTag<NoInfer<E>, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>
2800 ) => Effect.Effect<A1, E1, R1>
2801 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E1, R1 | R>
2802 <
2803 A,
2804 E,
2805 R,
2806 const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>,
2807 R1,
2808 E1,
2809 A1
2810 >(
2811 self: Effect.Effect<A, E, R>,
2812 k: K,
2813 f: (e: ExtractTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A1, E1, R1>
2814 ): Effect.Effect<A, E | E1, R | R1>
2815} = dual(
2816 3,
2817 <
2818 A,
2819 E,
2820 R,
2821 const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>,
2822 R1,
2823 E1,
2824 A1
2825 >(
2826 self: Effect.Effect<A, E, R>,
2827 k: K,
2828 f: (e: ExtractTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A1, E1, R1>
2829 ): Effect.Effect<A, E | E1, R | R1> => {
2830 const predicate = Array.isArray(k)
2831 ? ((e: E): e is ExtractTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K> =>
2832 hasProperty(e, "_tag") && k.includes(e._tag))
2833 : isTagged(k as string)
2834 return tapError(
2835 self,
2836 (error) =>
2837 predicate(error)
2838 ? f(error as ExtractTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>)
2839 : void_
2840 )
2841 }
2842)
2843
2844/** @internal */
2845export const tapDefect: {
2846 <B, E2, R2>(
2847 f: (defect: unknown) => Effect.Effect<B, E2, R2>
2848 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2>
2849 <A, E, R, B, E2, R2>(
2850 self: Effect.Effect<A, E, R>,
2851 f: (defect: unknown) => Effect.Effect<B, E2, R2>
2852 ): Effect.Effect<A, E | E2, R | R2>
2853} = dual(
2854 2,
2855 <A, E, R, B, E2, R2>(
2856 self: Effect.Effect<A, E, R>,
2857 f: (defect: unknown) => Effect.Effect<B, E2, R2>
2858 ): Effect.Effect<A, E | E2, R | R2> => tapCauseFilter(self, findDefect as any, (_: any) => f(_)) as any
2859)
2860
2861/** @internal */
2862export const catchIf: {
2863 <E, EB extends E, A2, E2, R2, A3 = unassigned, E3 = never, R3 = never>(
2864 refinement: Predicate.Refinement<NoInfer<E>, EB>,
2865 f: (e: EB) => Effect.Effect<A2, E2, R2>,
2866 orElse?: ((e: Exclude<E, EB>) => Effect.Effect<A3, E3, R3>) | undefined
2867 ): <A, R>(
2868 self: Effect.Effect<A, E, R>
2869 ) => Effect.Effect<
2870 A | A2 | Exclude<A3, unassigned>,
2871 E2 | E3 | (A3 extends unassigned ? Exclude<E, EB> : never),
2872 R | R2 | R3
2873 >
2874 <E, A2, E2, R2, A3 = unassigned, E3 = never, R3 = never>(
2875 predicate: Predicate.Predicate<NoInfer<E>>,
2876 f: (e: NoInfer<E>) => Effect.Effect<A2, E2, R2>,
2877 orElse?: ((e: NoInfer<E>) => Effect.Effect<A3, E3, R3>) | undefined
2878 ): <A, R>(
2879 self: Effect.Effect<A, E, R>
2880 ) => Effect.Effect<A | A2 | Exclude<A3, unassigned>, E2 | E3 | (A3 extends unassigned ? E : never), R | R2 | R3>
2881 <A, E, R, EB extends E, A2, E2, R2, A3 = unassigned, E3 = never, R3 = never>(
2882 self: Effect.Effect<A, E, R>,
2883 refinement: Predicate.Refinement<E, EB>,
2884 f: (e: EB) => Effect.Effect<A2, E2, R2>,
2885 orElse?: ((e: Exclude<E, EB>) => Effect.Effect<A3, E3, R3>) | undefined
2886 ): Effect.Effect<
2887 A | A2 | Exclude<A3, unassigned>,
2888 E2 | E3 | (A3 extends unassigned ? Exclude<E, EB> : never),
2889 R | R2 | R3
2890 >
2891 <A, E, R, A2, E2, R2, A3 = unassigned, E3 = never, R3 = never>(
2892 self: Effect.Effect<A, E, R>,
2893 predicate: Predicate.Predicate<E>,
2894 f: (e: E) => Effect.Effect<A2, E2, R2>,
2895 orElse?: ((e: E) => Effect.Effect<A3, E3, R3>) | undefined
2896 ): Effect.Effect<A | A2 | Exclude<A3, unassigned>, E2 | E3 | (A3 extends unassigned ? E : never), R | R2 | R3>
2897} = dual(
2898 (args) => isEffect(args[0]),
2899 <A, E, R, A2, E2, R2, A3 = never, E3 = E, R3 = never>(
2900 self: Effect.Effect<A, E, R>,
2901 predicate: Predicate.Predicate<E>,
2902 f: (e: E) => Effect.Effect<A2, E2, R2>,
2903 orElse?: ((e: E) => Effect.Effect<A3, E3, R3>) | undefined
2904 ): Effect.Effect<A | A2 | A3, E2 | E3, R | R2 | R3> =>
2905 catchCause(self, (cause): Effect.Effect<A2 | A3, E2 | E3, R2 | R3> => {
2906 const error = findError(cause)
2907 if (Result.isFailure(error)) return failCause(error.failure)
2908 if (!predicate(error.success)) {
2909 return orElse ? orElse(error.success as any) : failCause(cause as any as Cause.Cause<E3>)
2910 }
2911 return f(error.success as any)
2912 })
2913)
2914
2915/** @internal */
2916export const catchFilter: {
2917 <E, EB, A2, E2, R2, X, A3 = unassigned, E3 = never, R3 = never>(
2918 filter: Filter.Filter<NoInfer<E>, EB, X>,
2919 f: (e: EB) => Effect.Effect<A2, E2, R2>,
2920 orElse?: ((e: X) => Effect.Effect<A3, E3, R3>) | undefined
2921 ): <A, R>(
2922 self: Effect.Effect<A, E, R>
2923 ) => Effect.Effect<A | A2 | Exclude<A3, unassigned>, E2 | E3 | (A3 extends unassigned ? X : never), R | R2 | R3>
2924 <A, E, R, EB, A2, E2, R2, X, A3 = unassigned, E3 = never, R3 = never>(
2925 self: Effect.Effect<A, E, R>,
2926 filter: Filter.Filter<NoInfer<E>, EB, X>,
2927 f: (e: EB) => Effect.Effect<A2, E2, R2>,
2928 orElse?: ((e: X) => Effect.Effect<A3, E3, R3>) | undefined
2929 ): Effect.Effect<A | A2 | Exclude<A3, unassigned>, E2 | E3 | (A3 extends unassigned ? X : never), R | R2 | R3>
2930} = dual(
2931 (args) => isEffect(args[0]),
2932 <A, E, R, EB, A2, E2, R2, X, A3 = never, E3 = X, R3 = never>(
2933 self: Effect.Effect<A, E, R>,
2934 filter: Filter.Filter<NoInfer<E>, EB, X>,
2935 f: (e: EB) => Effect.Effect<A2, E2, R2>,
2936 orElse?: ((e: X) => Effect.Effect<A3, E3, R3>) | undefined
2937 ): Effect.Effect<A | A2 | A3, E2 | E3, R | R2 | R3> =>
2938 catchCause(self, (cause): Effect.Effect<A2 | A3, E2 | E3, R2 | R3> => {
2939 const error = findError(cause)
2940 if (Result.isFailure(error)) return failCause(error.failure)
2941 const result = filter(error.success)
2942 if (Result.isFailure(result)) {
2943 return orElse ? orElse(result.failure as any) : failCause(cause as any as Cause.Cause<E3>)
2944 }
2945 return f(result.success)
2946 })
2947)
2948
2949/** @internal */
2950export const catchTag: {
2951 <
2952 const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>,
2953 E,
2954 A1,
2955 E1,
2956 R1,
2957 A2 = unassigned,
2958 E2 = never,
2959 R2 = never
2960 >(
2961 k: K,
2962 f: (
2963 e: ExtractTag<NoInfer<E>, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>
2964 ) => Effect.Effect<A1, E1, R1>,
2965 orElse?:
2966 | ((e: ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A2, E2, R2>)
2967 | undefined
2968 ): <A, R>(
2969 self: Effect.Effect<A, E, R>
2970 ) => Effect.Effect<
2971 A | A1 | Exclude<A2, unassigned>,
2972 | E1
2973 | E2
2974 | (A2 extends unassigned ? ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K> : never),
2975 R | R1 | R2
2976 >
2977 <
2978 A,
2979 E,
2980 R,
2981 const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>,
2982 R1,
2983 E1,
2984 A1,
2985 A2 = unassigned,
2986 E2 = never,
2987 R2 = never
2988 >(
2989 self: Effect.Effect<A, E, R>,
2990 k: K,
2991 f: (e: ExtractTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A1, E1, R1>,
2992 orElse?:
2993 | ((e: ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A2, E2, R2>)
2994 | undefined
2995 ): Effect.Effect<
2996 A | A1 | Exclude<A2, unassigned>,
2997 | E1
2998 | E2
2999 | (A2 extends unassigned ? ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K> : never),
3000 R | R1 | R2
3001 >
3002} = dual(
3003 (args) => isEffect(args[0]),
3004 <
3005 A,
3006 E,
3007 R,
3008 const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>,
3009 R1,
3010 E1,
3011 A1,
3012 A2 = never,
3013 E2 = ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>,
3014 R2 = never
3015 >(
3016 self: Effect.Effect<A, E, R>,
3017 k: K,
3018 f: (e: ExtractTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A1, E1, R1>,
3019 orElse?:
3020 | ((e: ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A2, E2, R2>)
3021 | undefined
3022 ): Effect.Effect<A | A1 | A2, E1 | E2, R | R1 | R2> => {
3023 const pred = Array.isArray(k)
3024 ? ((e: E): e is any => hasProperty(e, "_tag") && k.includes(e._tag))
3025 : isTagged(k as string)
3026 return catchIf(self, pred, f, orElse as any) as any
3027 }
3028)
3029
3030/** @internal */
3031export const catchTags: {
3032 <
3033 E,
3034 Cases extends (E extends { _tag: string } ? {
3035 [K in E["_tag"]]+?: (error: Extract<E, { _tag: K }>) => Effect.Effect<any, any, any>
3036 } :
3037 {}),
3038 A2 = unassigned,
3039 E2 = never,
3040 R2 = never
3041 >(
3042 cases: Cases,
3043 orElse?: ((e: Exclude<E, { _tag: keyof Cases }>) => Effect.Effect<A2, E2, R2>) | undefined
3044 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<
3045 | A
3046 | Exclude<A2, unassigned>
3047 | {
3048 [K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<infer A, any, any>) ? A : never
3049 }[keyof Cases],
3050 | E2
3051 | (A2 extends unassigned ? Exclude<E, { _tag: keyof Cases }> : never)
3052 | {
3053 [K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<any, infer E, any>) ? E : never
3054 }[keyof Cases],
3055 | R
3056 | R2
3057 | {
3058 [K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<any, any, infer R>) ? R : never
3059 }[keyof Cases]
3060 >
3061 <
3062 R,
3063 E,
3064 A,
3065 Cases extends (E extends { _tag: string } ? {
3066 [K in E["_tag"]]+?: (error: Extract<E, { _tag: K }>) => Effect.Effect<any, any, any>
3067 } :
3068 {}),
3069 A2 = unassigned,
3070 E2 = never,
3071 R2 = never
3072 >(
3073 self: Effect.Effect<A, E, R>,
3074 cases: Cases,
3075 orElse?: ((e: Exclude<E, { _tag: keyof Cases }>) => Effect.Effect<A2, E2, R2>) | undefined
3076 ): Effect.Effect<
3077 | A
3078 | Exclude<A2, unassigned>
3079 | {
3080 [K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<infer A, any, any>) ? A : never
3081 }[keyof Cases],
3082 | E2
3083 | (A2 extends unassigned ? Exclude<E, { _tag: keyof Cases }> : never)
3084 | {
3085 [K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<any, infer E, any>) ? E : never
3086 }[keyof Cases],
3087 | R
3088 | R2
3089 | {
3090 [K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<any, any, infer R>) ? R : never
3091 }[keyof Cases]
3092 >
3093} = dual((args) => isEffect(args[0]), (self: Effect.Effect<any, any, any>, cases: Record<string, any>, orElse: any) => {
3094 let keys: Array<string>
3095 return catchFilter(
3096 self,
3097 (e) => {
3098 keys ??= Object.keys(cases)
3099 return hasProperty(e, "_tag") && isString(e["_tag"]) && keys.includes(e["_tag"])
3100 ? Result.succeed(e)
3101 : Result.fail(e)
3102 },
3103 (e: any) => cases[e["_tag"] as string](e),
3104 orElse
3105 ) as any
3106})
3107
3108/** @internal */
3109export const catchReason: {
3110 <
3111 K extends Tags<E>,
3112 E,
3113 RK extends ReasonTags<ExtractTag<NoInfer<E>, K>>,
3114 A2,
3115 E2,
3116 R2,
3117 A3 = unassigned,
3118 E3 = never,
3119 R3 = never
3120 >(
3121 errorTag: K,
3122 reasonTag: RK,
3123 f: (
3124 reason: ExtractReason<ExtractTag<NoInfer<E>, K>, RK>,
3125 error: NarrowReason<ExtractTag<NoInfer<E>, K>, RK>
3126 ) => Effect.Effect<A2, E2, R2>,
3127 orElse?:
3128 | ((
3129 reasons: ExcludeReason<ExtractTag<NoInfer<E>, K>, RK>,
3130 error: OmitReason<ExtractTag<NoInfer<E>, K>, RK>
3131 ) => Effect.Effect<A3, E3, R3>)
3132 | undefined
3133 ): <A, R>(
3134 self: Effect.Effect<A, E, R>
3135 ) => Effect.Effect<
3136 A | A2 | Exclude<A3, unassigned>,
3137 ExcludeTag<E, K> | E2 | E3 | (A3 extends unassigned ? ExtractTag<E, K> : never),
3138 R | R2 | R3
3139 >
3140 <
3141 A,
3142 E,
3143 R,
3144 K extends Tags<E>,
3145 RK extends ReasonTags<ExtractTag<E, K>>,
3146 A2,
3147 E2,
3148 R2,
3149 A3 = unassigned,
3150 E3 = never,
3151 R3 = never
3152 >(
3153 self: Effect.Effect<A, E, R>,
3154 errorTag: K,
3155 reasonTag: RK,
3156 f: (
3157 reason: ExtractReason<ExtractTag<E, K>, RK>,
3158 error: NarrowReason<ExtractTag<E, K>, RK>
3159 ) => Effect.Effect<A2, E2, R2>,
3160 orElse?:
3161 | ((
3162 reasons: ExcludeReason<ExtractTag<E, K>, RK>,
3163 error: OmitReason<ExtractTag<E, K>, RK>
3164 ) => Effect.Effect<A3, E3, R3>)
3165 | undefined
3166 ): Effect.Effect<
3167 A | A2 | Exclude<A3, unassigned>,
3168 ExcludeTag<E, K> | E2 | E3 | (A3 extends unassigned ? ExtractTag<E, K> : never),
3169 R | R2 | R3
3170 >
3171} = dual(
3172 (args) => isEffect(args[0]),
3173 <
3174 A,
3175 E,
3176 R,
3177 K extends Tags<E>,
3178 RK extends ReasonTags<ExtractTag<E, K>>,
3179 A2,
3180 E2,
3181 R2,
3182 A3 = unassigned,
3183 E3 = never,
3184 R3 = never
3185 >(
3186 self: Effect.Effect<A, E, R>,
3187 errorTag: K,
3188 reasonTag: RK,
3189 f: (reason: ExtractReason<ExtractTag<E, K>, RK>, error: ExtractTag<E, K>) => Effect.Effect<A2, E2, R2>,
3190 orElse?:
3191 | ((
3192 reasons: ExcludeReason<ExtractTag<E, K>, RK>,
3193 error: OmitReason<ExtractTag<E, K>, RK>
3194 ) => Effect.Effect<A3, E3, R3>)
3195 | undefined
3196 ): Effect.Effect<
3197 A | A2 | Exclude<A3, unassigned>,
3198 ExcludeTag<E, K> | E2 | E3 | (A3 extends unassigned ? ExtractTag<E, K> : never),
3199 R | R2 | R3
3200 > =>
3201 catchIf(
3202 self,
3203 ((e: any) =>
3204 isTagged(e, errorTag) &&
3205 hasProperty(e, "reason") &&
3206 (orElse !== undefined || isTagged(e.reason, reasonTag))) as any,
3207 (e: any): Effect.Effect<A2 | A3, E | E2 | E3, R2 | R3> => {
3208 const reason = e.reason as any
3209 if (isTagged(reason, reasonTag)) return f(reason as any, e)
3210 return orElse ? orElse(reason, e) : fail(e)
3211 }
3212 ) as any
3213)
3214
3215/** @internal */
3216export const catchReasons: {
3217 <
3218 K extends Tags<E>,
3219 E,
3220 Cases extends {
3221 [RK in ReasonTags<ExtractTag<NoInfer<E>, K>>]+?: (
3222 reason: ExtractReason<ExtractTag<NoInfer<E>, K>, RK>,
3223 error: NarrowReason<ExtractTag<NoInfer<E>, K>, RK>
3224 ) => Effect.Effect<any, any, any>
3225 },
3226 A2 = unassigned,
3227 E2 = never,
3228 R2 = never
3229 >(
3230 errorTag: K,
3231 cases: Cases,
3232 orElse?:
3233 | ((
3234 reason: ExcludeReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>>,
3235 error: OmitReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>>
3236 ) => Effect.Effect<A2, E2, R2>)
3237 | undefined
3238 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<
3239 | A
3240 | Exclude<A2, unassigned>
3241 | { [RK in keyof Cases]: Cases[RK] extends (...args: Array<any>) => Effect.Effect<infer A, any, any> ? A : never }[
3242 keyof Cases
3243 ],
3244 | ExcludeTag<E, K>
3245 | E2
3246 | (A2 extends unassigned ? ExtractTag<E, K> : never)
3247 | { [RK in keyof Cases]: Cases[RK] extends (...args: Array<any>) => Effect.Effect<any, infer E, any> ? E : never }[
3248 keyof Cases
3249 ],
3250 | R
3251 | R2
3252 | { [RK in keyof Cases]: Cases[RK] extends (...args: Array<any>) => Effect.Effect<any, any, infer R> ? R : never }[
3253 keyof Cases
3254 ]
3255 >
3256 <
3257 A,
3258 E,
3259 R,
3260 K extends Tags<E>,
3261 Cases extends {
3262 [RK in ReasonTags<ExtractTag<E, K>>]+?: (
3263 reason: ExtractReason<ExtractTag<E, K>, RK>,
3264 error: NarrowReason<ExtractTag<E, K>, RK>
3265 ) => Effect.Effect<any, any, any>
3266 },
3267 A2 = unassigned,
3268 E2 = never,
3269 R2 = never
3270 >(
3271 self: Effect.Effect<A, E, R>,
3272 errorTag: K,
3273 cases: Cases,
3274 orElse?:
3275 | ((
3276 reason: ExcludeReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>>,
3277 error: OmitReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>>
3278 ) => Effect.Effect<A2, E2, R2>)
3279 | undefined
3280 ): Effect.Effect<
3281 | A
3282 | Exclude<A2, unassigned>
3283 | { [RK in keyof Cases]: Cases[RK] extends (...args: Array<any>) => Effect.Effect<infer A, any, any> ? A : never }[
3284 keyof Cases
3285 ],
3286 | ExcludeTag<E, K>
3287 | E2
3288 | (A2 extends unassigned ? ExtractTag<E, K> : never)
3289 | { [RK in keyof Cases]: Cases[RK] extends (...args: Array<any>) => Effect.Effect<any, infer E, any> ? E : never }[
3290 keyof Cases
3291 ],
3292 | R
3293 | R2
3294 | { [RK in keyof Cases]: Cases[RK] extends (...args: Array<any>) => Effect.Effect<any, any, infer R> ? R : never }[
3295 keyof Cases
3296 ]
3297 >
3298} = dual((args) => isEffect(args[0]), (self, errorTag, cases, orElse) => {
3299 let keys: Array<string>
3300 return catchIf(
3301 self,
3302 ((e: any) =>
3303 isTagged(e, errorTag) &&
3304 hasProperty(e, "reason") &&
3305 hasProperty(e.reason, "_tag") &&
3306 isString(e.reason._tag) &&
3307 (orElse !== undefined || (keys ??= Object.keys(cases)).includes(e.reason._tag))) as any,
3308 (e: any) => {
3309 const reason = e.reason
3310 keys ??= Object.keys(cases)
3311 if (keys.includes(reason._tag)) {
3312 return (cases as any)[reason._tag](reason, e)
3313 }
3314 return orElse ? orElse(reason, e) : fail(e)
3315 }
3316 )
3317})
3318
3319/** @internal */
3320export const unwrapReason: {
3321 <
3322 K extends Effect.TagsWithReason<E>,
3323 E
3324 >(
3325 errorTag: K
3326 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, ExcludeTag<E, K> | ReasonOf<ExtractTag<E, K>>, R>
3327 <
3328 A,
3329 E,
3330 R,
3331 K extends Effect.TagsWithReason<E>
3332 >(
3333 self: Effect.Effect<A, E, R>,
3334 errorTag: K
3335 ): Effect.Effect<A, ExcludeTag<E, K> | ReasonOf<ExtractTag<E, K>>, R>
3336} = dual(
3337 2,
3338 <
3339 A,
3340 E,
3341 R,
3342 K extends Effect.TagsWithReason<E>
3343 >(
3344 self: Effect.Effect<A, E, R>,
3345 errorTag: K
3346 ): Effect.Effect<A, ExcludeTag<E, K> | ReasonOf<ExtractTag<E, K>>, R> =>
3347 catchFilter(
3348 self,
3349 (e: any) => {
3350 if (isTagged(e, errorTag) && hasProperty(e, "reason")) {
3351 return Result.succeed(e.reason)
3352 }
3353 return Result.fail(e)
3354 },
3355 fail as any
3356 ) as any
3357)
3358
3359/** @internal */
3360export const mapError: {
3361 <E, E2>(
3362 f: (e: E) => E2
3363 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E2, R>
3364 <A, E, R, E2>(
3365 self: Effect.Effect<A, E, R>,
3366 f: (e: E) => E2
3367 ): Effect.Effect<A, E2, R>
3368} = dual(
3369 2,
3370 <A, E, R, E2>(
3371 self: Effect.Effect<A, E, R>,
3372 f: (e: E) => E2
3373 ): Effect.Effect<A, E2, R> => catch_(self, (error) => failSync(() => f(error)))
3374)
3375
3376/** @internal */
3377export const mapBoth: {
3378 <E, E2, A, A2>(
3379 options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 }
3380 ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A2, E2, R>
3381 <A, E, R, E2, A2>(
3382 self: Effect.Effect<A, E, R>,
3383 options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 }
3384 ): Effect.Effect<A2, E2, R>
3385} = dual(2, <A, E, R, E2, A2>(
3386 self: Effect.Effect<A, E, R>,
3387 options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 }
3388): Effect.Effect<A2, E2, R> =>
3389 matchEffect(self, {
3390 onFailure: (e) => failSync(() => options.onFailure(e)),
3391 onSuccess: (a) => sync(() => options.onSuccess(a))
3392 }))
3393
3394/** @internal */
3395export const orDie = <A, E, R>(
3396 self: Effect.Effect<A, E, R>
3397): Effect.Effect<A, never, R> => catch_(self, die)
3398
3399/** @internal */
3400export const orElseSucceed: {
3401 <E, B>(
3402 f: (error: NoInfer<E>) => B
3403 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A | B, never, R>
3404 <A, E, R, B>(
3405 self: Effect.Effect<A, E, R>,
3406 f: (error: E) => B
3407 ): Effect.Effect<A | B, never, R>
3408} = dual(
3409 2,
3410 <A, E, R, B>(
3411 self: Effect.Effect<A, E, R>,
3412 f: (error: E) => B
3413 ): Effect.Effect<A | B, never, R> => catch_(self, (error) => sync(() => f(error)))
3414)
3415
3416/** @internal */
3417export const firstSuccessOf = <Eff extends Effect.Effect<any, any, any>>(
3418 effects: Iterable<Eff>
3419): Effect.Effect<Effect.Success<Eff>, Effect.Error<Eff>, Effect.Services<Eff>> =>
3420 suspend(() => {
3421 const iterator = effects[Symbol.iterator]()
3422 let state = iterator.next()
3423 if (state.done) {
3424 return die(new Error("Received an empty collection of effects"))
3425 }
3426 function loop(current: IteratorYieldResult<Eff>): Eff {
3427 const next = iterator.next()
3428 if (next.done) return current.value
3429 return catch_(current.value, (_) => loop(next)) as any
3430 }
3431 return loop(state)
3432 })
3433
3434/** @internal */
3435export const eventually = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, never, R> =>
3436 catch_(self, (_) => flatMap(yieldNow, () => eventually(self)))
3437
3438/** @internal */
3439export const ignore: <
3440 Arg extends Effect.Effect<any, any, any> | {
3441 readonly log?: boolean | LogLevel.Severity | undefined
3442 readonly message?: string | undefined
3443 } | undefined = {
3444 readonly log?: boolean | LogLevel.Severity | undefined
3445 readonly message?: string | undefined
3446 }
3447>(
3448 effectOrOptions: Arg,
3449 options?: {
3450 readonly log?: boolean | LogLevel.Severity | undefined
3451 readonly message?: string | undefined
3452 } | undefined
3453) => [Arg] extends [Effect.Effect<infer _A, infer _E, infer _R>] ? Effect.Effect<void, never, _R>
3454 : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<void, never, R> = dual(
3455 (args) => isEffect(args[0]),
3456 <A, E, R>(
3457 self: Effect.Effect<A, E, R>,
3458 options?: {
3459 readonly log?: boolean | LogLevel.Severity | undefined
3460 readonly message?: string | undefined
3461 } | undefined
3462 ): Effect.Effect<void, never, R> => {
3463 if (!options?.log) {
3464 return matchEffect(self, { onFailure: (_) => void_, onSuccess: (_) => void_ })
3465 }
3466 const logEffect = logWithLevel(options.log === true ? undefined : options.log)
3467 return matchCauseEffect(self, {
3468 onFailure(cause) {
3469 const failure = findFail(cause)
3470 return Result.isFailure(failure)
3471 ? failCause(failure.failure)
3472 : options.message === undefined
3473 ? logEffect(cause)
3474 : logEffect(options.message, cause)
3475 },
3476 onSuccess: (_) => void_
3477 })
3478 }
3479 )
3480
3481/** @internal */
3482export const ignoreCause: <
3483 Arg extends Effect.Effect<any, any, any> | {
3484 readonly log?: boolean | LogLevel.Severity | undefined
3485 readonly message?: string | undefined
3486 } | undefined = {
3487 readonly log?: boolean | LogLevel.Severity | undefined
3488 readonly message?: string | undefined
3489 }
3490>(
3491 effectOrOptions: Arg,
3492 options?: {
3493 readonly log?: boolean | LogLevel.Severity | undefined
3494 readonly message?: string | undefined
3495 } | undefined
3496) => [Arg] extends [Effect.Effect<infer _A, infer _E, infer _R>] ? Effect.Effect<void, never, _R>
3497 : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<void, never, R> = dual(
3498 (args) => isEffect(args[0]),
3499 <A, E, R>(
3500 self: Effect.Effect<A, E, R>,
3501 options?: {
3502 readonly log?: boolean | LogLevel.Severity | undefined
3503 readonly message?: string | undefined
3504 } | undefined
3505 ): Effect.Effect<void, never, R> => {
3506 if (!options?.log) {
3507 return matchCauseEffect(self, { onFailure: (_) => void_, onSuccess: (_) => void_ })
3508 }
3509 const logEffect = logWithLevel(options.log === true ? undefined : options.log)
3510 return matchCauseEffect(self, {
3511 onFailure: (cause) => options.message === undefined ? logEffect(cause) : logEffect(options.message, cause),
3512 onSuccess: (_) => void_
3513 })
3514 }
3515 )
3516
3517/** @internal */
3518export const option = <A, E, R>(
3519 self: Effect.Effect<A, E, R>
3520): Effect.Effect<Option.Option<A>, never, R> => match(self, { onFailure: Option.none, onSuccess: Option.some })
3521
3522/** @internal */
3523export const result = <A, E, R>(
3524 self: Effect.Effect<A, E, R>
3525): Effect.Effect<Result.Result<A, E>, never, R> =>
3526 matchEager(self, { onFailure: Result.fail, onSuccess: Result.succeed })
3527
3528// ----------------------------------------------------------------------------
3529// pattern matching
3530// ----------------------------------------------------------------------------
3531
3532/** @internal */
3533export const matchCauseEffect: {
3534 <E, A2, E2, R2, A, A3, E3, R3>(options: {
3535 readonly onFailure: (cause: Cause.Cause<E>) => Effect.Effect<A2, E2, R2>
3536 readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3>
3537 }): <R>(
3538 self: Effect.Effect<A, E, R>
3539 ) => Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R>
3540 <A, E, R, A2, E2, R2, A3, E3, R3>(
3541 self: Effect.Effect<A, E, R>,
3542 options: {
3543 readonly onFailure: (cause: Cause.Cause<E>) => Effect.Effect<A2, E2, R2>
3544 readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3>
3545 }
3546 ): Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R>
3547} = dual(
3548 2,
3549 <A, E, R, A2, E2, R2, A3, E3, R3>(
3550 self: Effect.Effect<A, E, R>,
3551 options: {
3552 readonly onFailure: (cause: Cause.Cause<E>) => Effect.Effect<A2, E2, R2>
3553 readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3>
3554 }
3555 ): Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R> =>
3556 new OnSuccessAndFailureImpl(
3557 self,
3558 options.onSuccess.length !== 1 ? (a: A) => options.onSuccess(a) : options.onSuccess,
3559 options.onFailure.length !== 1
3560 ? (cause: Cause.Cause<E>) => options.onFailure(cause)
3561 : options.onFailure
3562 )
3563)
3564const OnSuccessAndFailureProto = makePrimitiveProto({
3565 op: "OnSuccessAndFailure",
3566 [evaluate]: evaluateCont
3567})
3568const OnSuccessAndFailureImpl = function(
3569 this: any,
3570 self: Effect.Effect<any, any, any>,
3571 onSuccess: any,
3572 onFailure: any
3573) {
3574 this[args] = self
3575 this[contA] = onSuccess
3576 this[contE] = onFailure
3577} as unknown as PrimitiveCtor<[self: Effect.Effect<any, any, any>, onSuccess: any, onFailure: any]>
3578OnSuccessAndFailureImpl.prototype = OnSuccessAndFailureProto
3579
3580// `match` and `matchCause` keep the caller's handlers object as the frame's
3581// payload and call it from the prototype, so no closure is built per call.
3582const matchSuccess = function(this: any, value: any, fiber: FiberImpl) {
3583 const handlers = this.payload
3584 return fiber.succeedWith(
3585 continuationMarksStack ? handlers.onSuccess(value) : internalCall(() => handlers.onSuccess(value))
3586 )
3587}
3588const makeMatch = (
3589 op: string,
3590 onFailure: (this: any, cause: Cause.Cause<any>, fiber: FiberImpl) => Primitive | Yield
3591) => {
3592 const Proto = makePrimitiveProto({
3593 op,
3594 [evaluate]: evaluateCont,
3595 [contA]: matchSuccess,
3596 [contE]: onFailure
3597 })
3598 const MatchImpl = function(this: any, self: Effect.Effect<any, any, any>, handlers: any) {
3599 this[args] = self
3600 this.payload = handlers
3601 } as unknown as {
3602 new(self: Effect.Effect<any, any, any>, handlers: any): Effect.Effect<any, never, any>
3603 prototype: any
3604 }
3605 MatchImpl.prototype = Proto
3606 return MatchImpl
3607}
3608const MatchImpl = makeMatch("Match", function(cause, fiber) {
3609 const fail = cause.reasons.find(isFailReason)
3610 if (fail === undefined) return failCause(cause) as any
3611 const handlers = this.payload
3612 return fiber.succeedWith(
3613 continuationMarksStack ? handlers.onFailure(fail.error) : internalCall(() => handlers.onFailure(fail.error))
3614 )
3615})
3616const MatchCauseImpl = makeMatch("MatchCause", function(cause, fiber) {
3617 const handlers = this.payload
3618 return fiber.succeedWith(
3619 continuationMarksStack ? handlers.onFailure(cause) : internalCall(() => handlers.onFailure(cause))
3620 )
3621})
3622
3623/** @internal */
3624export const matchCause: {
3625 <E, A2, A, A3>(options: {
3626 readonly onFailure: (cause: Cause.Cause<E>) => A2
3627 readonly onSuccess: (a: A) => A3
3628 }): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A2 | A3, never, R>
3629 <A, E, R, A2, A3>(
3630 self: Effect.Effect<A, E, R>,
3631 options: {
3632 readonly onFailure: (cause: Cause.Cause<E>) => A2
3633 readonly onSuccess: (a: A) => A3
3634 }
3635 ): Effect.Effect<A2 | A3, never, R>
3636} = dual(
3637 2,
3638 <A, E, R, A2, A3>(
3639 self: Effect.Effect<A, E, R>,
3640 options: {
3641 readonly onFailure: (cause: Cause.Cause<E>) => A2
3642 readonly onSuccess: (a: A) => A3
3643 }
3644 ): Effect.Effect<A2 | A3, never, R> => new MatchCauseImpl(self, options)
3645)
3646
3647/** @internal */
3648export const matchEffect: {
3649 <E, A2, E2, R2, A, A3, E3, R3>(options: {
3650 readonly onFailure: (e: E) => Effect.Effect<A2, E2, R2>
3651 readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3>
3652 }): <R>(
3653 self: Effect.Effect<A, E, R>
3654 ) => Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R>
3655 <A, E, R, A2, E2, R2, A3, E3, R3>(
3656 self: Effect.Effect<A, E, R>,
3657 options: {
3658 readonly onFailure: (e: E) => Effect.Effect<A2, E2, R2>
3659 readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3>
3660 }
3661 ): Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R>
3662} = dual(
3663 2,
3664 <A, E, R, A2, E2, R2, A3, E3, R3>(
3665 self: Effect.Effect<A, E, R>,
3666 options: {
3667 readonly onFailure: (e: E) => Effect.Effect<A2, E2, R2>
3668 readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3>
3669 }
3670 ): Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R> =>
3671 matchCauseEffect(self, {
3672 onFailure: (cause) => {
3673 const fail = cause.reasons.find(isFailReason)
3674 return fail
3675 ? options.onFailure(fail.error)
3676 : failCause(cause as Cause.Cause<never>)
3677 },
3678 onSuccess: options.onSuccess
3679 })
3680)
3681
3682/** @internal */
3683export const match: {
3684 <E, A2, A, A3>(options: {
3685 readonly onFailure: (error: E) => A2
3686 readonly onSuccess: (value: A) => A3
3687 }): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A2 | A3, never, R>
3688 <A, E, R, A2, A3>(
3689 self: Effect.Effect<A, E, R>,
3690 options: {
3691 readonly onFailure: (error: E) => A2
3692 readonly onSuccess: (value: A) => A3
3693 }
3694 ): Effect.Effect<A2 | A3, never, R>
3695} = dual(
3696 2,
3697 <A, E, R, A2, A3>(
3698 self: Effect.Effect<A, E, R>,
3699 options: {
3700 readonly onFailure: (error: E) => A2
3701 readonly onSuccess: (value: A) => A3
3702 }
3703 ): Effect.Effect<A2 | A3, never, R> => new MatchImpl(self, options)
3704)
3705
3706/** @internal */
3707export const matchEager: {
3708 <E, A2, A, A3>(options: {
3709 readonly onFailure: (error: E) => A2
3710 readonly onSuccess: (value: A) => A3
3711 }): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A2 | A3, never, R>
3712 <A, E, R, A2, A3>(
3713 self: Effect.Effect<A, E, R>,
3714 options: {
3715 readonly onFailure: (error: E) => A2
3716 readonly onSuccess: (value: A) => A3
3717 }
3718 ): Effect.Effect<A2 | A3, never, R>
3719} = dual(
3720 2,
3721 <A, E, R, A2, A3>(
3722 self: Effect.Effect<A, E, R>,
3723 options: {
3724 readonly onFailure: (error: E) => A2
3725 readonly onSuccess: (value: A) => A3
3726 }
3727 ): Effect.Effect<A2 | A3, never, R> => {
3728 if (effectIsExit(self)) {
3729 if (self._tag === "Success") return exitSucceed(options.onSuccess(self.value))
3730 const error = findError(self.cause)
3731 if (Result.isFailure(error)) return self as Exit.Exit<never>
3732 return exitSucceed(options.onFailure(error.success))
3733 }
3734 return match(self, options)
3735 }
3736)
3737
3738/** @internal */
3739export const matchCauseEager: {
3740 <E, A2, A, A3>(options: {
3741 readonly onFailure: (cause: Cause.Cause<E>) => A2
3742 readonly onSuccess: (value: A) => A3
3743 }): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A2 | A3, never, R>
3744 <A, E, R, A2, A3>(
3745 self: Effect.Effect<A, E, R>,
3746 options: {
3747 readonly onFailure: (cause: Cause.Cause<E>) => A2
3748 readonly onSuccess: (value: A) => A3
3749 }
3750 ): Effect.Effect<A2 | A3, never, R>
3751} = dual(
3752 2,
3753 <A, E, R, A2, A3>(
3754 self: Effect.Effect<A, E, R>,
3755 options: {
3756 readonly onFailure: (cause: Cause.Cause<E>) => A2
3757 readonly onSuccess: (value: A) => A3
3758 }
3759 ): Effect.Effect<A2 | A3, never, R> => {
3760 if (effectIsExit(self)) {
3761 if (self._tag === "Success") return exitSucceed(options.onSuccess(self.value))
3762 return exitSucceed(options.onFailure(self.cause))
3763 }
3764 return matchCause(self, options)
3765 }
3766)
3767
3768/** @internal */
3769export const exit = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<Exit.Exit<A, E>, never, R> =>
3770 effectIsExit(self) ? exitSucceed(self) : exitPrimitive(self)
3771
3772const exitPrimitive: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Exit.Exit<A, E>, never, R> =
3773 makePrimitive({
3774 op: "Exit",
3775 [evaluate](fiber): Primitive {
3776 fiber._stack.push(this)
3777 return this[args] as any
3778 },
3779 [contA](value, fiber, exit) {
3780 return fiber.succeedWith(exit ?? exitSucceed(value))
3781 },
3782 [contE](cause, fiber, exit) {
3783 return fiber.succeedWith(exit ?? exitFailCause(cause))
3784 }
3785 })
3786
3787// ----------------------------------------------------------------------------
3788// Condition checking
3789// ----------------------------------------------------------------------------
3790
3791/** @internal */
3792export const isFailure: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<boolean, never, R> = matchEager({
3793 onFailure: () => true,
3794 onSuccess: () => false
3795})
3796
3797/** @internal */
3798export const isSuccess: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<boolean, never, R> = matchEager({
3799 onFailure: () => false,
3800 onSuccess: () => true
3801})
3802
3803// ----------------------------------------------------------------------------
3804// delays & timeouts
3805// ----------------------------------------------------------------------------
3806
3807/** @internal */
3808export const delay: {
3809 (
3810 duration: Duration.Input
3811 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
3812 <A, E, R>(
3813 self: Effect.Effect<A, E, R>,
3814 duration: Duration.Input
3815 ): Effect.Effect<A, E, R>
3816} = dual(
3817 2,
3818 <A, E, R>(
3819 self: Effect.Effect<A, E, R>,
3820 duration: Duration.Input
3821 ): Effect.Effect<A, E, R> => andThen(sleep(duration), self)
3822)
3823
3824/** @internal */
3825export const timeoutOrElse: {
3826 <A2, E2, R2>(options: {
3827 readonly duration: Duration.Input
3828 readonly orElse: LazyArg<Effect.Effect<A2, E2, R2>>
3829 }): <A, E, R>(
3830 self: Effect.Effect<A, E, R>
3831 ) => Effect.Effect<A | A2, E | E2, R | R2>
3832 <A, E, R, A2, E2, R2>(
3833 self: Effect.Effect<A, E, R>,
3834 options: {
3835 readonly duration: Duration.Input
3836 readonly orElse: LazyArg<Effect.Effect<A2, E2, R2>>
3837 }
3838 ): Effect.Effect<A | A2, E | E2, R | R2>
3839} = dual(
3840 2,
3841 <A, E, R, A2, E2, R2>(
3842 self: Effect.Effect<A, E, R>,
3843 options: {
3844 readonly duration: Duration.Input
3845 readonly orElse: LazyArg<Effect.Effect<A2, E2, R2>>
3846 }
3847 ): Effect.Effect<A | A2, E | E2, R | R2> =>
3848 flatMap(
3849 timeoutOption(self, options.duration),
3850 (option): Effect.Effect<A | A2, E2, R2> => Option.isNone(option) ? options.orElse() : succeed(option.value)
3851 )
3852)
3853
3854/** @internal */
3855const timeoutErrorFromDuration = (duration: Duration.Duration): TimeoutError =>
3856 new TimeoutError(`Operation timed out after '${Duration.format(duration)}'`)
3857
3858/** @internal */
3859export const timeout: {
3860 (
3861 duration: Duration.Input
3862 ): <A, E, R>(
3863 self: Effect.Effect<A, E, R>
3864 ) => Effect.Effect<A, E | Cause.TimeoutError, R>
3865 <A, E, R>(
3866 self: Effect.Effect<A, E, R>,
3867 duration: Duration.Input
3868 ): Effect.Effect<A, E | Cause.TimeoutError, R>
3869} = dual(
3870 2,
3871 <A, E, R>(
3872 self: Effect.Effect<A, E, R>,
3873 duration: Duration.Input
3874 ): Effect.Effect<A, E | TimeoutError, R> => {
3875 const decoded = Duration.fromInputUnsafe(duration)
3876 return timeoutOrElse(self, {
3877 duration: decoded,
3878 orElse: () => fail(timeoutErrorFromDuration(decoded))
3879 })
3880 }
3881)
3882
3883/** @internal */
3884export const timeoutOption: {
3885 (
3886 duration: Duration.Input
3887 ): <A, E, R>(
3888 self: Effect.Effect<A, E, R>
3889 ) => Effect.Effect<Option.Option<A>, E, R>
3890 <A, E, R>(
3891 self: Effect.Effect<A, E, R>,
3892 duration: Duration.Input
3893 ): Effect.Effect<Option.Option<A>, E, R>
3894} = dual(
3895 2,
3896 <A, E, R>(
3897 self: Effect.Effect<A, E, R>,
3898 duration: Duration.Input
3899 ): Effect.Effect<Option.Option<A>, E, R> =>
3900 raceFirst(
3901 asSome(self),
3902 as(sleep(duration), Option.none())
3903 )
3904)
3905
3906/** @internal */
3907export const timed = <A, E, R>(
3908 self: Effect.Effect<A, E, R>
3909): Effect.Effect<[duration: Duration.Duration, result: A], E, R> =>
3910 clockWith((clock) => {
3911 const start = clock.monotonicTimeNanosUnsafe()
3912 return map(self, (a) => [Duration.nanos(clock.monotonicTimeNanosUnsafe() - start), a])
3913 })
3914
3915// ----------------------------------------------------------------------------
3916// resources & finalization
3917// ----------------------------------------------------------------------------
3918
3919/** @internal */
3920export const ScopeTypeId = "~effect/Scope"
3921
3922/** @internal */
3923export const ScopeCloseableTypeId = "~effect/Scope/Closeable"
3924
3925/** @internal */
3926export const scopeTag: Context.Service<Scope.Scope, Scope.Scope> = Context.Service<Scope.Scope>("effect/Scope")
3927
3928/** @internal */
3929export const scopeClose = <A, E>(self: Scope.Scope, exit_: Exit.Exit<A, E>) =>
3930 withFiber((fiber) => {
3931 const close = scopeCloseUnsafe(self, exit_)
3932 if (close === undefined) return void_
3933 fiberEnterUninterruptibleUnsafe(fiber)
3934 return close
3935 })
3936
3937/** @internal */
3938export const scopeCloseUnsafe = <A, E>(self: Scope.Scope, exit_: Exit.Exit<A, E>) => {
3939 const state = self.state
3940 if (state._tag === "Closed") return
3941 self.state = { _tag: "Closed", exit: exit_ }
3942 if (self.parent !== undefined) {
3943 scopeRemoveFinalizerUnsafe(self.parent, self)
3944 }
3945 if (state._tag === "Empty") return
3946 if (state.finalizer !== undefined) {
3947 return runFinalizer(state.finalizer, exit_)
3948 }
3949 const finalizers = state.finalizers!
3950 if (finalizers.size === 1) {
3951 return runFinalizer(finalizers.values().next().value!, exit_)
3952 }
3953 return scopeCloseFinalizers(self, finalizers, exit_)
3954}
3955
3956const runFinalizer = (
3957 finalizer: (exit: Exit.Exit<any, any>) => Effect.Effect<unknown>,
3958 exit_: Exit.Exit<any, any>
3959): Effect.Effect<unknown> => {
3960 try {
3961 return finalizer(exit_)
3962 } catch (defect) {
3963 return exitDie(defect)
3964 }
3965}
3966
3967const combineFinalizerCause = <A, E, XE, XR>(
3968 exit_: Exit.Exit<A, E>,
3969 finalizer: Effect.Effect<void, XE, XR>
3970): Effect.Effect<void, E | XE, XR> =>
3971 exitIsSuccess(exit_) ? finalizer : catchCause(finalizer, (cause) => failCause(causeCombine(exit_.cause, cause)))
3972
3973const scopeCloseFinalizers = fnUntraced(function*<A, E>(
3974 self: Scope.Scope,
3975 finalizers: NonNullable<Scope.State.Open["finalizers"]>,
3976 exit_: Exit.Exit<A, E>
3977) {
3978 let exits: Array<Exit.Exit<any, never>> = []
3979 const fibers: Array<Fiber.Fiber<any, never>> = []
3980 const arr = Array.from(finalizers.values())
3981 const parent = getCurrentFiber()!
3982 for (let i = arr.length - 1; i >= 0; i--) {
3983 const finalizer = arr[i]
3984 if (self.strategy === "sequential") {
3985 exits.push(yield* exit(runFinalizer(finalizer, exit_)))
3986 } else {
3987 fibers.push(forkUnsafe(parent, runFinalizer(finalizer, exit_), true, true, "inherit"))
3988 }
3989 }
3990 if (fibers.length > 0) {
3991 exits = yield* fiberAwaitAll(fibers)
3992 }
3993 return yield* exitAsVoidAll(exits)
3994})
3995
3996/** @internal */
3997export const scopeFork = (scope: Scope.Scope, finalizerStrategy?: "sequential" | "parallel") =>
3998 sync(() => scopeForkUnsafe(scope, finalizerStrategy))
3999
4000/** @internal */
4001export const scopeForkUnsafe = (scope: Scope.Scope, finalizerStrategy?: "sequential" | "parallel") => {
4002 const child = makeScope(finalizerStrategy, scope)
4003 if (scope.state._tag === "Closed") {
4004 child.state = scope.state
4005 return child
4006 }
4007 scopeAddFinalizerUnsafe(scope, child, (exit) => scopeClose(child, exit))
4008 return child
4009}
4010
4011/** @internal */
4012export const scopeAddFinalizerExit = (
4013 scope: Scope.Scope,
4014 finalizer: (exit: Exit.Exit<any, any>) => Effect.Effect<unknown>
4015): Effect.Effect<void> => {
4016 return suspend(() => {
4017 if (scope.state._tag === "Closed") {
4018 return finalizer(scope.state.exit)
4019 }
4020 scopeAddFinalizerUnsafe(scope, {}, finalizer)
4021 return void_
4022 })
4023}
4024
4025/** @internal */
4026export const scopeAddFinalizer = (
4027 scope: Scope.Scope,
4028 finalizer: Effect.Effect<unknown>
4029): Effect.Effect<void> => scopeAddFinalizerExit(scope, constant(finalizer))
4030
4031/** @internal */
4032export const scopeAddFinalizerUnsafe = (
4033 scope: Scope.Scope,
4034 key: {},
4035 finalizer: (exit: Exit.Exit<any, any>) => Effect.Effect<unknown>
4036): void => {
4037 if (scope.state._tag === "Empty") {
4038 scope.state = { _tag: "Open", finalizerKey: key, finalizer, finalizers: undefined }
4039 } else if (scope.state._tag === "Open") {
4040 const state = scope.state
4041 if (state.finalizer !== undefined) {
4042 state.finalizers = new Map([[state.finalizerKey!, state.finalizer]])
4043 state.finalizerKey = undefined
4044 state.finalizer = undefined
4045 state.finalizers.set(key, finalizer)
4046 } else {
4047 state.finalizers!.set(key, finalizer)
4048 }
4049 }
4050}
4051
4052/** @internal */
4053export const scopeRemoveFinalizerUnsafe = (
4054 scope: Scope.Scope,
4055 key: {}
4056): void => {
4057 if (scope.state._tag !== "Open") return
4058 const state = scope.state
4059 if (state.finalizerKey === key) {
4060 scope.state = constScopeEmpty
4061 } else if (state.finalizers !== undefined) {
4062 state.finalizers.delete(key)
4063 if (state.finalizers.size === 0) {
4064 scope.state = constScopeEmpty
4065 }
4066 }
4067}
4068
4069/** @internal */
4070export const scopeMakeUnsafe = (finalizerStrategy?: "sequential" | "parallel"): Scope.Closeable =>
4071 makeScope(finalizerStrategy, undefined)
4072
4073const makeScope = (
4074 finalizerStrategy: "sequential" | "parallel" = "sequential",
4075 parent: Scope.Scope | undefined
4076): Scope.Closeable => ({
4077 [ScopeCloseableTypeId]: ScopeCloseableTypeId,
4078 [ScopeTypeId]: ScopeTypeId,
4079 strategy: finalizerStrategy,
4080 parent,
4081 state: constScopeEmpty
4082})
4083
4084const constScopeEmpty = { _tag: "Empty" } as const
4085
4086/** @internal */
4087export const scopeMake = (finalizerStrategy?: "sequential" | "parallel"): Effect.Effect<Scope.Closeable> =>
4088 sync(() => scopeMakeUnsafe(finalizerStrategy))
4089
4090/** @internal */
4091export const scope: Effect.Effect<Scope.Scope, never, Scope.Scope> = scopeTag
4092
4093/** @internal */
4094export const provideScope: {
4095 (value: Scope.Scope): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Scope.Scope>>
4096 <A, E, R>(self: Effect.Effect<A, E, R>, value: Scope.Scope): Effect.Effect<A, E, Exclude<R, Scope.Scope>>
4097} = provideService(scopeTag)
4098
4099/** @internal */
4100export const scoped = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, Exclude<R, Scope.Scope>> =>
4101 withFiber((fiber) => {
4102 const prev = fiber.context
4103 const scope = scopeMakeUnsafe()
4104 fiber.setContext(Context.add(fiber.context, scopeTag, scope))
4105 onExitUnsafe<A, E>(fiber, (exit) => {
4106 fiber.setContext(prev)
4107 return scopeCloseUnsafe(scope, exit)
4108 })
4109 return self
4110 }) as any
4111
4112/** @internal */
4113export const scopeUse: {
4114 (
4115 scope: Scope.Closeable
4116 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Scope.Scope>>
4117 <A, E, R>(self: Effect.Effect<A, E, R>, scope: Scope.Closeable): Effect.Effect<A, E, Exclude<R, Scope.Scope>>
4118} = dual(
4119 2,
4120 <A, E, R>(self: Effect.Effect<A, E, R>, scope: Scope.Closeable): Effect.Effect<A, E, Exclude<R, Scope.Scope>> =>
4121 onExit(provideScope(self, scope), (exit) => suspend(() => scopeCloseUnsafe(scope, exit) ?? void_))
4122)
4123
4124/** @internal */
4125export const scopedWith = <A, E, R>(
4126 f: (scope: Scope.Scope) => Effect.Effect<A, E, R>
4127): Effect.Effect<A, E, R> =>
4128 suspend(() => {
4129 const scope = scopeMakeUnsafe()
4130 return onExit(f(scope), (exit) => suspend(() => scopeCloseUnsafe(scope, exit) ?? void_))
4131 })
4132
4133/** @internal */
4134export const acquireRelease = <A, E, R, R2>(
4135 acquire: Effect.Effect<A, E, R>,
4136 release: (a: A, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<unknown, never, R2>,
4137 options?: { readonly interruptible?: boolean }
4138): Effect.Effect<A, E, R | R2 | Scope.Scope> =>
4139 contextWith((context: Context.Context<R2>) =>
4140 uninterruptibleMask((restore) =>
4141 flatMap(
4142 scope,
4143 (scope) =>
4144 tap(
4145 options?.interruptible ? restore(acquire) : acquire,
4146 (a) => scopeAddFinalizerExit(scope, (exit) => provideContext(release(a, exit), context))
4147 )
4148 )
4149 )
4150 )
4151
4152/** @internal */
4153export const addFinalizer = <R>(
4154 finalizer: (exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void, never, R>
4155): Effect.Effect<void, never, R | Scope.Scope> =>
4156 flatMap(
4157 scope,
4158 (scope) =>
4159 contextWith((context: Context.Context<R>) =>
4160 scopeAddFinalizerExit(scope, (exit) => provideContext(finalizer(exit), context))
4161 )
4162 )
4163
4164const OnExitImpl = (function() {
4165 const Proto = makePrimitiveProto({
4166 op: "OnExit",
4167 [evaluate](this: any, fiber: FiberImpl) {
4168 fiber._stack.push(this)
4169 return this.effect
4170 },
4171 [contAll](this: any, fiber) {
4172 if (fiber.interruptible && this.interruptible !== true) {
4173 fiber._stack.push(setInterruptibleTrue)
4174 fiber.interruptible = false
4175 }
4176 },
4177 [contA](this: any, value, _, exit) {
4178 exit ??= exitSucceed(value)
4179 let eff: Effect.Effect<void, any, any> | undefined
4180 try {
4181 eff = this.onExit(exit)
4182 } catch (defect) {
4183 eff = exitDie(defect)
4184 }
4185 return eff ? flatMap(eff, (_) => exit) : exit
4186 },
4187 [contE](this: any, cause, _, exit) {
4188 exit ??= exitFailCause(cause)
4189 let eff: Effect.Effect<void, any, any> | undefined
4190 try {
4191 eff = this.onExit(exit)
4192 } catch (defect) {
4193 eff = exitDie(defect)
4194 }
4195 return eff ? flatMap(combineFinalizerCause(exit, eff), (_) => exit) : exit
4196 }
4197 })
4198 const OnExitImpl = function(this: any, effect: any, onExit: any, interruptible: any) {
4199 this.effect = effect
4200 this.onExit = onExit
4201 this.interruptible = interruptible
4202 } as unknown as PrimitiveCtor<[effect: any, onExit: any, interruptible: any]>
4203 OnExitImpl.prototype = Proto
4204 return OnExitImpl
4205})()
4206
4207/** @internal */
4208export const onExitPrimitive: <A, E, R, XE = never, XR = never>(
4209 self: Effect.Effect<A, E, R>,
4210 f: (exit: Exit.Exit<A, E>) => Effect.Effect<void, XE, XR> | undefined,
4211 interruptible?: boolean
4212) => Effect.Effect<A, E | XE, R | XR> = (effect, onExit, interruptible) =>
4213 new OnExitImpl(effect, onExit, interruptible) as any
4214
4215/**
4216 * Pushes an exit finalizer for the current `withFiber` evaluation. Only call inside `withFiber`.
4217 * @internal
4218 */
4219export const onExitUnsafe = <A = unknown, E = unknown>(
4220 fiber: Fiber.Fiber<unknown, unknown>,
4221 f: (exit: Exit.Exit<A, E>) => Effect.Effect<void, unknown, unknown> | undefined
4222): void => {
4223 ;(fiber as FiberImpl)._stack.push(new OnExitImpl(undefined, f, undefined))
4224}
4225
4226/** @internal */
4227export const onExit: {
4228 <A, E, XE = never, XR = never>(
4229 f: (exit: Exit.Exit<A, E>) => Effect.Effect<void, XE, XR>
4230 ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR>
4231 <A, E, R, XE = never, XR = never>(
4232 self: Effect.Effect<A, E, R>,
4233 f: (exit: Exit.Exit<A, E>) => Effect.Effect<void, XE, XR>
4234 ): Effect.Effect<A, E | XE, R | XR>
4235} = dual(2, onExitPrimitive)
4236
4237/** @internal */
4238export const ensuring: {
4239 <XE, XR>(
4240 finalizer: Effect.Effect<void, XE, XR>
4241 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR>
4242 <A, E, R, XE, XR>(
4243 self: Effect.Effect<A, E, R>,
4244 finalizer: Effect.Effect<void, XE, XR>
4245 ): Effect.Effect<A, E | XE, R | XR>
4246} = dual(
4247 2,
4248 <A, E, R, XE, XR>(
4249 self: Effect.Effect<A, E, R>,
4250 finalizer: Effect.Effect<void, XE, XR>
4251 ): Effect.Effect<A, E | XE, R | XR> => onExit(self, (_) => finalizer)
4252)
4253
4254/** @internal */
4255export const onExitIf: {
4256 <A, E, XE, XR>(
4257 predicate: Predicate.Predicate<Exit.Exit<NoInfer<A>, NoInfer<E>>>,
4258 f: (exit: Exit.Exit<NoInfer<A>, NoInfer<E>>) => Effect.Effect<void, XE, XR>
4259 ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR>
4260 <A, E, R, XE, XR>(
4261 self: Effect.Effect<A, E, R>,
4262 predicate: Predicate.Predicate<Exit.Exit<NoInfer<A>, NoInfer<E>>>,
4263 f: (exit: Exit.Exit<NoInfer<A>, NoInfer<E>>) => Effect.Effect<void, XE, XR>
4264 ): Effect.Effect<A, E | XE, R | XR>
4265} = dual(
4266 3,
4267 <A, E, R, XE, XR>(
4268 self: Effect.Effect<A, E, R>,
4269 predicate: Predicate.Predicate<Exit.Exit<NoInfer<A>, NoInfer<E>>>,
4270 f: (exit: Exit.Exit<NoInfer<A>, NoInfer<E>>) => Effect.Effect<void, XE, XR>
4271 ): Effect.Effect<A, E | XE, R | XR> =>
4272 onExit(self, (exit) => {
4273 if (!predicate(exit)) {
4274 return void_
4275 }
4276 return f(exit)
4277 })
4278)
4279
4280/** @internal */
4281export const onExitFilter: {
4282 <A, E, XE, XR, B, X>(
4283 filter: Filter.Filter<Exit.Exit<NoInfer<A>, NoInfer<E>>, B, X>,
4284 f: (b: B, exit: Exit.Exit<NoInfer<A>, NoInfer<E>>) => Effect.Effect<void, XE, XR>
4285 ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR>
4286 <A, E, R, XE, XR, B, X>(
4287 self: Effect.Effect<A, E, R>,
4288 filter: Filter.Filter<Exit.Exit<NoInfer<A>, NoInfer<E>>, B, X>,
4289 f: (b: B, exit: Exit.Exit<NoInfer<A>, NoInfer<E>>) => Effect.Effect<void, XE, XR>
4290 ): Effect.Effect<A, E | XE, R | XR>
4291} = dual(
4292 3,
4293 <A, E, R, XE, XR, B, X>(
4294 self: Effect.Effect<A, E, R>,
4295 filter: Filter.Filter<Exit.Exit<NoInfer<A>, NoInfer<E>>, B, X>,
4296 f: (b: B, exit: Exit.Exit<NoInfer<A>, NoInfer<E>>) => Effect.Effect<void, XE, XR>
4297 ): Effect.Effect<A, E | XE, R | XR> =>
4298 onExit(self, (exit) => {
4299 const b = filter(exit)
4300 return Result.isFailure(b) ? void_ : f(b.success, exit)
4301 })
4302)
4303
4304/** @internal */
4305export const onError: {
4306 <A, E, XE, XR>(
4307 f: (cause: Cause.Cause<NoInfer<E>>) => Effect.Effect<void, XE, XR>
4308 ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR>
4309 <A, E, R, XE, XR>(
4310 self: Effect.Effect<A, E, R>,
4311 f: (cause: Cause.Cause<NoInfer<E>>) => Effect.Effect<void, XE, XR>
4312 ): Effect.Effect<A, E | XE, R | XR>
4313} = dual(
4314 2,
4315 <A, E, R, XE, XR>(
4316 self: Effect.Effect<A, E, R>,
4317 f: (cause: Cause.Cause<NoInfer<E>>) => Effect.Effect<void, XE, XR>
4318 ): Effect.Effect<A, E | XE, R | XR> => onExitFilter(self, exitFilterCause as any, f as any) as any
4319)
4320
4321/** @internal */
4322export const onErrorIf: {
4323 <E, XE, XR>(
4324 predicate: Predicate.Predicate<Cause.Cause<E>>,
4325 f: (cause: Cause.Cause<E>) => Effect.Effect<void, XE, XR>
4326 ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR>
4327 <A, E, R, XE, XR>(
4328 self: Effect.Effect<A, E, R>,
4329 predicate: Predicate.Predicate<Cause.Cause<E>>,
4330 f: (cause: Cause.Cause<E>) => Effect.Effect<void, XE, XR>
4331 ): Effect.Effect<A, E | XE, R | XR>
4332} = dual(
4333 3,
4334 <A, E, R, XE, XR>(
4335 self: Effect.Effect<A, E, R>,
4336 predicate: Predicate.Predicate<Cause.Cause<E>>,
4337 f: (cause: Cause.Cause<E>) => Effect.Effect<void, XE, XR>
4338 ): Effect.Effect<A, E | XE, R | XR> =>
4339 onExitIf(
4340 self,
4341 (exit): exit is Exit.Failure<A, E> => {
4342 if (exit._tag !== "Failure") {
4343 return false
4344 }
4345 return predicate(exit.cause)
4346 },
4347 (exit) => f((exit as Exit.Failure<A, E>).cause)
4348 ) as any
4349)
4350
4351/** @internal */
4352export const onErrorFilter: {
4353 <A, E, EB, X, XE, XR>(
4354 filter: Filter.Filter<Cause.Cause<E>, EB, X>,
4355 f: (failure: EB, cause: Cause.Cause<E>) => Effect.Effect<void, XE, XR>
4356 ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR>
4357 <A, E, R, EB, X, XE, XR>(
4358 self: Effect.Effect<A, E, R>,
4359 filter: Filter.Filter<Cause.Cause<E>, EB, X>,
4360 f: (failure: EB, cause: Cause.Cause<E>) => Effect.Effect<void, XE, XR>
4361 ): Effect.Effect<A, E | XE, R | XR>
4362} = dual(
4363 3,
4364 <A, E, R, EB, X, XE, XR>(
4365 self: Effect.Effect<A, E, R>,
4366 filter: Filter.Filter<Cause.Cause<E>, EB, X>,
4367 f: (failure: EB, cause: Cause.Cause<E>) => Effect.Effect<void, XE, XR>
4368 ): Effect.Effect<A, E | XE, R | XR> =>
4369 onExit(self, (exit) => {
4370 if (exit._tag !== "Failure") {
4371 return void_
4372 }
4373 const result = filter(exit.cause)
4374 return Result.isFailure(result) ? void_ : f(result.success, exit.cause)
4375 })
4376)
4377
4378/** @internal */
4379export const onInterrupt: {
4380 <XE, XR>(
4381 finalizer: (interruptors: ReadonlySet<number>) => Effect.Effect<void, XE, XR>
4382 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR>
4383 <A, E, R, XE, XR>(
4384 self: Effect.Effect<A, E, R>,
4385 finalizer: (interruptors: ReadonlySet<number>) => Effect.Effect<void, XE, XR>
4386 ): Effect.Effect<A, E | XE, R | XR>
4387} = dual(
4388 2,
4389 <A, E, R, XE, XR>(
4390 self: Effect.Effect<A, E, R>,
4391 finalizer: (interruptors: ReadonlySet<number>) => Effect.Effect<void, XE, XR>
4392 ): Effect.Effect<A, E | XE, R | XR> => onErrorFilter(causeFilterInterruptors as any, finalizer)(self) as any
4393)
4394
4395/** @internal */
4396export const acquireUseRelease = <Resource, E, R, A, E2, R2, E3, R3>(
4397 acquire: Effect.Effect<Resource, E, R>,
4398 use: (a: Resource) => Effect.Effect<A, E2, R2>,
4399 release: (a: Resource, exit: Exit.Exit<A, E2>) => Effect.Effect<void, E3, R3>
4400): Effect.Effect<A, E | E2 | E3, R | R2 | R3> =>
4401 uninterruptibleMask((restore) =>
4402 flatMap(acquire, (a) =>
4403 onExitPrimitive(
4404 suspend(() => restore(use(a))),
4405 (exit) => release(a, exit),
4406 true
4407 ))
4408 )
4409
4410/** @internal */
4411export const acquireDisposable = <A extends AsyncDisposable | Disposable, E, R>(
4412 acquire: Effect.Effect<A, E, R>
4413): Effect.Effect<A, E, R | Scope.Scope> =>
4414 acquireRelease(acquire, (resource) =>
4415 hasProperty(resource, Symbol.asyncDispose)
4416 ? promise(() => resource[Symbol.asyncDispose]())
4417 : sync(() => resource[Symbol.dispose]()))
4418
4419// ----------------------------------------------------------------------------
4420// Caching
4421// ----------------------------------------------------------------------------
4422
4423/** @internal */
4424export const cachedInvalidateWithTTL: {
4425 <A, E>(timeToLive: (exit: Exit.Exit<A, E>) => Duration.Input): <R>(
4426 self: Effect.Effect<A, E, R>
4427 ) => Effect.Effect<[Effect.Effect<A, E, R>, Effect.Effect<void>]>
4428 (timeToLive: Duration.Input): <A, E, R>(
4429 self: Effect.Effect<A, E, R>
4430 ) => Effect.Effect<[Effect.Effect<A, E, R>, Effect.Effect<void>]>
4431 <A, E>(timeToLive: Duration.Input | ((exit: Exit.Exit<A, E>) => Duration.Input)): <R>(
4432 self: Effect.Effect<A, E, R>
4433 ) => Effect.Effect<[Effect.Effect<A, E, R>, Effect.Effect<void>]>
4434 <A, E, R>(
4435 self: Effect.Effect<A, E, R>,
4436 timeToLive: Duration.Input | ((exit: Exit.Exit<A, E>) => Duration.Input)
4437 ): Effect.Effect<[Effect.Effect<A, E, R>, Effect.Effect<void>]>
4438} = dual(2, <A, E, R>(
4439 self: Effect.Effect<A, E, R>,
4440 ttl: Duration.Input | ((exit: Exit.Exit<A, E>) => Duration.Input)
4441): Effect.Effect<[Effect.Effect<A, E, R>, Effect.Effect<void>]> =>
4442 sync(() =>
4443 makeCachedUnsafe(
4444 self,
4445 typeof ttl === "function"
4446 ? (exit: Exit.Exit<A, E>) => Duration.toMillis(Duration.fromInputUnsafe(ttl(exit)))
4447 : constant(Duration.toMillis(Duration.fromInputUnsafe(ttl)))
4448 )
4449 ))
4450
4451const infiniteTTL = constant(Infinity)
4452
4453interface CachedRun<A, E> {
4454 fiber: FiberImpl<A, E> | undefined
4455 awaiters: number
4456}
4457
4458const makeCachedUnsafe = <A, E, R>(
4459 self: Effect.Effect<A, E, R>,
4460 ttlMillis: (exit: Exit.Exit<A, E>) => number
4461): [Effect.Effect<A, E, R>, Effect.Effect<void>] => {
4462 let expiresAt = 0
4463 let exit: Exit.Exit<A, E> | undefined
4464 let current: CachedRun<A, E> | undefined
4465
4466 const join = (fiber: Fiber.Fiber<unknown, unknown>, run: CachedRun<A, E>): Effect.Effect<A, E> => {
4467 run.awaiters++
4468 onExitUnsafe(fiber, () => {
4469 // Abandon the run once every caller has left, unless it already finished.
4470 if (--run.awaiters > 0 || current !== run) return
4471 // Detach it first so new callers start a fresh run instead of joining
4472 // one that is being interrupted.
4473 current = undefined
4474 return fiberInterrupt(run.fiber!)
4475 })
4476 return fiberJoin(run.fiber!)
4477 }
4478
4479 return [
4480 withFiber((fiber) => {
4481 if (current !== undefined) return join(fiber, current)
4482 if (
4483 exit !== undefined &&
4484 (expiresAt === Infinity || fiber.getRef(ClockRef).currentTimeMillisUnsafe() < expiresAt)
4485 ) {
4486 return exit
4487 }
4488 exit = undefined
4489 const clock = fiber.getRef(ClockRef)
4490 const run: CachedRun<A, E> = { fiber: undefined, awaiters: 0 }
4491 current = run
4492 run.fiber = forkUnsafe(
4493 fiber,
4494 onExitPrimitive(self, (exit_) => {
4495 // An abandoned run must not overwrite or clear a replacement run.
4496 if (current !== run) return
4497 current = undefined
4498 // Interruption is abandonment, so it is never cached.
4499 if (exitHasInterrupts(exit_)) return
4500 const duration = ttlMillis(exit_)
4501 expiresAt = duration === Infinity ? Infinity : clock.currentTimeMillisUnsafe() + duration
4502 exit = exit_
4503 }),
4504 true,
4505 true
4506 )
4507 return run.fiber._exit ?? join(fiber, run)
4508 }),
4509 sync(() => {
4510 exit = undefined
4511 })
4512 ]
4513}
4514
4515/** @internal */
4516export const cachedWithTTL: {
4517 <A, E>(
4518 timeToLive: (exit: Exit.Exit<A, E>) => Duration.Input
4519 ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Effect.Effect<A, E, R>>
4520 (
4521 timeToLive: Duration.Input
4522 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Effect.Effect<A, E, R>>
4523 <A, E>(
4524 timeToLive: Duration.Input | ((exit: Exit.Exit<A, E>) => Duration.Input)
4525 ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Effect.Effect<A, E, R>>
4526 <A, E, R>(
4527 self: Effect.Effect<A, E, R>,
4528 timeToLive: Duration.Input | ((exit: Exit.Exit<A, E>) => Duration.Input)
4529 ): Effect.Effect<Effect.Effect<A, E, R>>
4530} = dual(
4531 2,
4532 <A, E, R>(
4533 self: Effect.Effect<A, E, R>,
4534 timeToLive: Duration.Input | ((exit: Exit.Exit<A, E>) => Duration.Input)
4535 ): Effect.Effect<Effect.Effect<A, E, R>> => map(cachedInvalidateWithTTL(self, timeToLive), (tuple) => tuple[0])
4536)
4537
4538/** @internal */
4539export const cached = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<Effect.Effect<A, E, R>> =>
4540 sync(() => makeCachedUnsafe(self, infiniteTTL)[0])
4541
4542// ----------------------------------------------------------------------------
4543// interruption
4544// ----------------------------------------------------------------------------
4545
4546/** @internal */
4547export const interrupt: Effect.Effect<never> = withFiber((fiber) => failCause(causeInterrupt(fiber.id)))
4548
4549/** @internal */
4550export const uninterruptible = <A, E, R>(
4551 self: Effect.Effect<A, E, R>
4552): Effect.Effect<A, E, R> =>
4553 withFiber((fiber) => {
4554 if (!fiber.interruptible) return self
4555 fiber.interruptible = false
4556 fiber._stack.push(setInterruptibleTrue)
4557 return self
4558 })
4559
4560const setInterruptible: (interruptible: boolean) => Primitive = makePrimitive({
4561 op: "SetInterruptible",
4562 [contAll](fiber) {
4563 fiber.interruptible = this[args]
4564 if (fiber._interruptedCause && fiber.interruptible) {
4565 return () => failCause(fiber._interruptedCause!)
4566 }
4567 }
4568})
4569const setInterruptibleTrue = setInterruptible(true)
4570const setInterruptibleFalse = setInterruptible(false)
4571
4572const setFiberInterruptible = (fiber: FiberImpl): Effect.Effect<never> | undefined => {
4573 fiber.interruptible = true
4574 fiber._stack.push(setInterruptibleFalse)
4575 if (fiber._interruptedCause) return failCause(fiber._interruptedCause)
4576}
4577
4578/**
4579 * Makes the current fiber uninterruptible for the returned effect without an
4580 * extra primitive. Call only within `withFiber`.
4581 *
4582 * @internal
4583 */
4584export const fiberEnterUninterruptibleUnsafe = (fiber: Fiber.Fiber<unknown, unknown>): void => {
4585 const impl = fiber as FiberImpl
4586 if (!impl.interruptible) return
4587 impl.interruptible = false
4588 impl._stack.push(setInterruptibleTrue)
4589}
4590
4591/**
4592 * Makes the current fiber interruptible for the returned effect without an
4593 * extra primitive. Call only within `withFiber` and return any pending
4594 * interruption it produces.
4595 *
4596 * @internal
4597 */
4598export const fiberEnterInterruptibleUnsafe = (
4599 fiber: Fiber.Fiber<unknown, unknown>
4600): Effect.Effect<never> | undefined => {
4601 const impl = fiber as FiberImpl
4602 if (impl.interruptible) return undefined
4603 return setFiberInterruptible(impl)
4604}
4605
4606/** @internal */
4607export const interruptible = <A, E, R>(
4608 self: Effect.Effect<A, E, R>
4609): Effect.Effect<A, E, R> =>
4610 withFiber((fiber) => {
4611 if (fiber.interruptible) return self
4612 return setFiberInterruptible(fiber) ?? self
4613 })
4614
4615/** @internal */
4616export const uninterruptibleMask = <A, E, R>(
4617 f: (
4618 restore: <A, E, R>(
4619 effect: Effect.Effect<A, E, R>
4620 ) => Effect.Effect<A, E, R>
4621 ) => Effect.Effect<A, E, R>
4622): Effect.Effect<A, E, R> =>
4623 withFiber((fiber) => {
4624 if (!fiber.interruptible) return f(identity)
4625 fiber.interruptible = false
4626 fiber._stack.push(setInterruptibleTrue)
4627 return f(interruptible)
4628 })
4629
4630/** @internal */
4631export const interruptibleMask = <A, E, R>(
4632 f: (
4633 restore: <A, E, R>(
4634 effect: Effect.Effect<A, E, R>
4635 ) => Effect.Effect<A, E, R>
4636 ) => Effect.Effect<A, E, R>
4637): Effect.Effect<A, E, R> =>
4638 withFiber((fiber) => {
4639 if (fiber.interruptible) return f(identity)
4640 const interrupted = setFiberInterruptible(fiber)
4641 const effect = f(uninterruptible)
4642 return interrupted ?? effect
4643 })
4644
4645/** @internal */
4646export const abortSignal: Effect.Effect<AbortSignal, never, Scope.Scope> = map(
4647 acquireRelease(
4648 sync(() => new AbortController()),
4649 (controller) => sync(() => controller.abort())
4650 ),
4651 (_) => _.signal
4652)
4653
4654// ========================================================================
4655// collecting & elements
4656// ========================================================================
4657
4658/** @internal */
4659export const all = <
4660 const Arg extends
4661 | Iterable<Effect.Effect<any, any, any>>
4662 | Record<string, Effect.Effect<any, any, any>>,
4663 O extends {
4664 readonly concurrency?: Concurrency | undefined
4665 readonly discard?: boolean | undefined
4666 readonly mode?: "default" | "result" | undefined
4667 }
4668>(
4669 arg: Arg,
4670 options?: O
4671): Effect.All.Return<Arg, O> => {
4672 if (isIterable(arg)) {
4673 return options?.mode === "result"
4674 ? (forEach as any)(arg, result, options)
4675 : (forEach as any)(arg, identity, options)
4676 } else if (options?.discard) {
4677 return options.mode === "result"
4678 ? (forEach as any)(Object.values(arg), result, options)
4679 : (forEach as any)(Object.values(arg), identity, options)
4680 }
4681 return suspend(() => {
4682 const out: Record<string, unknown> = {}
4683 return as(
4684 forEach(
4685 Object.entries(arg),
4686 ([key, effect]) =>
4687 map(options?.mode === "result" ? result(effect) : effect, (value) => {
4688 InternalRecord.assignProperty(out, key, value)
4689 }),
4690 {
4691 discard: true,
4692 concurrency: options?.concurrency
4693 }
4694 ),
4695 out
4696 )
4697 }) as any
4698}
4699
4700/** @internal */
4701export const partition: {
4702 <A, B, E, R>(
4703 f: (a: A, i: number) => Effect.Effect<B, E, R>,
4704 options?: { readonly concurrency?: Concurrency | undefined }
4705 ): (elements: Iterable<A>) => Effect.Effect<[passes: Array<B>, fails: Array<E>], never, R>
4706 <A, B, E, R>(
4707 elements: Iterable<A>,
4708 f: (a: A, i: number) => Effect.Effect<B, E, R>,
4709 options?: { readonly concurrency?: Concurrency | undefined }
4710 ): Effect.Effect<[passes: Array<B>, fails: Array<E>], never, R>
4711} = dual(
4712 (args) => isIterable(args[0]) && !isEffect(args[0]),
4713 <A, B, E, R>(
4714 elements: Iterable<A>,
4715 f: (a: A, i: number) => Effect.Effect<B, E, R>,
4716 options?: { readonly concurrency?: Concurrency | undefined }
4717 ): Effect.Effect<[passes: Array<B>, fails: Array<E>], never, R> =>
4718 map(
4719 forEach(elements, (a, i) => result(f(a, i)), options),
4720 (results) => Arr.partition(results, identity)
4721 )
4722)
4723
4724/** @internal */
4725export const reduce: {
4726 <Z, A, E, R>(
4727 zero: LazyArg<Z>,
4728 f: (z: Z, a: A, i: number) => Effect.Effect<Z, E, R>
4729 ): (elements: Iterable<A>) => Effect.Effect<Z, E, R>
4730 <A, Z, E, R>(
4731 elements: Iterable<A>,
4732 zero: LazyArg<Z>,
4733 f: (z: Z, a: A, i: number) => Effect.Effect<Z, E, R>
4734 ): Effect.Effect<Z, E, R>
4735} = dual(
4736 3,
4737 <A, Z, E, R>(
4738 elements: Iterable<A>,
4739 zero: LazyArg<Z>,
4740 f: (z: Z, a: A, i: number) => Effect.Effect<Z, E, R>
4741 ) => {
4742 const arr = Arr.fromIterable(elements)
4743 if (arr.length === 0) return sync(zero)
4744 return suspend(() => {
4745 let index = 0
4746 let state = zero()
4747 return map(
4748 whileLoop({
4749 while: () => index < arr.length,
4750 body: () => f(state, arr[index], index),
4751 step(next) {
4752 state = next
4753 index++
4754 }
4755 }),
4756 () => state
4757 )
4758 })
4759 }
4760)
4761
4762/** @internal */
4763export const validate: {
4764 <A, B, E, R>(
4765 f: (a: A, i: number) => Effect.Effect<B, E, R>,
4766 options?: {
4767 readonly concurrency?: Concurrency | undefined
4768 readonly discard?: false | undefined
4769 } | undefined
4770 ): (elements: Iterable<A>) => Effect.Effect<Array<B>, Arr.NonEmptyArray<E>, R>
4771 <A, B, E, R>(
4772 f: (a: A, i: number) => Effect.Effect<B, E, R>,
4773 options: {
4774 readonly concurrency?: Concurrency | undefined
4775 readonly discard: true
4776 }
4777 ): (elements: Iterable<A>) => Effect.Effect<void, Arr.NonEmptyArray<E>, R>
4778 <A, B, E, R>(
4779 elements: Iterable<A>,
4780 f: (a: A, i: number) => Effect.Effect<B, E, R>,
4781 options?: {
4782 readonly concurrency?: Concurrency | undefined
4783 readonly discard?: false | undefined
4784 } | undefined
4785 ): Effect.Effect<Array<B>, Arr.NonEmptyArray<E>, R>
4786 <A, B, E, R>(
4787 elements: Iterable<A>,
4788 f: (a: A, i: number) => Effect.Effect<B, E, R>,
4789 options: {
4790 readonly concurrency?: Concurrency | undefined
4791 readonly discard: true
4792 }
4793 ): Effect.Effect<void, Arr.NonEmptyArray<E>, R>
4794} = dual(
4795 (args) => isIterable(args[0]) && !isEffect(args[0]),
4796 <A, B, E, R>(
4797 elements: Iterable<A>,
4798 f: (a: A, i: number) => Effect.Effect<B, E, R>,
4799 options?: {
4800 readonly concurrency?: Concurrency | undefined
4801 readonly discard?: boolean | undefined
4802 } | undefined
4803 ): Effect.Effect<Array<B> | void, Arr.NonEmptyArray<E>, R> =>
4804 flatMap(
4805 partition(elements, f, { concurrency: options?.concurrency }),
4806 ([passes, fails]) => {
4807 if (Arr.isArrayNonEmpty(fails)) {
4808 return fail(fails)
4809 }
4810 return options?.discard ? void_ : succeed(passes)
4811 }
4812 )
4813)
4814
4815/** @internal */
4816export const findFirst: {
4817 <A, E, R>(
4818 predicate: (a: NoInfer<A>, i: number) => Effect.Effect<boolean, E, R>
4819 ): (elements: Iterable<A>) => Effect.Effect<Option.Option<A>, E, R>
4820 <A, E, R>(
4821 elements: Iterable<A>,
4822 predicate: (a: NoInfer<A>, i: number) => Effect.Effect<boolean, E, R>
4823 ): Effect.Effect<Option.Option<A>, E, R>
4824} = dual(
4825 (args) => isIterable(args[0]) && !isEffect(args[0]),
4826 <A, E, R>(
4827 elements: Iterable<A>,
4828 predicate: (a: A, i: number) => Effect.Effect<boolean, E, R>
4829 ): Effect.Effect<Option.Option<A>, E, R> =>
4830 suspend(() => {
4831 const iterator = elements[Symbol.iterator]()
4832 const next = iterator.next()
4833 if (!next.done) {
4834 return findFirstLoop(iterator, 0, predicate, next.value)
4835 }
4836 return succeed(Option.none())
4837 })
4838)
4839
4840const findFirstLoop = <A, E, R>(
4841 iterator: Iterator<A>,
4842 index: number,
4843 predicate: (a: A, i: number) => Effect.Effect<boolean, E, R>,
4844 value: A
4845): Effect.Effect<Option.Option<A>, E, R> =>
4846 flatMap(predicate(value, index), (keep) => {
4847 if (keep) {
4848 return succeed(Option.some(value))
4849 }
4850 const next = iterator.next()
4851 if (!next.done) {
4852 return findFirstLoop(iterator, index + 1, predicate, next.value)
4853 }
4854 return succeed(Option.none())
4855 })
4856
4857/** @internal */
4858export const findFirstFilter: {
4859 <A, B, X, E, R>(
4860 filter: (input: NoInfer<A>, i: number) => Effect.Effect<Result.Result<B, X>, E, R>
4861 ): (elements: Iterable<A>) => Effect.Effect<Option.Option<B>, E, R>
4862 <A, B, X, E, R>(
4863 elements: Iterable<A>,
4864 filter: (input: NoInfer<A>, i: number) => Effect.Effect<Result.Result<B, X>, E, R>
4865 ): Effect.Effect<Option.Option<B>, E, R>
4866} = dual(
4867 (args) => isIterable(args[0]) && !isEffect(args[0]),
4868 <A, B, X, E, R>(
4869 elements: Iterable<A>,
4870 filter: (input: A, i: number) => Effect.Effect<Result.Result<B, X>, E, R>
4871 ): Effect.Effect<Option.Option<B>, E, R> =>
4872 suspend(() => {
4873 const iterator = elements[Symbol.iterator]()
4874 const next = iterator.next()
4875 if (!next.done) {
4876 return findFirstFilterLoop(iterator, 0, filter, next.value)
4877 }
4878 return succeed(Option.none())
4879 })
4880)
4881
4882const findFirstFilterLoop = <A, B, X, E, R>(
4883 iterator: Iterator<A>,
4884 index: number,
4885 filter: (input: A, i: number) => Effect.Effect<Result.Result<B, X>, E, R>,
4886 value: A
4887): Effect.Effect<Option.Option<B>, E, R> =>
4888 flatMap(filter(value, index), (result) => {
4889 if (Result.isSuccess(result)) {
4890 return succeed(Option.some(result.success))
4891 }
4892 const next = iterator.next()
4893 if (!next.done) {
4894 return findFirstFilterLoop(iterator, index + 1, filter, next.value)
4895 }
4896 return succeed(Option.none())
4897 })
4898
4899/** @internal */
4900export const whileLoop: <A, E, R>(options: {
4901 readonly while: LazyArg<boolean>
4902 readonly body: LazyArg<Effect.Effect<A, E, R>>
4903 readonly step: (a: A) => void
4904}) => Effect.Effect<void, E, R> = makePrimitive({
4905 op: "While",
4906 [contA](value, fiber) {
4907 this[args].step(value)
4908 if (this[args].while()) {
4909 fiber._stack.push(this)
4910 return this[args].body()
4911 }
4912 return exitVoid
4913 },
4914 [evaluate](fiber) {
4915 if (this[args].while()) {
4916 fiber._stack.push(this)
4917 return this[args].body()
4918 }
4919 return exitVoid
4920 }
4921})
4922
4923/** @internal */
4924export const forEach: {
4925 <A, B, E, R, S extends Iterable<A> = Iterable<A>, const Discard extends boolean = false>(
4926 f: (a: A, i: number) => Effect.Effect<B, E, R>,
4927 options?: {
4928 readonly concurrency?: Concurrency | undefined
4929 readonly discard?: Discard | undefined
4930 } | undefined
4931 ): (
4932 self: [S] extends [never] ? Iterable<A> : S
4933 ) => Effect.Effect<Discard extends false ? Arr.ReadonlyArray.With<S, B> : void, E, R>
4934 <B, E, R, S extends Iterable<any>, const Discard extends boolean = false>(
4935 self: S,
4936 f: (a: Arr.ReadonlyArray.Infer<S>, i: number) => Effect.Effect<B, E, R>,
4937 options?: {
4938 readonly concurrency?: Concurrency | undefined
4939 readonly discard?: Discard | undefined
4940 } | undefined
4941 ): Effect.Effect<Discard extends false ? Arr.ReadonlyArray.With<S, B> : void, E, R>
4942} = dual((args) => typeof args[1] === "function", <A, B, E, R>(
4943 iterable: Iterable<A>,
4944 f: (a: A, index: number) => Effect.Effect<B, E, R>,
4945 options?: {
4946 readonly concurrency?: Concurrency | undefined
4947 readonly discard?: boolean | undefined
4948 }
4949): Effect.Effect<any, E, R> =>
4950 suspend(() => {
4951 const concurrency = resolveConcurrency(options?.concurrency)
4952
4953 if (concurrency === 1) {
4954 return forEachSequential(iterable, f, options)
4955 }
4956
4957 const items = Arr.fromIterable(iterable)
4958 let length = items.length
4959 if (length === 0) {
4960 return options?.discard ? void_ : succeed([])
4961 }
4962
4963 const out: Array<B> | undefined = options?.discard
4964 ? undefined
4965 : new Array(length)
4966 const eff = forEachConcurrent({ f, out }, items, { concurrency })
4967 return eff ? as(eff, out as any) : succeed(out as any)
4968 }))
4969
4970/** @internal */
4971export const head = <A, E, R>(
4972 self: Effect.Effect<Iterable<A>, E, R>
4973): Effect.Effect<A, E | Cause.NoSuchElementError, R> =>
4974 flatMap(self, (elements) => {
4975 const result = elements[Symbol.iterator]().next()
4976 return result.done ? fail(new NoSuchElementError()) : succeed(result.value)
4977 })
4978
4979const forEachSequential = <A, B, E, R>(
4980 iterable: Iterable<A>,
4981 f: (a: A, index: number) => Effect.Effect<B, E, R>,
4982 options?: {
4983 readonly discard?: boolean | undefined
4984 }
4985) =>
4986 suspend(() => {
4987 const out: Array<B> | undefined = options?.discard ? undefined : []
4988 const iterator = iterable[Symbol.iterator]()
4989 let state = iterator.next()
4990 let index = 0
4991 return as(
4992 whileLoop({
4993 while: () => !state.done,
4994 body: () => f(state.value!, index++),
4995 step: (b) => {
4996 if (out) out.push(b)
4997 state = iterator.next()
4998 }
4999 }),
5000 out
5001 )
5002 })
5003
5004/** @internal */
5005export const resolveConcurrency = (concurrency: Concurrency | undefined): number =>
5006 concurrency === "unbounded" ? Number.POSITIVE_INFINITY : Math.max(1, concurrency ?? 1)
5007
5008type IterateOptions<S, A, X, E, R, E2> = {
5009 readonly onItem: (state: S, item: A, index: number) => Effect.Effect<X, E, R>
5010 readonly step: (state: NoInfer<S>, item: A, exit: Exit.Exit<X, E>, index: number) => Exit.Exit<void, E2> | void
5011}
5012
5013/** @internal */
5014export const iterateEager = <S, A>() =>
5015<X, E, R, E2>(options: IterateOptions<S, A, X, E, R, E2>): (
5016 initialState: S,
5017 items: ReadonlyArray<A>,
5018 start?: number,
5019 end?: number
5020) => Effect.Effect<void, E | E2, R> | undefined => {
5021 const onItem = options.onItem
5022 const step = options.step
5023
5024 const resumeSequential = (
5025 state: S,
5026 items: ReadonlyArray<A>,
5027 index: number,
5028 end: number,
5029 effect: Effect.Effect<X, E, R>
5030 ): Effect.Effect<void, E | E2, R> =>
5031 flatMap(
5032 exit(effect),
5033 (itemExit) => step(state, items[index], itemExit, index) ?? runSequential(state, items, index + 1, end) ?? void_
5034 )
5035
5036 const runSequential = (
5037 state: S,
5038 items: ReadonlyArray<A>,
5039 index = 0,
5040 end = items.length
5041 ): Effect.Effect<void, E | E2, R> | undefined => {
5042 for (; index < end; index++) {
5043 const item = items[index]
5044 const effect = onItem(state, item, index)
5045 if (!effectIsExit(effect)) {
5046 return resumeSequential(state, items, index, end, effect)
5047 }
5048 const terminal = step(state, item, effect, index)
5049 if (terminal) return terminal._tag === "Failure" ? terminal : undefined
5050 }
5051 }
5052
5053 return runSequential
5054}
5055
5056const iterateConcurrentImpl = <S, A, X, E, R, E2>(options: IterateOptions<S, A, X, E, R, E2>) => {
5057 const onItem = options.onItem
5058 const step = options.step
5059 return (
5060 state: S,
5061 items: ReadonlyArray<A>,
5062 opts: { readonly concurrency: number; readonly end?: number | undefined }
5063 ): Effect.Effect<void, E | E2, R> | undefined => {
5064 let index = 0
5065 const end = opts.end ?? items.length
5066 const concurrency = opts.concurrency
5067 let done = false
5068 let parentFiber: Fiber.Fiber<any, any> | undefined
5069 let fibers: Set<Fiber.Fiber<any, any>> | undefined
5070 let resume: ((effect: Effect.Effect<void, E | E2, R>) => void) | undefined
5071 let terminal: Exit.Exit<void, E | E2> | void
5072 let effect: Effect.Effect<X, E, R> | undefined
5073
5074 const failDefect = (error: unknown): Effect.Effect<void, E | E2, R> => {
5075 const defect = exitDie(error)
5076 terminal = defect
5077 done = true
5078 return fibers && fibers.size > 0
5079 ? flatMap(uninterruptible(fiberInterruptAll(Array.from(fibers))), () => terminal ?? defect)
5080 : defect
5081 }
5082
5083 const go = (): Effect.Effect<void, E | E2, R> | undefined => {
5084 let paused = false
5085 for (; !terminal && index < end; index++) {
5086 const item = items[index]
5087 const eff = effect ?? onItem(state, item, index)
5088
5089 if (effectIsExit(eff)) {
5090 terminal = step(state, item, eff, index)
5091 if (terminal) break
5092 } else if (!parentFiber) {
5093 return callback((cb) => {
5094 parentFiber = getCurrentFiber()!
5095 fibers = new Set()
5096 effect = eff
5097 resume = cb
5098 let result: Effect.Effect<void, E | E2, R> | undefined
5099 try {
5100 result = go()
5101 } catch (error) {
5102 return cb(failDefect(error))
5103 }
5104 if (result) return cb(result)
5105 return suspend(() => {
5106 terminal ??= exitVoid
5107 return flatMap(
5108 fibers ? fiberInterruptAll(fibers) : void_,
5109 () => terminal?._tag === "Failure" ? terminal : void_
5110 )
5111 })
5112 })
5113 } else {
5114 // Clear the effect cached before the parent fiber was available.
5115 effect = undefined
5116
5117 const fiber = forkUnsafe(parentFiber, eff, true, true, "inherit")
5118 if (fiber._exit) {
5119 terminal = step(state, item, fiber._exit, index)
5120 if (terminal) break
5121 continue
5122 }
5123
5124 fibers!.add(fiber)
5125
5126 const currentIndex = index
5127 fiber.addObserver((exit) => {
5128 fibers!.delete(fiber)
5129 try {
5130 if (terminal) {
5131 if (exit._tag === "Failure") {
5132 const reasons = exit.cause.reasons.filter((reason) => reason._tag !== "Interrupt")
5133 if (reasons.length > 0) {
5134 const cause = causeFromReasons(reasons)
5135 terminal = exitFailCause(terminal._tag === "Failure" ? causeCombine(terminal.cause, cause) : cause)
5136 }
5137 }
5138 } else {
5139 const result = step(state, item, exit, currentIndex)
5140 if (result) {
5141 terminal = result
5142 go()
5143 }
5144 }
5145
5146 if (paused) {
5147 const eff = go()
5148 if (eff) resume!(eff)
5149 } else if (done && fibers!.size === 0) {
5150 resume!(terminal ?? void_)
5151 }
5152 } catch (error) {
5153 resume!(failDefect(error))
5154 }
5155 })
5156
5157 if (fibers!.size < concurrency) continue
5158 paused = true
5159 index++
5160 return
5161 }
5162 }
5163
5164 done = true
5165
5166 if (terminal) {
5167 if (fibers && fibers.size > 0) {
5168 const annotations = fiberStackAnnotations(parentFiber!)
5169 fibers.forEach((f) => f.interruptUnsafe(parentFiber!.id, annotations))
5170 return
5171 }
5172 if (resume || terminal._tag === "Failure") {
5173 return terminal
5174 }
5175 } else if (resume) {
5176 if (!fibers) {
5177 return exitVoid
5178 } else if (fibers.size === 0) {
5179 resume(void_)
5180 }
5181 }
5182 }
5183
5184 return go()
5185 }
5186}
5187
5188/** @internal */
5189export const iterateConcurrent = <S, A>() => <X, E, R, E2>(options: IterateOptions<S, A, X, E, R, E2>) =>
5190 iterateConcurrentImpl<S, A, X, E, R, E2>(options)
5191
5192const forEachConcurrent = iterateConcurrentImpl({
5193 onItem(
5194 state: {
5195 readonly f: (a: any, i: number) => Effect.Effect<any, any, any>
5196 readonly out: Array<any> | undefined
5197 },
5198 item,
5199 index
5200 ) {
5201 return state.f(item, index)
5202 },
5203 step(state, _, exit, index) {
5204 if (exit._tag === "Failure") return exit
5205 else if (state.out) {
5206 state.out[index] = exit.value
5207 }
5208 }
5209})
5210
5211/** @internal */
5212export const filterOrElse: {
5213 <A, C, E2, R2, B extends A>(
5214 refinement: Predicate.Refinement<NoInfer<A>, B>,
5215 orElse: (a: EqualsWith<A, B, NoInfer<A>, Exclude<NoInfer<A>, B>>) => Effect.Effect<C, E2, R2>
5216 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B | C, E2 | E, R2 | R>
5217 <A, C, E2, R2>(
5218 predicate: Predicate.Predicate<NoInfer<A>>,
5219 orElse: (a: NoInfer<A>) => Effect.Effect<C, E2, R2>
5220 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A | C, E2 | E, R2 | R>
5221 <A, E, R, C, E2, R2, B extends A>(
5222 self: Effect.Effect<A, E, R>,
5223 refinement: Predicate.Refinement<A, B>,
5224 orElse: (a: EqualsWith<A, B, A, Exclude<A, B>>) => Effect.Effect<C, E2, R2>
5225 ): Effect.Effect<B | C, E | E2, R | R2>
5226 <A, E, R, C, E2, R2>(
5227 self: Effect.Effect<A, E, R>,
5228 predicate: Predicate.Predicate<NoInfer<A>>,
5229 orElse: (a: NoInfer<A>) => Effect.Effect<C, E2, R2>
5230 ): Effect.Effect<A | C, E | E2, R | R2>
5231} = dual(3, <A, E, R, B, E2, R2>(
5232 self: Effect.Effect<A, E, R>,
5233 predicate: Predicate.Predicate<A>,
5234 orElse: (a: A) => Effect.Effect<B, E2, R2>
5235): Effect.Effect<A | B, E | E2, R | R2> =>
5236 flatMap(
5237 self,
5238 (a) => predicate(a) ? succeed<A | B>(a) : orElse(a)
5239 ))
5240
5241/** @internal */
5242export const filterMapOrElse: {
5243 <A, B, X, C, E2, R2>(
5244 filter: Filter.Filter<NoInfer<A>, B, X>,
5245 orElse: (x: X) => Effect.Effect<C, E2, R2>
5246 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B | C, E2 | E, R2 | R>
5247 <A, E, R, B, X, C, E2, R2>(
5248 self: Effect.Effect<A, E, R>,
5249 filter: Filter.Filter<NoInfer<A>, B, X>,
5250 orElse: (x: X) => Effect.Effect<C, E2, R2>
5251 ): Effect.Effect<B | C, E | E2, R | R2>
5252} = dual(3, <A, E, R, B, X, C, E2, R2>(
5253 self: Effect.Effect<A, E, R>,
5254 filter: Filter.Filter<NoInfer<A>, B, X>,
5255 orElse: (x: X) => Effect.Effect<C, E2, R2>
5256): Effect.Effect<B | C, E | E2, R | R2> =>
5257 flatMap(
5258 self,
5259 (a) => {
5260 const result = filter(a)
5261 return (Result.isFailure(result)
5262 ? orElse(result.failure)
5263 : succeed(result.success)) as Effect.Effect<B | C, E2, R2>
5264 }
5265 ))
5266
5267/** @internal */
5268export const filterMapOrFail: {
5269 <A, B, X, E2>(
5270 filter: Filter.Filter<NoInfer<A>, B, X>,
5271 orFailWith: (x: X) => E2
5272 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E2 | E, R>
5273 <A, B, X>(
5274 filter: Filter.Filter<NoInfer<A>, B, X>
5275 ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, Cause.NoSuchElementError | E, R>
5276 <A, E, R, B, X, E2>(
5277 self: Effect.Effect<A, E, R>,
5278 filter: Filter.Filter<NoInfer<A>, B, X>,
5279 orFailWith: (x: X) => E2
5280 ): Effect.Effect<B, E2 | E, R>
5281 <A, E, R, B, X>(
5282 self: Effect.Effect<A, E, R>,
5283 filter: Filter.Filter<NoInfer<A>, B, X>
5284 ): Effect.Effect<B, Cause.NoSuchElementError | E, R>
5285} = dual((args) => isEffect(args[0]), <A, E, R, B, X, E2>(
5286 self: Effect.Effect<A, E, R>,
5287 filter: Filter.Filter<NoInfer<A>, B, X>,
5288 orFailWith?: (x: X) => E2
5289): Effect.Effect<B, E2 | Cause.NoSuchElementError | E, R> =>
5290 filterMapOrElse(
5291 self,
5292 filter,
5293 orFailWith ? (x: X) => fail(orFailWith(x)) : () => fail(new NoSuchElementError() as E2)
5294 ))
5295
5296/** @internal */
5297export const filter: {
5298 <A, B extends A>(
5299 refinement: Predicate.Refinement<NoInfer<A>, B>
5300 ): (elements: Iterable<A>) => Effect.Effect<Array<B>>
5301 <A>(
5302 predicate: Predicate.Predicate<NoInfer<A>>
5303 ): (elements: Iterable<A>) => Effect.Effect<Array<A>>
5304 <A, E, R>(
5305 predicate: (a: NoInfer<A>, i: number) => Effect.Effect<boolean, E, R>,
5306 options?: { readonly concurrency?: Concurrency | undefined }
5307 ): (iterable: Iterable<A>) => Effect.Effect<Array<A>, E, R>
5308 <A, B extends A>(
5309 elements: Iterable<A>,
5310 refinement: Predicate.Refinement<A, B>
5311 ): Effect.Effect<Array<B>>
5312 <A>(
5313 elements: Iterable<A>,
5314 predicate: Predicate.Predicate<A>
5315 ): Effect.Effect<Array<A>>
5316 <A, E, R>(
5317 iterable: Iterable<A>,
5318 predicate: (a: NoInfer<A>, i: number) => Effect.Effect<boolean, E, R>,
5319 options?: { readonly concurrency?: Concurrency | undefined }
5320 ): Effect.Effect<Array<A>, E, R>
5321} = dual(
5322 (args) => isIterable(args[0]) && !isEffect(args[0]),
5323 <A, E, R>(
5324 elements: Iterable<A>,
5325 predicate:
5326 | Predicate.Predicate<A>
5327 | ((a: A, i: number) => Effect.Effect<boolean, E, R>),
5328 options?: { readonly concurrency?: Concurrency | undefined }
5329 ): Effect.Effect<Array<A>, E, R> =>
5330 suspend(() => {
5331 const out: Array<A> = []
5332 return as(
5333 forEach(
5334 elements,
5335 (a, i) => {
5336 const result = (predicate as Function)(a, i)
5337 if (typeof result === "boolean") {
5338 if (result) out.push(a)
5339 return void_ as any
5340 }
5341 return map(result, (keep) => {
5342 if (keep) {
5343 out.push(a)
5344 }
5345 })
5346 },
5347 {
5348 discard: true,
5349 concurrency: options?.concurrency
5350 }
5351 ),
5352 out
5353 )
5354 })
5355)
5356
5357/** @internal */
5358export const filterMap: {
5359 <A, B, X>(
5360 filter: Filter.Filter<NoInfer<A>, B, X>
5361 ): (elements: Iterable<A>) => Effect.Effect<Array<B>>
5362 <A, B, X>(
5363 elements: Iterable<A>,
5364 filter: Filter.Filter<NoInfer<A>, B, X>
5365 ): Effect.Effect<Array<B>>
5366} = dual(
5367 (args) => isIterable(args[0]) && !isEffect(args[0]),
5368 <A, B, X>(
5369 elements: Iterable<A>,
5370 filter: Filter.Filter<A, B, X>
5371 ): Effect.Effect<Array<B>> =>
5372 suspend(() => {
5373 const out: Array<B> = []
5374 for (const a of elements) {
5375 const result = filter(a)
5376 if (Result.isSuccess(result)) {
5377 out.push(result.success)
5378 }
5379 }
5380 return succeed(out)
5381 })
5382)
5383
5384/** @internal */
5385export const filterMapEffect: {
5386 <A, B, X, E, R>(
5387 filter: Filter.FilterEffect<NoInfer<A>, B, X, E, R>,
5388 options?: { readonly concurrency?: Concurrency | undefined }
5389 ): (elements: Iterable<A>) => Effect.Effect<Array<B>, E, R>
5390 <A, B, X, E, R>(
5391 elements: Iterable<A>,
5392 filter: Filter.FilterEffect<NoInfer<A>, B, X, E, R>,
5393 options?: { readonly concurrency?: Concurrency | undefined }
5394 ): Effect.Effect<Array<B>, E, R>
5395} = dual(
5396 (args) => isIterable(args[0]) && !isEffect(args[0]),
5397 <A, B, X, E, R>(
5398 elements: Iterable<A>,
5399 filter: Filter.FilterEffect<A, B, X, E, R>,
5400 options?: { readonly concurrency?: Concurrency | undefined }
5401 ): Effect.Effect<Array<B>, E, R> =>
5402 suspend(() => {
5403 const out: Array<B> = []
5404 return as(
5405 forEach(
5406 elements,
5407 (a) =>
5408 map(filter(a), (result) => {
5409 if (Result.isSuccess(result)) {
5410 out.push(result.success)
5411 }
5412 }),
5413 {
5414 discard: true,
5415 concurrency: options?.concurrency
5416 }
5417 ),
5418 out
5419 )
5420 })
5421)
5422
5423// ----------------------------------------------------------------------------
5424// do notation
5425// ----------------------------------------------------------------------------
5426
5427/** @internal */
5428export const Do: Effect.Effect<{}> = succeed({})
5429
5430/** @internal */
5431export const bindTo: {
5432 <N extends string>(
5433 name: N
5434 ): <A, E, R>(
5435 self: Effect.Effect<A, E, R>
5436 ) => Effect.Effect<Record<N, A>, E, R>
5437 <A, E, R, N extends string>(
5438 self: Effect.Effect<A, E, R>,
5439 name: N
5440 ): Effect.Effect<Record<N, A>, E, R>
5441} = doNotation.bindTo<Effect.EffectTypeLambda>(map)
5442
5443/** @internal */
5444export const bind: {
5445 <N extends string, A extends Record<string, any>, B, E2, R2>(
5446 name: N,
5447 f: (a: NoInfer<A>) => Effect.Effect<B, E2, R2>
5448 ): <E, R>(
5449 self: Effect.Effect<A, E, R>
5450 ) => Effect.Effect<Simplify<Omit<A, N> & Record<N, B>>, E | E2, R | R2>
5451 <A extends Record<string, any>, E, R, B, E2, R2, N extends string>(
5452 self: Effect.Effect<A, E, R>,
5453 name: N,
5454 f: (a: NoInfer<A>) => Effect.Effect<B, E2, R2>
5455 ): Effect.Effect<Simplify<Omit<A, N> & Record<N, B>>, E | E2, R | R2>
5456} = doNotation.bind<Effect.EffectTypeLambda>(map, flatMap)
5457
5458/** @internal */
5459const let_: {
5460 <N extends string, A extends Record<string, any>, B>(
5461 name: N,
5462 f: (a: NoInfer<A>) => B
5463 ): <E, R>(
5464 self: Effect.Effect<A, E, R>
5465 ) => Effect.Effect<Simplify<Omit<A, N> & Record<N, B>>, E, R>
5466 <A extends Record<string, any>, E, R, B, N extends string>(
5467 self: Effect.Effect<A, E, R>,
5468 name: N,
5469 f: (a: NoInfer<A>) => B
5470 ): Effect.Effect<Simplify<Omit<A, N> & Record<N, B>>, E, R>
5471} = doNotation.let_<Effect.EffectTypeLambda>(map)
5472
5473/** @internal */
5474export { let_ as let }
5475
5476// ----------------------------------------------------------------------------
5477// fibers & forking
5478// ----------------------------------------------------------------------------
5479
5480/** @internal */
5481export const forkChild: {
5482 <
5483 Arg extends Effect.Effect<any, any, any> | {
5484 readonly startImmediately?: boolean | undefined
5485 readonly uninterruptible?: boolean | "inherit" | undefined
5486 } | undefined = {
5487 readonly startImmediately?: boolean | undefined
5488 readonly uninterruptible?: boolean | "inherit" | undefined
5489 }
5490 >(
5491 effectOrOptions: Arg,
5492 options?: {
5493 readonly startImmediately?: boolean | undefined
5494 readonly uninterruptible?: boolean | "inherit" | undefined
5495 } | undefined
5496 ): [Arg] extends [Effect.Effect<infer _A, infer _E, infer _R>] ? Effect.Effect<Fiber.Fiber<_A, _E>, never, _R>
5497 : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Fiber.Fiber<A, E>, never, R>
5498} = dual((args) => isEffect(args[0]), <A, E, R>(
5499 self: Effect.Effect<A, E, R>,
5500 options?: {
5501 readonly startImmediately?: boolean
5502 readonly uninterruptible?: boolean | "inherit"
5503 }
5504): Effect.Effect<Fiber.Fiber<A, E>, never, R> =>
5505 withFiber((fiber) => {
5506 interruptChildrenPatch()
5507 return succeed(forkUnsafe(
5508 fiber,
5509 self,
5510 options?.startImmediately,
5511 false,
5512 options?.uninterruptible ?? false
5513 ))
5514 }))
5515
5516/** @internal */
5517export const forkUnsafe = <FA, FE, A, E, R>(
5518 parent: Fiber.Fiber<FA, FE>,
5519 effect: Effect.Effect<A, E, R>,
5520 immediate = false,
5521 daemon = false,
5522 uninterruptible: boolean | "inherit" = false
5523): FiberImpl<A, E> => {
5524 const parentRuntime = parent as FiberImpl<FA, FE>
5525 const interruptible = uninterruptible === "inherit" ? parentRuntime.interruptible : !uninterruptible
5526 const child = new FiberImpl<A, E>(parentRuntime.context, interruptible)
5527 if (immediate) {
5528 child.evaluate(effect as any)
5529 } else {
5530 // Preserve the fork context rather than the dispatcher's context.
5531 child._asyncContext = captureAsyncContext()
5532 parentRuntime.currentDispatcher.scheduleTask(() => child.evaluate(effect as any), 0)
5533 }
5534 if (!daemon && !child._exit) {
5535 parentRuntime.children().add(child)
5536 child._parent = parentRuntime
5537 }
5538 return child
5539}
5540
5541/** @internal */
5542export const forkDetach: {
5543 <
5544 Arg extends Effect.Effect<any, any, any> | {
5545 readonly startImmediately?: boolean | undefined
5546 readonly uninterruptible?: boolean | "inherit" | undefined
5547 } | undefined = {
5548 readonly startImmediately?: boolean | undefined
5549 readonly uninterruptible?: boolean | "inherit" | undefined
5550 }
5551 >(
5552 effectOrOptions: Arg,
5553 options?: {
5554 readonly startImmediately?: boolean | undefined
5555 readonly uninterruptible?: boolean | "inherit" | undefined
5556 } | undefined
5557 ): [Arg] extends [Effect.Effect<infer _A, infer _E, infer _R>] ? Effect.Effect<Fiber.Fiber<_A, _E>, never, _R>
5558 : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Fiber.Fiber<A, E>, never, R>
5559} = dual((args) => isEffect(args[0]), <A, E, R>(
5560 self: Effect.Effect<A, E, R>,
5561 options?: {
5562 readonly startImmediately?: boolean
5563 readonly uninterruptible?: boolean | "inherit" | undefined
5564 }
5565): Effect.Effect<Fiber.Fiber<A, E>, never, R> =>
5566 withFiber((fiber) => succeed(forkUnsafe(fiber, self, options?.startImmediately, true, options?.uninterruptible))))
5567
5568/** @internal */
5569export const awaitAllChildren = <A, E, R>(
5570 self: Effect.Effect<A, E, R>
5571): Effect.Effect<A, E, R> =>
5572 withFiber((fiber) => {
5573 const initialChildren = fiber._children && new Set(fiber._children)
5574 const isInterruptible = fiber.interruptible
5575 return onExitPrimitive(
5576 self,
5577 (_) => {
5578 let children = fiber._children
5579 if (children === undefined || children.size === 0) {
5580 return void_
5581 } else if (initialChildren) {
5582 children = Iterable.filter(
5583 children,
5584 (child: FiberImpl<any, any>) => !initialChildren.has(child)
5585 ) as Set<FiberImpl<any, any>>
5586 }
5587 const awaitChildren = asVoid(fiberAwaitAll(children))
5588 return isInterruptible ? interruptible(awaitChildren) : awaitChildren
5589 }
5590 )
5591 })
5592
5593/** @internal */
5594export const forkIn: {
5595 (
5596 scope: Scope.Scope,
5597 options?: {
5598 readonly startImmediately?: boolean | undefined
5599 readonly uninterruptible?: boolean | "inherit" | undefined
5600 }
5601 ): <A, E, R>(
5602 self: Effect.Effect<A, E, R>
5603 ) => Effect.Effect<Fiber.Fiber<A, E>, never, R>
5604 <A, E, R>(
5605 self: Effect.Effect<A, E, R>,
5606 scope: Scope.Scope,
5607 options?: {
5608 readonly startImmediately?: boolean | undefined
5609 readonly uninterruptible?: boolean | "inherit" | undefined
5610 }
5611 ): Effect.Effect<Fiber.Fiber<A, E>, never, R>
5612} = dual(
5613 (args) => isEffect(args[0]),
5614 <A, E, R>(
5615 self: Effect.Effect<A, E, R>,
5616 scope: Scope.Scope,
5617 options?: {
5618 readonly startImmediately?: boolean | undefined
5619 readonly uninterruptible?: boolean | "inherit" | undefined
5620 }
5621 ): Effect.Effect<Fiber.Fiber<A, E>, never, R> =>
5622 withFiber((parent) => {
5623 const fiber = forkUnsafe(parent, self, options?.startImmediately, true, options?.uninterruptible)
5624 if (!(fiber as FiberImpl<any, any>)._exit) {
5625 if (scope.state._tag !== "Closed") {
5626 const key = {}
5627 const finalizer = () => withFiberId((interruptor) => interruptor === fiber.id ? void_ : fiberInterrupt(fiber))
5628 scopeAddFinalizerUnsafe(scope, key, finalizer)
5629 fiber.addObserver(() => scopeRemoveFinalizerUnsafe(scope, key))
5630 } else {
5631 fiber.interruptUnsafe(parent.id, fiberStackAnnotations(parent))
5632 }
5633 }
5634 return succeed(fiber)
5635 })
5636)
5637
5638/** @internal */
5639export const forkScoped: {
5640 <
5641 Arg extends Effect.Effect<any, any, any> | {
5642 readonly startImmediately?: boolean | undefined
5643 readonly uninterruptible?: boolean | "inherit" | undefined
5644 } | undefined = {
5645 readonly startImmediately?: boolean | undefined
5646 readonly uninterruptible?: boolean | "inherit" | undefined
5647 }
5648 >(
5649 effectOrOptions: Arg,
5650 options?: {
5651 readonly startImmediately?: boolean | undefined
5652 readonly uninterruptible?: boolean | "inherit" | undefined
5653 } | undefined
5654 ): [Arg] extends [Effect.Effect<infer _A, infer _E, infer _R>] ?
5655 Effect.Effect<Fiber.Fiber<_A, _E>, never, _R | Scope.Scope>
5656 : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Fiber.Fiber<A, E>, never, R | Scope.Scope>
5657} = dual((args) => isEffect(args[0]), <A, E, R>(
5658 self: Effect.Effect<A, E, R>,
5659 options?: {
5660 readonly startImmediately?: boolean
5661 readonly uninterruptible?: boolean | "inherit"
5662 }
5663): Effect.Effect<Fiber.Fiber<A, E>, never, R | Scope.Scope> => flatMap(scope, (scope) => forkIn(self, scope, options)))
5664
5665// ----------------------------------------------------------------------------
5666// execution
5667// ----------------------------------------------------------------------------
5668
5669/** @internal */
5670export const runForkWith = <R>(context: Context.Context<R>) =>
5671<A, E>(
5672 effect: Effect.Effect<A, E, R>,
5673 options?: Effect.RunOptions | undefined
5674): Fiber.Fiber<A, E> => {
5675 const fiber = new FiberImpl<A, E>(
5676 options?.scheduler ? Context.add(context, Scheduler.Scheduler, options.scheduler) : context,
5677 options?.uninterruptible !== true
5678 )
5679 fiber.evaluate(effect as any)
5680 if (fiber._exit) return fiber
5681
5682 if (options?.signal) {
5683 if (options.signal.aborted) {
5684 fiber.interruptUnsafe()
5685 } else {
5686 const abort = () => fiber.interruptUnsafe()
5687 options.signal.addEventListener("abort", abort, { once: true })
5688 fiber.addObserver(() => options.signal!.removeEventListener("abort", abort))
5689 }
5690 }
5691 if (options?.onFiberStart) {
5692 options.onFiberStart(fiber)
5693 }
5694 return fiber
5695}
5696
5697/** @internal */
5698export const fiberRunIn: {
5699 (scope: Scope.Scope): <A, E>(self: Fiber.Fiber<A, E>) => Fiber.Fiber<A, E>
5700 <A, E>(
5701 self: Fiber.Fiber<A, E>,
5702 scope: Scope.Scope
5703 ): Fiber.Fiber<A, E>
5704} = dual(2, <A, E>(
5705 self: FiberImpl<A, E>,
5706 scope: Scope.Scope
5707): Fiber.Fiber<A, E> => {
5708 if (self._exit) {
5709 return self
5710 } else if (scope.state._tag === "Closed") {
5711 self.interruptUnsafe(self.id)
5712 return self
5713 }
5714 const key = {}
5715 scopeAddFinalizerUnsafe(scope, key, () => fiberInterrupt(self))
5716 self.addObserver(() => scopeRemoveFinalizerUnsafe(scope, key))
5717 return self
5718})
5719
5720/** @internal */
5721export const runFork: <A, E>(
5722 effect: Effect.Effect<A, E, never>,
5723 options?: Effect.RunOptions | undefined
5724) => Fiber.Fiber<A, E> = runForkWith(Context.empty())
5725
5726/** @internal */
5727export const runCallbackWith = <R>(context: Context.Context<R>) => {
5728 const runFork = runForkWith(context)
5729 return <A, E>(
5730 effect: Effect.Effect<A, E, R>,
5731 options?:
5732 | Effect.RunOptions & {
5733 readonly onExit: (exit: Exit.Exit<A, E>) => void
5734 }
5735 | undefined
5736 ): (interruptor?: number | undefined) => void => {
5737 const fiber = runFork(effect, options)
5738 if (options?.onExit) {
5739 fiber.addObserver(options.onExit)
5740 }
5741 return (interruptor) => {
5742 return fiber.interruptUnsafe(interruptor)
5743 }
5744 }
5745}
5746
5747/** @internal */
5748export const runCallback = runCallbackWith(Context.empty())
5749
5750/** @internal */
5751export const runPromiseExitWith = <R>(context: Context.Context<R>) => {
5752 const runFork = runForkWith(context)
5753 return <A, E>(
5754 effect: Effect.Effect<A, E, R>,
5755 options?: Effect.RunOptions | undefined
5756 ): Promise<Exit.Exit<A, E>> => {
5757 const fiber = runFork(effect, options)
5758 return new Promise((resolve) => {
5759 fiber.addObserver((exit) => resolve(exit))
5760 })
5761 }
5762}
5763
5764/** @internal */
5765export const runPromiseExit = runPromiseExitWith(Context.empty())
5766
5767/** @internal */
5768export const runPromiseWith = <R>(context: Context.Context<R>) => {
5769 const runPromiseExit = runPromiseExitWith(context)
5770 return <A, E>(
5771 effect: Effect.Effect<A, E, R>,
5772 options?:
5773 | Effect.RunOptions
5774 | undefined
5775 ): Promise<A> =>
5776 runPromiseExit(effect, options).then((exit) => {
5777 if (exit._tag === "Failure") {
5778 throw causeSquash(exit.cause)
5779 }
5780 return exit.value
5781 })
5782}
5783
5784/** @internal */
5785export const runPromise: <A, E>(
5786 effect: Effect.Effect<A, E>,
5787 options?:
5788 | Effect.RunOptions
5789 | undefined
5790) => Promise<A> = runPromiseWith(Context.empty())
5791
5792/** @internal */
5793export const runSyncExitWith = <R>(context: Context.Context<R>) => {
5794 const runFork = runForkWith(context)
5795 return <A, E>(effect: Effect.Effect<A, E, R>): Exit.Exit<A, E> => {
5796 if (effectIsExit(effect)) return effect
5797 const scheduler = new Scheduler.MixedScheduler("sync")
5798 const fiber = runFork(effect, { scheduler }) as FiberImpl<A, E>
5799 fiber._dispatcher?.flush()
5800 return fiber._exit ?? exitDie(new AsyncFiberError(fiber))
5801 }
5802}
5803
5804/** @internal */
5805export const runSyncExit: <A, E>(effect: Effect.Effect<A, E>) => Exit.Exit<A, E> = runSyncExitWith(
5806 Context.empty()
5807)
5808
5809/** @internal */
5810export const runSyncWith = <R>(context: Context.Context<R>) => {
5811 const runSyncExit = runSyncExitWith(context)
5812 return <A, E>(effect: Effect.Effect<A, E, R>): A => {
5813 const exit = runSyncExit(effect)
5814 if (exit._tag === "Failure") throw causeSquash(exit.cause)
5815 return exit.value
5816 }
5817}
5818
5819/** @internal */
5820export const runSync: <A, E>(effect: Effect.Effect<A, E>) => A = runSyncWith(Context.empty())
5821
5822const succeedTrue = succeed(true)
5823const succeedFalse = succeed(false)
5824
5825class Latch implements _Latch.Latch {
5826 waiters: Array<(_: Effect.Effect<void>) => void> = []
5827 scheduled: Array<(_: Effect.Effect<void>) => void> | undefined = undefined
5828 private _isOpen: boolean
5829
5830 constructor(isOpen: boolean) {
5831 this._isOpen = isOpen
5832 }
5833
5834 private scheduleUnsafe(fiber: Fiber.Fiber<unknown, unknown>) {
5835 if (this.waiters.length === 0) {
5836 return succeedTrue
5837 }
5838 if (this.scheduled === undefined) {
5839 this.scheduled = this.waiters
5840 fiber.currentDispatcher.scheduleTask(this.flushScheduled, 0)
5841 } else {
5842 for (let i = 0; i < this.waiters.length; i++) {
5843 this.scheduled.push(this.waiters[i])
5844 }
5845 }
5846 this.waiters = []
5847 return succeedTrue
5848 }
5849 private flushScheduled = () => {
5850 if (this.scheduled === undefined) return
5851 const waiters = this.scheduled
5852 this.scheduled = undefined
5853 for (let i = 0; i < waiters.length; i++) {
5854 waiters[i](exitVoid)
5855 }
5856 }
5857 private flushWaiters() {
5858 // swap both arrays out before any resume runs: a resumed waiter can
5859 // reentrantly close the latch and register new waiters, which must not
5860 // be drained by this flush
5861 const waiters = this.waiters
5862 this.waiters = []
5863 this.flushScheduled()
5864 for (let i = 0; i < waiters.length; i++) {
5865 waiters[i](exitVoid)
5866 }
5867 }
5868
5869 open = withFiber<boolean>((fiber) => {
5870 if (this._isOpen) return succeedFalse
5871 this._isOpen = true
5872 return this.scheduleUnsafe(fiber)
5873 })
5874 release = withFiber<boolean>((fiber) => this._isOpen ? succeedFalse : this.scheduleUnsafe(fiber))
5875 openUnsafe() {
5876 if (this._isOpen) return false
5877 this._isOpen = true
5878 this.flushWaiters()
5879 return true
5880 }
5881 await = callback<void>((resume) => {
5882 if (this._isOpen) {
5883 return resume(void_)
5884 }
5885 this.waiters.push(resume)
5886 return sync(() => {
5887 let index = this.waiters.indexOf(resume)
5888 if (index !== -1) {
5889 this.waiters.splice(index, 1)
5890 } else if (this.scheduled !== undefined) {
5891 index = this.scheduled.indexOf(resume)
5892 if (index !== -1) {
5893 this.scheduled.splice(index, 1)
5894 }
5895 }
5896 })
5897 })
5898 closeUnsafe() {
5899 if (!this._isOpen) return false
5900 this._isOpen = false
5901 return true
5902 }
5903 close = sync(() => this.closeUnsafe())
5904 whenOpen = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> => flatMap(this.await, () => self)
5905 isOpen() {
5906 return this._isOpen
5907 }
5908}
5909
5910/** @internal */
5911export const makeLatchUnsafe = (open?: boolean | undefined): _Latch.Latch => new Latch(open ?? false)
5912
5913/** @internal */
5914export const makeLatch = (open?: boolean | undefined) => sync(() => makeLatchUnsafe(open))
5915
5916// ----------------------------------------------------------------------------
5917// Tracer
5918// ----------------------------------------------------------------------------
5919
5920/** @internal */
5921export const tracer: Effect.Effect<Tracer.Tracer> = withFiber((fiber) => succeed(fiber.getRef(Tracer.Tracer)))
5922
5923/** @internal */
5924export const withTracer: {
5925 (tracer: Tracer.Tracer): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
5926 <A, E, R>(effect: Effect.Effect<A, E, R>, tracer: Tracer.Tracer): Effect.Effect<A, E, R>
5927} = dual(
5928 2,
5929 <A, E, R>(effect: Effect.Effect<A, E, R>, tracer: Tracer.Tracer): Effect.Effect<A, E, R> =>
5930 provideService(effect, Tracer.Tracer, tracer)
5931)
5932
5933/** @internal */
5934export const withTracerEnabled: {
5935 (enabled: boolean): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
5936 <A, E, R>(effect: Effect.Effect<A, E, R>, enabled: boolean): Effect.Effect<A, E, R>
5937} = provideService(TracerEnabled)
5938
5939/** @internal */
5940export const withTracerTiming: {
5941 (enabled: boolean): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
5942 <A, E, R>(effect: Effect.Effect<A, E, R>, enabled: boolean): Effect.Effect<A, E, R>
5943} = provideService(TracerTimingEnabled)
5944
5945const bigint0 = BigInt(0)
5946
5947const NoopSpanProto: Omit<Tracer.Span, "parent" | "name" | "annotations" | "level"> = {
5948 _tag: "Span",
5949 spanId: "noop",
5950 traceId: "noop",
5951 sampled: false,
5952 status: {
5953 _tag: "Ended",
5954 startTime: bigint0,
5955 endTime: bigint0,
5956 exit: exitVoid
5957 },
5958 attributes: new Map(),
5959 links: [],
5960 kind: "internal",
5961 attribute() {},
5962 event() {},
5963 end() {},
5964 addLinks() {}
5965}
5966
5967/** @internal */
5968export const noopSpan = (options: {
5969 readonly name: string
5970 readonly parent: Option.Option<Tracer.AnySpan>
5971 readonly annotations: Context.Context<never>
5972}): Tracer.Span => Object.assign(Object.create(NoopSpanProto), options)
5973
5974const filterDisablePropagation = (span: Tracer.AnySpan | undefined): Option.Option<Tracer.AnySpan> => {
5975 if (!span) return Option.none()
5976 return Context.get(span.annotations, Tracer.DisablePropagation)
5977 ? span._tag === "Span" ? filterDisablePropagation(Option.getOrUndefined(span.parent)) : Option.none()
5978 : Option.some(span)
5979}
5980
5981/** @internal */
5982export const makeSpanUnsafe = <XA, XE>(
5983 fiber: Fiber.Fiber<XA, XE>,
5984 name: string,
5985 options: Tracer.SpanOptionsNoTrace | undefined
5986) => {
5987 const disablePropagation = !fiber.cache.tracerEnabled ||
5988 (options?.annotations && Context.get(options.annotations, Tracer.DisablePropagation))
5989 const parent = options?.parent !== undefined
5990 ? Option.some(options.parent)
5991 : options?.root
5992 ? Option.none<Tracer.AnySpan>()
5993 : filterDisablePropagation(fiber.cache.span)
5994
5995 let span: Tracer.Span
5996
5997 if (disablePropagation) {
5998 span = noopSpan({
5999 name,
6000 parent,
6001 annotations: Context.add(
6002 options?.annotations ?? Context.empty(),
6003 Tracer.DisablePropagation,
6004 true
6005 )
6006 })
6007 } else {
6008 // The cache stores only explicit tracer overrides; absent references use the default.
6009 const tracer = fiber.cache.tracer ?? Tracer.nativeTracer
6010 const clock = fiber.getRef(ClockRef)
6011 const timingEnabled = fiber.getRef(TracerTimingEnabled)
6012 const annotationsFromEnv = fiber.getRef(TracerSpanAnnotations)
6013 const linksFromEnv = fiber.getRef(TracerSpanLinks)
6014 const level = options?.level ?? fiber.getRef(Tracer.CurrentTraceLevel)
6015
6016 const links = options?.links !== undefined ?
6017 [...linksFromEnv, ...options.links] :
6018 linksFromEnv.length === 0
6019 ? []
6020 : linksFromEnv.slice()
6021
6022 span = tracer.span({
6023 name,
6024 parent,
6025 annotations: options?.annotations ?? Context.empty(),
6026 links,
6027 startTime: timingEnabled ? clock.currentTimeNanosUnsafe() : bigint0,
6028 kind: options?.kind ?? "internal",
6029 root: options?.root ?? Option.isNone(parent),
6030 sampled: options?.sampled ??
6031 (Option.isSome(parent) && parent.value.sampled === false
6032 ? false
6033 : !isLogLevelGreaterThan(fiber.getRef(Tracer.MinimumTraceLevel), level))
6034 })
6035
6036 for (const key in annotationsFromEnv) {
6037 span.attribute(key, annotationsFromEnv[key])
6038 }
6039 if (options?.attributes !== undefined) {
6040 for (const key in options.attributes) {
6041 span.attribute(key, options.attributes[key])
6042 }
6043 }
6044 }
6045
6046 return span
6047}
6048
6049/** @internal */
6050export const makeSpan = (
6051 name: string,
6052 options?: Tracer.SpanOptions
6053): Effect.Effect<Tracer.Span> => withFiber((fiber) => succeed(makeSpanUnsafe(fiber, name, options)))
6054
6055/** @internal */
6056export const makeSpanScoped = (
6057 name: string,
6058 options?: Tracer.SpanOptionsNoTrace | undefined
6059): Effect.Effect<Tracer.Span, never, Scope.Scope> =>
6060 uninterruptible(
6061 withFiber((fiber) => {
6062 const scope = Context.getUnsafe(fiber.context, scopeTag)
6063 const span = makeSpanUnsafe(fiber, name, options ?? {})
6064 const clock = fiber.getRef(ClockRef)
6065 const timingEnabled = fiber.getRef(TracerTimingEnabled)
6066 return as(
6067 scopeAddFinalizerExit(scope, (exit) => endSpan(span, exit, clock, timingEnabled)),
6068 span
6069 )
6070 })
6071 )
6072
6073/** @internal */
6074export const withSpanScoped: {
6075 (
6076 name: string,
6077 options?: Tracer.SpanOptions
6078 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan> | Scope.Scope>
6079 <A, E, R>(
6080 self: Effect.Effect<A, E, R>,
6081 name: string,
6082 options?: Tracer.SpanOptions
6083 ): Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan> | Scope.Scope>
6084} = function() {
6085 const dataFirst = typeof arguments[0] !== "string"
6086 const name = dataFirst ? arguments[1] : arguments[0]
6087 const options = addSpanStackTrace(dataFirst ? arguments[2] : arguments[1])
6088 if (dataFirst) {
6089 const self = arguments[0]
6090 return flatMap(
6091 makeSpanScoped(name, options),
6092 (span) => withParentSpan(self, span, options)
6093 )
6094 }
6095 return (self: Effect.Effect<any, any, any>) =>
6096 flatMap(
6097 makeSpanScoped(name, options),
6098 (span) => withParentSpan(self, span, options)
6099 )
6100} as any
6101
6102const provideSpanStackFrame = (name: string, stack: (() => string | undefined) | undefined) => {
6103 stack = typeof stack === "function" ? stack : constUndefined
6104 return updateService(CurrentStackFrame, (parent) => ({
6105 name,
6106 stack,
6107 parent
6108 }))
6109}
6110
6111/** @internal */
6112export const spanAnnotations: Effect.Effect<Readonly<Record<string, unknown>>> = TracerSpanAnnotations
6113
6114/** @internal */
6115export const spanLinks: Effect.Effect<ReadonlyArray<Tracer.SpanLink>> = TracerSpanLinks
6116
6117/** @internal */
6118export const linkSpans: {
6119 (
6120 span: Tracer.AnySpan | ReadonlyArray<Tracer.AnySpan>,
6121 attributes?: Record<string, unknown>
6122 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
6123 <A, E, R>(
6124 self: Effect.Effect<A, E, R>,
6125 span: Tracer.AnySpan | ReadonlyArray<Tracer.AnySpan>,
6126 attributes?: Record<string, unknown>
6127 ): Effect.Effect<A, E, R>
6128} = dual((args) => isEffect(args[0]), <A, E, R>(
6129 self: Effect.Effect<A, E, R>,
6130 span: Tracer.AnySpan | ReadonlyArray<Tracer.AnySpan>,
6131 attributes: Record<string, unknown> = {}
6132): Effect.Effect<A, E, R> => {
6133 const spans: Array<Tracer.AnySpan> = Array.isArray(span) ? span : [span]
6134 const links = spans.map((span): Tracer.SpanLink => ({ span, attributes }))
6135 return updateService(self, TracerSpanLinks, (current) => [...current, ...links])
6136})
6137
6138/** @internal */
6139export const endSpan = <A, E>(
6140 span: Tracer.Span,
6141 exit: Exit.Exit<A, E>,
6142 clock: Clock.Clock,
6143 timingEnabled: boolean
6144) =>
6145 sync(() => {
6146 if (span.status._tag === "Ended") return
6147 span.end(timingEnabled ? clock.currentTimeNanosUnsafe() : bigint0, exit)
6148 })
6149
6150/** @internal */
6151export const useSpan: {
6152 <A, E, R>(name: string, evaluate: (span: Tracer.Span) => Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
6153 <A, E, R>(
6154 name: string,
6155 options: Tracer.SpanOptionsNoTrace,
6156 evaluate: (span: Tracer.Span) => Effect.Effect<A, E, R>
6157 ): Effect.Effect<A, E, R>
6158} = <A, E, R>(
6159 name: string,
6160 ...args: [evaluate: (span: Tracer.Span) => Effect.Effect<A, E, R>] | [
6161 options: any,
6162 evaluate: (span: Tracer.Span) => Effect.Effect<A, E, R>
6163 ]
6164): Effect.Effect<A, E, R> => {
6165 const options = args.length === 1 ? undefined : args[0]
6166 const evaluate: (span: Tracer.Span) => Effect.Effect<A, E, R> = args[args.length - 1]
6167 return withFiber((fiber) => {
6168 const span = makeSpanUnsafe(fiber, name, options)
6169 const clock = fiber.getRef(ClockRef)
6170 const timingEnabled = fiber.getRef(TracerTimingEnabled)
6171 onExitUnsafe(fiber, (exit) => endSpan(span, exit, clock, timingEnabled))
6172 return evaluate(span)
6173 })
6174}
6175
6176const provideParentSpan = provideService(Tracer.ParentSpan)
6177
6178/** @internal */
6179export const withParentSpan: {
6180 (
6181 value: Tracer.AnySpan,
6182 options?: Tracer.TraceOptions
6183 ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>>
6184 <A, E, R>(
6185 self: Effect.Effect<A, E, R>,
6186 value: Tracer.AnySpan,
6187 options?: Tracer.TraceOptions
6188 ): Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>>
6189} = function() {
6190 const dataFirst = isEffect(arguments[0])
6191 const span: Tracer.AnySpan = dataFirst ? arguments[1] : arguments[0]
6192 let options = dataFirst ? arguments[2] : arguments[1]
6193 let provideStackFrame: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> = identity
6194 if (span._tag === "Span") {
6195 options = addSpanStackTrace(options)
6196 provideStackFrame = provideSpanStackFrame(span.name, options?.captureStackTrace)
6197 }
6198 if (dataFirst) {
6199 return provideParentSpan(provideStackFrame(arguments[0]), span)
6200 }
6201 return (self: Effect.Effect<any, any, any>) => provideParentSpan(provideStackFrame(self), span)
6202} as any
6203
6204/** @internal */
6205export const withSpan: {
6206 <Args extends ReadonlyArray<any>>(
6207 name: string,
6208 options?: Tracer.SpanOptionsNoTrace | ((...args: NoInfer<Args>) => Tracer.SpanOptionsNoTrace) | undefined,
6209 traceOptions?: Tracer.TraceOptions | undefined
6210 ): <A, E, R>(self: Effect.Effect<A, E, R>, ...args: Args) => Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>>
6211 <A, E, R>(
6212 self: Effect.Effect<A, E, R>,
6213 name: string,
6214 options?: Tracer.SpanOptions | undefined
6215 ): Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>>
6216} = function() {
6217 const dataFirst = typeof arguments[0] !== "string"
6218 const name = dataFirst ? arguments[1] : arguments[0]
6219 const traceOptions = addSpanStackTrace(arguments[2])
6220 if (dataFirst) {
6221 const self = arguments[0]
6222 return useSpan(name, arguments[2], (span) => withParentSpan(self, span, traceOptions))
6223 }
6224 const fnArg = typeof arguments[1] === "function" ? arguments[1] : undefined
6225 const options = fnArg ? undefined : arguments[1]
6226 return (self: Effect.Effect<any, any, any>, ...args: any) =>
6227 useSpan(
6228 name,
6229 fnArg ? fnArg(...args) : options,
6230 (span) => withParentSpan(self, span, traceOptions)
6231 )
6232} as any
6233
6234/** @internal */
6235export const annotateSpans: {
6236 (key: string, value: unknown): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
6237 (values: Record<string, unknown>): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
6238 <A, E, R>(effect: Effect.Effect<A, E, R>, key: string, value: unknown): Effect.Effect<A, E, R>
6239 <A, E, R>(effect: Effect.Effect<A, E, R>, values: Record<string, unknown>): Effect.Effect<A, E, R>
6240} = dual(
6241 (args) => isEffect(args[0]),
6242 <A, E, R>(
6243 effect: Effect.Effect<A, E, R>,
6244 ...args: [Record<string, unknown>] | [key: string, value: unknown]
6245 ): Effect.Effect<A, E, R> =>
6246 updateService(effect, TracerSpanAnnotations, (annotations) => {
6247 const newAnnotations = args.length === 1 ? { ...annotations, ...args[0] } : { ...annotations }
6248 if (args.length === 1) {
6249 return newAnnotations
6250 } else {
6251 InternalRecord.assignProperty(newAnnotations, args[0], args[1])
6252 }
6253 return newAnnotations
6254 })
6255)
6256
6257/** @internal */
6258export const annotateCurrentSpan: {
6259 (key: string, value: unknown): Effect.Effect<void>
6260 (values: Record<string, unknown>): Effect.Effect<void>
6261} = (...args: [Record<string, unknown>] | [key: string, value: unknown]) =>
6262 withFiber((fiber) => {
6263 const span = fiber.currentSpanLocal
6264 if (span) {
6265 if (args.length === 1) {
6266 for (const [key, value] of Object.entries(args[0])) {
6267 span.attribute(key, value)
6268 }
6269 } else {
6270 span.attribute(args[0], args[1])
6271 }
6272 }
6273 return void_
6274 })
6275
6276/** @internal */
6277export const currentSpan: Effect.Effect<Tracer.Span, Cause.NoSuchElementError> = withFiber((fiber) => {
6278 const span = fiber.currentSpanLocal
6279 return span ? succeed(span) : fail(new NoSuchElementError())
6280})
6281
6282/** @internal */
6283export const currentParentSpan: Effect.Effect<Tracer.AnySpan, Cause.NoSuchElementError> = serviceOptional(
6284 Tracer.ParentSpan
6285)
6286
6287// ----------------------------------------------------------------------------
6288// Clock
6289// ----------------------------------------------------------------------------
6290
6291/** @internal */
6292export const ClockRef = Context.Reference<Clock.Clock>("effect/Clock", {
6293 defaultValue: (): Clock.Clock => new ClockImpl()
6294})
6295
6296const MAX_TIMER_MILLIS = 2 ** 31 - 1
6297
6298class ClockImpl implements Clock.Clock {
6299 currentTimeMillisUnsafe(): number {
6300 return Date.now()
6301 }
6302 readonly currentTimeMillis: Effect.Effect<number> = sync(() => this.currentTimeMillisUnsafe())
6303 currentTimeNanosUnsafe(): bigint {
6304 return wallTimeNanos()
6305 }
6306 readonly currentTimeNanos: Effect.Effect<bigint> = sync(() => this.currentTimeNanosUnsafe())
6307 monotonicTimeNanosUnsafe(): bigint {
6308 return monotonicNowNanos()
6309 }
6310 readonly monotonicTimeNanos: Effect.Effect<bigint> = sync(() => this.monotonicTimeNanosUnsafe())
6311 sleep(duration: Duration.Duration): Effect.Effect<void> {
6312 return this.sleepMillis(Duration.toMillis(duration))
6313 }
6314 private sleepMillis(millis: number): Effect.Effect<void> {
6315 if (millis <= 0) return yieldNow
6316 else if (!Number.isFinite(millis)) return never
6317 return callback((resume) => {
6318 const continuation = millis > MAX_TIMER_MILLIS
6319 ? this.sleepMillis(millis - MAX_TIMER_MILLIS)
6320 : void_
6321 const handle = setTimeout(() => resume(continuation), Math.min(millis, MAX_TIMER_MILLIS))
6322 return sync(() => clearTimeout(handle))
6323 })
6324 }
6325}
6326
6327const nanosPerMilli = BigInt(1_000_000)
6328
6329const monotonicNowNanos = (function() {
6330 const processHrtime = (globalThis as {
6331 readonly process?: { readonly hrtime?: { readonly bigint?: () => bigint } }
6332 }).process?.hrtime
6333 if (typeof processHrtime?.bigint === "function") {
6334 return () => processHrtime.bigint!()
6335 }
6336 if (typeof performance !== "undefined" && typeof performance.now === "function") {
6337 return () => BigInt(Math.round(performance.now() * 1_000_000))
6338 }
6339 let previous = BigInt(0)
6340 return () => {
6341 const current = BigInt(Date.now()) * nanosPerMilli
6342 if (current > previous) {
6343 previous = current
6344 }
6345 return previous
6346 }
6347})()
6348
6349const wallTimeNanos = (function() {
6350 const reanchorThresholdNanos = BigInt(1_000_000_000)
6351 let origin: bigint | undefined
6352 return () => {
6353 const monotonic = monotonicNowNanos()
6354 const wall = BigInt(Date.now()) * nanosPerMilli
6355 if (origin === undefined) {
6356 origin = wall - monotonic
6357 } else {
6358 const projected = origin + monotonic
6359 const skew = wall > projected ? wall - projected : projected - wall
6360 if (skew > reanchorThresholdNanos) {
6361 origin = wall - monotonic
6362 }
6363 }
6364 return origin + monotonic
6365 }
6366})()
6367
6368/** @internal */
6369export const clockWith = <A, E, R>(f: (clock: Clock.Clock) => Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
6370 withFiber((fiber) => f(fiber.getRef(ClockRef)))
6371
6372/** @internal */
6373export const sleep = (duration: Duration.Input): Effect.Effect<void> =>
6374 clockWith((clock) => clock.sleep(Duration.fromInputUnsafe(duration)))
6375
6376/** @internal */
6377export const currentTimeMillis: Effect.Effect<number> = clockWith((clock) => clock.currentTimeMillis)
6378
6379/** @internal */
6380export const currentTimeNanos: Effect.Effect<bigint> = clockWith((clock) => clock.currentTimeNanos)
6381
6382/** @internal */
6383export const monotonicTimeNanos: Effect.Effect<bigint> = clockWith((clock) => clock.monotonicTimeNanos)
6384
6385// ----------------------------------------------------------------------------
6386// Errors
6387// ----------------------------------------------------------------------------
6388
6389/** @internal */
6390export const TimeoutErrorTypeId = "~effect/Cause/TimeoutError"
6391
6392/** @internal */
6393export const isTimeoutError = (u: unknown): u is Cause.TimeoutError => hasProperty(u, TimeoutErrorTypeId)
6394
6395/** @internal */
6396export class TimeoutError extends TaggedError("TimeoutError") {
6397 readonly [TimeoutErrorTypeId] = TimeoutErrorTypeId
6398 constructor(message?: string) {
6399 super({ message } as any)
6400 }
6401}
6402
6403/** @internal */
6404export const IllegalArgumentErrorTypeId = "~effect/Cause/IllegalArgumentError"
6405
6406/** @internal */
6407export const isIllegalArgumentError = (
6408 u: unknown
6409): u is Cause.IllegalArgumentError => hasProperty(u, IllegalArgumentErrorTypeId)
6410
6411/** @internal */
6412export class IllegalArgumentError extends TaggedError("IllegalArgumentError") {
6413 readonly [IllegalArgumentErrorTypeId] = IllegalArgumentErrorTypeId
6414 constructor(message?: string) {
6415 super({ message } as any)
6416 }
6417}
6418
6419/** @internal */
6420export const ExceededCapacityErrorTypeId = "~effect/Cause/ExceededCapacityError"
6421
6422/** @internal */
6423export const isExceededCapacityError = (
6424 u: unknown
6425): u is Cause.ExceededCapacityError => hasProperty(u, ExceededCapacityErrorTypeId)
6426
6427/** @internal */
6428export class ExceededCapacityError extends TaggedError("ExceededCapacityError") {
6429 readonly [ExceededCapacityErrorTypeId] = ExceededCapacityErrorTypeId
6430 constructor(message?: string) {
6431 super({ message } as any)
6432 }
6433}
6434
6435/** @internal */
6436export const AsyncFiberErrorTypeId = "~effect/Cause/AsyncFiberError"
6437
6438/** @internal */
6439export const isAsyncFiberError = (
6440 u: unknown
6441): u is Cause.AsyncFiberError => hasProperty(u, AsyncFiberErrorTypeId)
6442
6443/** @internal */
6444export class AsyncFiberError extends TaggedError("AsyncFiberError")<{
6445 fiber: Fiber.Fiber<unknown, unknown>
6446 message: string
6447}> {
6448 readonly [AsyncFiberErrorTypeId] = AsyncFiberErrorTypeId
6449 constructor(fiber: Fiber.Fiber<unknown, unknown>) {
6450 super({
6451 message: "An asynchronous Effect was executed with Effect.runSync",
6452 fiber
6453 })
6454 }
6455}
6456
6457/** @internal */
6458export const UnknownErrorTypeId = "~effect/Cause/UnknownError"
6459
6460/** @internal */
6461export const isUnknownError = (
6462 u: unknown
6463): u is Cause.UnknownError => hasProperty(u, UnknownErrorTypeId)
6464
6465/** @internal */
6466export class UnknownError extends TaggedError("UnknownError")<{
6467 cause: unknown
6468 message?: string | undefined
6469}> {
6470 readonly [UnknownErrorTypeId] = UnknownErrorTypeId
6471 constructor(cause: unknown, message?: string) {
6472 super({ message, cause } as any)
6473 }
6474}
6475
6476// ----------------------------------------------------------------------------
6477// Console
6478// ----------------------------------------------------------------------------
6479
6480/** @internal */
6481export const ConsoleRef = Context.Reference<Console.Console>(
6482 "effect/Console",
6483 { defaultValue: (): Console.Console => globalThis.console }
6484)
6485
6486// ----------------------------------------------------------------------------
6487// LogLevel
6488// ----------------------------------------------------------------------------
6489
6490/** @internal */
6491export const logLevelToOrder = (level: LogLevel.LogLevel) => {
6492 switch (level) {
6493 case "All":
6494 return Number.MIN_SAFE_INTEGER
6495 case "Fatal":
6496 return 50_000
6497 case "Error":
6498 return 40_000
6499 case "Warn":
6500 return 30_000
6501 case "Info":
6502 return 20_000
6503 case "Debug":
6504 return 10_000
6505 case "Trace":
6506 return 0
6507 case "None":
6508 return Number.MAX_SAFE_INTEGER
6509 }
6510}
6511
6512/** @internal */
6513export const LogLevelOrder = Order.mapInput(Order.Number, logLevelToOrder)
6514
6515/** @internal */
6516export const isLogLevelGreaterThan = Order.isGreaterThan(LogLevelOrder)
6517
6518// ----------------------------------------------------------------------------
6519// Logger
6520// ----------------------------------------------------------------------------
6521
6522/** @internal */
6523export const CurrentLoggers = Context.Reference<
6524 ReadonlySet<Logger.Logger<unknown, any>>
6525>("effect/Logger/CurrentLoggers", {
6526 defaultValue: () => new Set([defaultLogger, tracerLogger])
6527})
6528
6529/** @internal */
6530export const LogToStderr = Context.Reference<boolean>("effect/Logger/LogToStderr", {
6531 defaultValue: constFalse
6532})
6533
6534/** @internal */
6535export const annotateLogsScoped: {
6536 (key: string, value: unknown): Effect.Effect<void, never, Scope.Scope>
6537 (values: Record<string, unknown>): Effect.Effect<void, never, Scope.Scope>
6538} = function() {
6539 const entries = typeof arguments[0] === "string" ?
6540 [[arguments[0], arguments[1]]] :
6541 Object.entries(arguments[0])
6542 return uninterruptible(withFiber((fiber) => {
6543 const prev = fiber.getRef(CurrentLogAnnotations)
6544 const next = { ...prev }
6545 for (let i = 0; i < entries.length; i++) {
6546 const [key, value] = entries[i]
6547 InternalRecord.assignProperty(next, key, value)
6548 }
6549 fiber.setContext(Context.add(fiber.context, CurrentLogAnnotations, next))
6550 return scopeAddFinalizerExit(Context.getUnsafe(fiber.context, scopeTag), (_) => {
6551 const current = fiber.getRef(CurrentLogAnnotations)
6552 const next = { ...current }
6553 for (let i = 0; i < entries.length; i++) {
6554 const [key, value] = entries[i]
6555 if (current[key] !== value && !Object.is(current[key], value)) continue
6556 if (Object.hasOwn(prev, key)) {
6557 InternalRecord.assignProperty(next, key, prev[key])
6558 } else {
6559 delete next[key]
6560 }
6561 }
6562 fiber.setContext(Context.add(fiber.context, CurrentLogAnnotations, next))
6563 return void_
6564 })
6565 }))
6566}
6567
6568/** @internal */
6569export const LoggerTypeId = "~effect/Logger"
6570
6571const LoggerProto = {
6572 [LoggerTypeId]: {
6573 _Message: identity,
6574 _Output: identity
6575 },
6576 pipe() {
6577 return pipeArguments(this, arguments)
6578 }
6579}
6580
6581/** @internal */
6582export const loggerMake = <Message, Output>(
6583 log: (options: Logger.Options<Message>) => Output
6584): Logger.Logger<Message, Output> => {
6585 const self = Object.create(LoggerProto)
6586 self.log = log
6587 return self
6588}
6589
6590/**
6591 * Sanitize a given string by replacing spaces, equal signs, and double quotes
6592 * with underscores.
6593 *
6594 * @internal
6595 */
6596export const formatLabel = (key: string) => key.replace(/[\s="]/g, "_")
6597
6598/**
6599 * Formats a log span into a `<label>=<value>ms` string.
6600 *
6601 * @internal
6602 */
6603export const formatLogSpan = (self: [label: string, timestamp: number], now: number): string => {
6604 const label = formatLabel(self[0])
6605 return `${label}=${now - self[1]}ms`
6606}
6607
6608/** @internal */
6609export const structuredMessage = (u: unknown): unknown => {
6610 switch (typeof u) {
6611 case "function":
6612 case "symbol": {
6613 return String(u)
6614 }
6615 default: {
6616 return toJson(u)
6617 }
6618 }
6619}
6620
6621/** @internal */
6622export const logWithLevel = (level?: LogLevel.Severity) =>
6623(
6624 ...message: ReadonlyArray<any>
6625): Effect.Effect<void> => {
6626 let cause: Cause.Cause<unknown> | undefined = undefined
6627 for (let i = 0, len = message.length; i < len; i++) {
6628 const msg = message[i]
6629 if (isCause(msg)) {
6630 if (cause) {
6631 ;(message as Array<any>).splice(i, 1)
6632 } else {
6633 message = message.slice(0, i).concat(message.slice(i + 1))
6634 }
6635 cause = cause ? causeFromReasons(cause.reasons.concat(msg.reasons)) : msg
6636 i--
6637 }
6638 }
6639 if (cause === undefined) {
6640 cause = causeEmpty
6641 }
6642 return withFiber((fiber) => {
6643 const logLevel = level ?? fiber.cache.logLevel
6644 if (isLogLevelGreaterThan(fiber.cache.minimumLogLevel, logLevel)) {
6645 return void_
6646 }
6647 const clock = fiber.getRef(ClockRef)
6648 const loggers = fiber.getRef(CurrentLoggers)
6649 if (loggers.size > 0) {
6650 const date = new Date(clock.currentTimeMillisUnsafe())
6651 for (const logger of loggers) {
6652 logger.log({
6653 cause,
6654 fiber,
6655 date,
6656 logLevel,
6657 message
6658 })
6659 }
6660 }
6661 return void_
6662 })
6663}
6664
6665const withColor = (text: string, ...colors: ReadonlyArray<string>) => {
6666 let out = ""
6667 for (let i = 0; i < colors.length; i++) {
6668 out += `\x1b[${colors[i]}m`
6669 }
6670 return out + text + "\x1b[0m"
6671}
6672const withColorNoop = (text: string, ..._colors: ReadonlyArray<string>) => text
6673const colors = {
6674 bold: "1",
6675 red: "31",
6676 green: "32",
6677 yellow: "33",
6678 blue: "34",
6679 cyan: "36",
6680 white: "37",
6681 gray: "90",
6682 black: "30",
6683 bgBrightRed: "101"
6684} as const
6685
6686const logLevelColors: Record<LogLevel.LogLevel, ReadonlyArray<string>> = {
6687 None: [],
6688 All: [],
6689 Trace: [colors.gray],
6690 Debug: [colors.blue],
6691 Info: [colors.green],
6692 Warn: [colors.yellow],
6693 Error: [colors.red],
6694 Fatal: [colors.bgBrightRed, colors.black]
6695}
6696const logLevelStyle: Record<LogLevel.LogLevel, string> = {
6697 None: "",
6698 All: "",
6699 Trace: "color:gray",
6700 Debug: "color:blue",
6701 Info: "color:green",
6702 Warn: "color:orange",
6703 Error: "color:red",
6704 Fatal: "background-color:red;color:white"
6705}
6706
6707const defaultDateFormat = (date: Date): string =>
6708 `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${
6709 date.getSeconds().toString().padStart(2, "0")
6710 }.${date.getMilliseconds().toString().padStart(3, "0")}`
6711
6712/** @internal */
6713export const consolePretty = (options?: {
6714 readonly colors?: "auto" | boolean | undefined
6715 readonly formatDate?: ((date: Date) => string) | undefined
6716 readonly mode?: "browser" | "tty" | "auto" | undefined
6717}) => {
6718 // evaluated lazily so the module-level bundle stays free of `process`
6719 // property accesses, which bundlers must retain as possible side effects
6720 const process = (globalThis as { readonly process?: { readonly stdout?: unknown } }).process
6721 const hasProcessStdout = typeof process?.stdout === "object" && process.stdout !== null
6722 const isDeno = "Deno" in globalThis
6723 const mode = options?.mode ?? "auto"
6724 const isTtyLogger = mode === "auto" ? hasProcessStdout || isDeno : mode === "tty"
6725
6726 return isTtyLogger ? prettyLoggerTty(options) : prettyLoggerBrowser(options)
6727}
6728
6729/** @internal */
6730export const prettyLoggerTty = (options?: {
6731 readonly colors?: "auto" | boolean | undefined
6732 readonly formatDate?: ((date: Date) => string) | undefined
6733}) => {
6734 const formatDate = options?.formatDate ?? defaultDateFormat
6735 // evaluated lazily so the module-level bundle stays free of `process`
6736 // property accesses, which bundlers must retain as possible side effects
6737 const process = (globalThis as {
6738 readonly process?: {
6739 readonly stdout?: { readonly isTTY?: unknown }
6740 readonly isBun?: boolean
6741 }
6742 }).process
6743
6744 const hasProcessStdout = typeof process?.stdout === "object" && process.stdout !== null
6745 const processStdoutIsTTY = hasProcessStdout && process.stdout.isTTY === true
6746 const showColors = typeof options?.colors === "boolean" ? options.colors : processStdoutIsTTY
6747 const color = showColors ? withColor : withColorNoop
6748
6749 const processIsBun = process?.isBun === true
6750 return loggerMake<unknown, void>(
6751 ({ cause, date, fiber, logLevel, message: message_ }) => {
6752 const console = fiber.getRef(ConsoleRef)
6753 // oxlint-disable-next-line no-console
6754 const log = fiber.getRef(LogToStderr) ? console.error : console.log
6755
6756 const message = Array.isArray(message_) ? message_.slice() : [message_]
6757
6758 let firstLine = color(`[${formatDate(date)}]`, colors.white)
6759 + ` ${color(logLevel.toUpperCase(), ...logLevelColors[logLevel])}`
6760 + ` (#${fiber.id})`
6761
6762 const now = date.getTime()
6763 const spans = fiber.getRef(CurrentLogSpans)
6764 for (const span of spans) {
6765 firstLine += " " + formatLogSpan(span, now)
6766 }
6767
6768 firstLine += ":"
6769 let messageIndex = 0
6770 if (message.length > 0) {
6771 const firstMaybeString = structuredMessage(message[0])
6772 if (typeof firstMaybeString === "string") {
6773 firstLine += " " + color(firstMaybeString, colors.bold, colors.cyan)
6774 messageIndex++
6775 }
6776 }
6777
6778 log(firstLine)
6779 // oxlint-disable-next-line no-console
6780 if (!processIsBun) console.group()
6781
6782 if (cause.reasons.length > 0) {
6783 log(causePretty(cause))
6784 }
6785
6786 if (messageIndex < message.length) {
6787 for (; messageIndex < message.length; messageIndex++) {
6788 log(redact(message[messageIndex]))
6789 }
6790 }
6791
6792 const annotations = fiber.getRef(CurrentLogAnnotations)
6793 for (const [key, value] of Object.entries(annotations)) {
6794 log(color(`${key}:`, colors.bold, colors.white), redact(value))
6795 }
6796
6797 // oxlint-disable-next-line no-console
6798 if (!processIsBun) console.groupEnd()
6799 }
6800 )
6801}
6802
6803/** @internal */
6804export const prettyLoggerBrowser = (options?: {
6805 readonly colors?: "auto" | boolean | undefined
6806 readonly formatDate?: ((date: Date) => string) | undefined
6807}) => {
6808 const showColors = options?.colors !== false
6809 const color = showColors ? "%c" : ""
6810 const formatDate = options?.formatDate ?? defaultDateFormat
6811 return loggerMake<unknown, void>(
6812 ({ cause, date, fiber, logLevel, message: message_ }) => {
6813 const console = fiber.getRef(ConsoleRef)
6814
6815 const message = Array.isArray(message_) ? message_.slice() : [message_]
6816
6817 let firstLine = `${color}[${formatDate(date)}]`
6818 const firstParams = []
6819 if (showColors) {
6820 firstParams.push("color:gray")
6821 }
6822 firstLine += ` ${color}${logLevel.toUpperCase()}${color} (#${fiber.id})`
6823 if (showColors) {
6824 firstParams.push(logLevelStyle[logLevel], "")
6825 }
6826
6827 const now = date.getTime()
6828 const spans = fiber.getRef(CurrentLogSpans)
6829 for (const span of spans) {
6830 firstLine += " " + formatLogSpan(span, now)
6831 }
6832
6833 firstLine += ":"
6834
6835 let messageIndex = 0
6836 if (message.length > 0) {
6837 const firstMaybeString = structuredMessage(message[0])
6838 if (typeof firstMaybeString === "string") {
6839 firstLine += ` ${color}${firstMaybeString}`
6840 if (showColors) {
6841 firstParams.push("color:deepskyblue")
6842 }
6843 messageIndex++
6844 }
6845 }
6846
6847 // oxlint-disable-next-line no-console
6848 console.groupCollapsed(firstLine, ...firstParams)
6849
6850 if (cause.reasons.length > 0) {
6851 // oxlint-disable-next-line no-console
6852 console.error(causePretty(cause))
6853 }
6854
6855 if (messageIndex < message.length) {
6856 for (; messageIndex < message.length; messageIndex++) {
6857 // oxlint-disable-next-line no-console
6858 console.log(redact(message[messageIndex]))
6859 }
6860 }
6861
6862 const annotations = fiber.getRef(CurrentLogAnnotations)
6863 for (const [key, value] of Object.entries(annotations)) {
6864 const redacted = redact(value)
6865 if (showColors) {
6866 // oxlint-disable-next-line no-console
6867 console.log(`%c${key}:`, "color:gray", redacted)
6868 } else {
6869 // oxlint-disable-next-line no-console
6870 console.log(`${key}:`, redacted)
6871 }
6872 }
6873
6874 // oxlint-disable-next-line no-console
6875 console.groupEnd()
6876 }
6877 )
6878}
6879
6880/** @internal */
6881export const defaultLogger = loggerMake<unknown, void>(({ cause, date, fiber, logLevel, message }) => {
6882 const message_ = Array.isArray(message) ? message.slice() : [message]
6883 if (cause.reasons.length > 0) {
6884 message_.push(causePretty(cause))
6885 }
6886 const now = date.getTime()
6887 const spans = fiber.getRef(CurrentLogSpans)
6888 let spanString = ""
6889 for (const span of spans) {
6890 spanString += ` ${formatLogSpan(span, now)}`
6891 }
6892 const annotations = fiber.getRef(CurrentLogAnnotations)
6893 if (Object.keys(annotations).length > 0) {
6894 message_.push(annotations)
6895 }
6896 const console = fiber.getRef(ConsoleRef)
6897 // oxlint-disable-next-line no-console
6898 const log = fiber.getRef(LogToStderr) ? console.error : console.log
6899 log(`[${defaultDateFormat(date)}] ${logLevel.toUpperCase()} (#${fiber.id})${spanString}:`, ...message_)
6900})
6901
6902/** @internal */
6903export const tracerLogger = loggerMake<unknown, void>(({ cause, fiber, logLevel, message }) => {
6904 const clock = fiber.getRef(ClockRef)
6905 const annotations = fiber.getRef(CurrentLogAnnotations)
6906 const span = fiber.cache.span
6907 if (span === undefined || span._tag === "ExternalSpan") return
6908 const attributes: Record<string, unknown> = {}
6909 for (const [key, value] of Object.entries(annotations)) {
6910 InternalRecord.assignProperty(attributes, key, value)
6911 }
6912 attributes["effect.fiberId"] = fiber.id
6913 attributes["effect.logLevel"] = logLevel.toUpperCase()
6914 if (cause.reasons.length > 0) {
6915 attributes["effect.cause"] = causePretty(cause)
6916 }
6917 span.event(
6918 toStringUnknown(Array.isArray(message) && message.length === 1 ? message[0] : message),
6919 clock.currentTimeNanosUnsafe(),
6920 attributes
6921 )
6922})
6923
6924/** @internal */
6925export function interruptChildrenPatch() {
6926 fiberMiddleware.interruptChildren ??= fiberInterruptChildren
6927}
6928
6929/** @internal */
6930const undefined_ = succeed(undefined)
6931
6932/** @internal */
6933export { undefined_ as undefined }
6934
6935// ----------------------------------------------------------------------------
6936// ErrorReporter
6937// ----------------------------------------------------------------------------
6938
6939/** @internal */
6940export const withErrorReporting: <
6941 Arg extends Effect.Effect<any, any, any> | {
6942 readonly defectsOnly?: boolean | undefined
6943 } | undefined = {
6944 readonly defectsOnly?: boolean | undefined
6945 }
6946>(
6947 effectOrOptions: Arg,
6948 options?: {
6949 readonly defectsOnly?: boolean | undefined
6950 } | undefined
6951) => [Arg] extends [Effect.Effect<infer A, infer E, infer R>] ? Effect.Effect<A, E, R>
6952 : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> = dual(
6953 (args) => isEffect(args[0]),
6954 <A, E, R>(
6955 self: Effect.Effect<A, E, R>,
6956 options?: {
6957 readonly defectsOnly?: boolean | undefined
6958 } | undefined
6959 ): Effect.Effect<A, E, R> =>
6960 onError(self, (cause) =>
6961 withFiber((fiber) => {
6962 reportCauseUnsafe(fiber, cause, options?.defectsOnly)
6963 return void_
6964 }))
6965 )
6966
6967/** @internal */
6968export const reportCauseUnsafe = (
6969 fiber: Fiber.Fiber<unknown, unknown>,
6970 cause: Cause.Cause<unknown>,
6971 defectsOnly?: boolean
6972) => {
6973 const reporters = fiber.getRef(CurrentErrorReporters)
6974 if (reporters.size === 0) return
6975 if (defectsOnly && !hasDies(cause)) return
6976 const opts = { cause, fiber, timestamp: fiber.getRef(ClockRef).currentTimeNanosUnsafe() }
6977 reporters.forEach((reporter) => reporter.report(opts))
6978}