| import * as Arr from "../Array.ts" | |
| import type * as Cause from "../Cause.ts" | |
| import type * as Clock from "../Clock.ts" | |
| import type * as Console from "../Console.ts" | |
| import * as Context from "../Context.ts" | |
| import * as Duration from "../Duration.ts" | |
| import type * as Effect from "../Effect.ts" | |
| import * as Equal from "../Equal.ts" | |
| import type * as Exit from "../Exit.ts" | |
| import type * as Fiber from "../Fiber.ts" | |
| import * as Filter from "../Filter.ts" | |
| import { formatJson } from "../Formatter.ts" | |
| import type { LazyArg } from "../Function.ts" | |
| import { constant, constFalse, constTrue, constUndefined, constVoid, dual, identity } from "../Function.ts" | |
| import * as Hash from "../Hash.ts" | |
| import { toJson, toStringUnknown } from "../Inspectable.ts" | |
| import * as Iterable from "../Iterable.ts" | |
| import type * as _Latch from "../Latch.ts" | |
| import type * as Logger from "../Logger.ts" | |
| import type * as LogLevel from "../LogLevel.ts" | |
| import type * as Metric from "../Metric.ts" | |
| import * as Option from "../Option.ts" | |
| import * as Order from "../Order.ts" | |
| import { pipeArguments } from "../Pipeable.ts" | |
| import type * as Predicate from "../Predicate.ts" | |
| import { hasProperty, isIterable, isString, isTagged } from "../Predicate.ts" | |
| import { currentFiberTypeId, redact } from "../Redactable.ts" | |
| import type { StackFrame } from "../References.ts" | |
| import * as Result from "../Result.ts" | |
| import * as Scheduler from "../Scheduler.ts" | |
| import type * as Scope from "../Scope.ts" | |
| import * as Tracer from "../Tracer.ts" | |
| import type { | |
| Concurrency, | |
| EqualsWith, | |
| ExcludeReason, | |
| ExcludeTag, | |
| ExtractReason, | |
| ExtractTag, | |
| NarrowReason, | |
| NoInfer, | |
| OmitReason, | |
| ReasonOf, | |
| ReasonTags, | |
| Simplify, | |
| Tags, | |
| unassigned | |
| } from "../Types.ts" | |
| import { internalCall } from "../Utils.ts" | |
| import type { Primitive } from "./core.ts" | |
| import { | |
| args, | |
| causeAnnotate, | |
| causeEmpty, | |
| causeFromReasons, | |
| CauseImpl, | |
| constEmptyAnnotations, | |
| contA, | |
| contAll, | |
| contE, | |
| evaluate, | |
| exitDie, | |
| exitFail, | |
| exitFailCause, | |
| exitSucceed, | |
| ExitTypeId, | |
| Fail, | |
| InterruptorStackTrace, | |
| isCause, | |
| isDieReason, | |
| isEffect, | |
| isFailReason, | |
| isInterruptReason, | |
| isNoSuchElementError, | |
| makePrimitive, | |
| makePrimitiveProto, | |
| NoSuchElementError, | |
| ReasonBase, | |
| StackTraceKey as CauseStackTrace, | |
| TaggedError, | |
| withFiber, | |
| Yield | |
| } from "./core.ts" | |
| import * as doNotation from "./doNotation.ts" | |
| import * as InternalMetric from "./metric.ts" | |
| import { | |
| CurrentConcurrency, | |
| CurrentErrorReporters, | |
| CurrentLogAnnotations, | |
| CurrentLogLevel, | |
| CurrentLogSpans, | |
| CurrentStackFrame, | |
| MinimumLogLevel, | |
| TracerEnabled, | |
| TracerSpanAnnotations, | |
| TracerSpanLinks, | |
| TracerTimingEnabled | |
| } from "./references.ts" | |
| import { addSpanStackTrace, type ErrorWithStackTraceLimit, makeStackCleaner } from "./tracer.ts" | |
| import { version } from "./version.ts" | |
| // ---------------------------------------------------------------------------- | |
| // Cause | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export class Interrupt extends ReasonBase<"Interrupt"> implements Cause.Interrupt { | |
| readonly fiberId: number | undefined | |
| constructor( | |
| fiberId: number | undefined, | |
| annotations = constEmptyAnnotations | |
| ) { | |
| super("Interrupt", annotations, "Interrupted") | |
| this.fiberId = fiberId | |
| } | |
| override toString() { | |
| return `Interrupt(${this.fiberId})` | |
| } | |
| toJSON(): unknown { | |
| return { | |
| _tag: "Interrupt", | |
| fiberId: this.fiberId | |
| } | |
| } | |
| [Equal.symbol](that: any): boolean { | |
| return ( | |
| isInterruptReason(that) && | |
| this.fiberId === that.fiberId && | |
| this.annotations === that.annotations | |
| ) | |
| } | |
| [Hash.symbol](): number { | |
| return Hash.combine(Hash.string(`${this._tag}:${this.fiberId}`))( | |
| Hash.random(this.annotations) | |
| ) | |
| } | |
| } | |
| /** @internal */ | |
| export const makeInterruptReason = (fiberId?: number | undefined): Cause.Interrupt => new Interrupt(fiberId) | |
| /** @internal */ | |
| export const causeInterrupt = ( | |
| fiberId?: number | undefined | |
| ): Cause.Cause<never> => new CauseImpl([new Interrupt(fiberId)]) | |
| /** @internal */ | |
| export const hasFails = <E>(self: Cause.Cause<E>): boolean => self.reasons.some(isFailReason) | |
| /** @internal */ | |
| export const findFail = <E>(self: Cause.Cause<E>): Result.Result<Cause.Fail<E>, Cause.Cause<never>> => { | |
| const reason = self.reasons.find(isFailReason) | |
| return reason ? Result.succeed(reason) : Result.fail(self as Cause.Cause<never>) | |
| } | |
| /** @internal */ | |
| export const findError = <E>(self: Cause.Cause<E>): Result.Result<E, Cause.Cause<never>> => { | |
| for (let i = 0; i < self.reasons.length; i++) { | |
| const reason = self.reasons[i] | |
| if (reason._tag === "Fail") { | |
| return Result.succeed(reason.error) | |
| } | |
| } | |
| return Result.fail(self as Cause.Cause<never>) | |
| } | |
| /** @internal */ | |
| export const findErrorOption = Filter.toOption(findError) | |
| /** @internal */ | |
| export const hasDies = <E>(self: Cause.Cause<E>): boolean => self.reasons.some(isDieReason) | |
| /** @internal */ | |
| export const findDie = <E>(self: Cause.Cause<E>): Result.Result<Cause.Die, Cause.Cause<E>> => { | |
| const reason = self.reasons.find(isDieReason) | |
| return reason ? Result.succeed(reason) : Result.fail(self) | |
| } | |
| /** @internal */ | |
| export const findDefect = <E>(self: Cause.Cause<E>): Result.Result<unknown, Cause.Cause<E>> => { | |
| const reason = self.reasons.find(isDieReason) | |
| return reason ? Result.succeed(reason.defect) : Result.fail(self) | |
| } | |
| /** @internal */ | |
| export const hasInterrupts = <E>(self: Cause.Cause<E>): boolean => self.reasons.some(isInterruptReason) | |
| /** @internal */ | |
| export const findInterrupt = <E>(self: Cause.Cause<E>): Result.Result<Cause.Interrupt, Cause.Cause<E>> => { | |
| const reason = self.reasons.find(isInterruptReason) | |
| return reason ? Result.succeed(reason) : Result.fail(self) | |
| } | |
| /** @internal */ | |
| export const causeFilterInterruptors = <E>( | |
| self: Cause.Cause<E> | |
| ): Result.Result<Set<number>, Cause.Cause<E>> => { | |
| let interruptors: Set<number> | undefined | |
| for (let i = 0; i < self.reasons.length; i++) { | |
| const f = self.reasons[i] | |
| if (f._tag !== "Interrupt") continue | |
| interruptors ??= new Set() | |
| if (f.fiberId !== undefined) { | |
| interruptors.add(f.fiberId) | |
| } | |
| } | |
| return interruptors ? Result.succeed(interruptors) : Result.fail(self) | |
| } | |
| /** @internal */ | |
| export const causeInterruptors = <E>(self: Cause.Cause<E>): ReadonlySet<number> => { | |
| const result = causeFilterInterruptors(self) | |
| return Result.isFailure(result) ? emptySet : result.success | |
| } | |
| const emptySet = new Set<number>() | |
| /** @internal */ | |
| export const hasInterruptsOnly = <E>(self: Cause.Cause<E>): boolean => | |
| self.reasons.length > 0 && self.reasons.every(isInterruptReason) | |
| /** @internal */ | |
| export const reasonAnnotations = <E>( | |
| self: Cause.Reason<E> | |
| ): Context.Context<never> => Context.makeUnsafe(self.annotations) | |
| /** @internal */ | |
| export const causeAnnotations = <E>( | |
| self: Cause.Cause<E> | |
| ): Context.Context<never> => { | |
| const map = new Map<string, unknown>() | |
| for (const f of self.reasons) { | |
| if (f.annotations.size > 0) { | |
| for (const [key, value] of f.annotations) { | |
| map.set(key, value) | |
| } | |
| } | |
| } | |
| return Context.makeUnsafe(map) | |
| } | |
| /** @internal */ | |
| export const causeCombine: { | |
| <E2>(that: Cause.Cause<E2>): <E>(self: Cause.Cause<E>) => Cause.Cause<E | E2> | |
| <E, E2>(self: Cause.Cause<E>, that: Cause.Cause<E2>): Cause.Cause<E | E2> | |
| } = dual( | |
| 2, | |
| <E, E2>(self: Cause.Cause<E>, that: Cause.Cause<E2>): Cause.Cause<E | E2> => { | |
| if (self.reasons.length === 0) { | |
| return that as Cause.Cause<E | E2> | |
| } else if (that.reasons.length === 0) { | |
| return self as Cause.Cause<E | E2> | |
| } | |
| const newCause = new CauseImpl<E | E2>( | |
| Arr.union(self.reasons, that.reasons) | |
| ) | |
| return Equal.equals(self, newCause) ? self : newCause | |
| } | |
| ) | |
| /** @internal */ | |
| export const causeMap: { | |
| <E, E2>(f: (error: NoInfer<E>) => E2): (self: Cause.Cause<E>) => Cause.Cause<E2> | |
| <E, E2>(self: Cause.Cause<E>, f: (error: NoInfer<E>) => E2): Cause.Cause<E2> | |
| } = dual( | |
| 2, | |
| <E, E2>(self: Cause.Cause<E>, f: (error: NoInfer<E>) => E2): Cause.Cause<E2> => { | |
| let hasFail = false | |
| const failures = self.reasons.map((failure) => { | |
| if (isFailReason(failure)) { | |
| hasFail = true | |
| return new Fail(f(failure.error)) | |
| } | |
| return failure | |
| }) | |
| return hasFail ? causeFromReasons(failures) : self as any | |
| } | |
| ) | |
| /** @internal */ | |
| export const causePartition = <E>( | |
| self: Cause.Cause<E> | |
| ): { | |
| readonly Fail: ReadonlyArray<Cause.Fail<E>> | |
| readonly Die: ReadonlyArray<Cause.Die> | |
| readonly Interrupt: ReadonlyArray<Cause.Interrupt> | |
| } => { | |
| const obj = { | |
| Fail: [] as Array<Cause.Fail<E>>, | |
| Die: [] as Array<Cause.Die>, | |
| Interrupt: [] as Array<Cause.Interrupt> | |
| } | |
| for (let i = 0; i < self.reasons.length; i++) { | |
| obj[self.reasons[i]._tag].push(self.reasons[i] as any) | |
| } | |
| return obj | |
| } | |
| /** @internal */ | |
| export const causeSquash = <E>(self: Cause.Cause<E>): unknown => { | |
| const partitioned = causePartition(self) | |
| if (partitioned.Fail.length > 0) { | |
| return partitioned.Fail[0].error | |
| } else if (partitioned.Die.length > 0) { | |
| return partitioned.Die[0].defect | |
| } else if (partitioned.Interrupt.length > 0) { | |
| return new globalThis.Error("All fibers interrupted without error") | |
| } | |
| return new globalThis.Error("Empty cause") | |
| } | |
| /** @internal */ | |
| export const causePrettyErrors = <E>(self: Cause.Cause<E>): Array<Error> => { | |
| const errors: Array<Error> = [] | |
| const interrupts: Array<Cause.Interrupt> = [] | |
| if (self.reasons.length === 0) return errors | |
| const prevStackLimit = (Error as ErrorWithStackTraceLimit).stackTraceLimit | |
| ;(Error as ErrorWithStackTraceLimit) | |
| .stackTraceLimit = 1 | |
| for (const failure of self.reasons) { | |
| if (failure._tag === "Interrupt") { | |
| interrupts.push(failure) | |
| continue | |
| } | |
| errors.push( | |
| causePrettyError( | |
| failure._tag === "Die" ? failure.defect : failure.error as any, | |
| failure.annotations | |
| ) | |
| ) | |
| } | |
| if (errors.length === 0) { | |
| const cause = new Error("The fiber was interrupted by:") | |
| cause.name = "InterruptCause" | |
| cause.stack = interruptCauseStack(cause, interrupts) | |
| const error = new globalThis.Error("All fibers interrupted without error", { cause }) | |
| error.name = "InterruptError" | |
| error.stack = `${error.name}: ${error.message}` | |
| errors.push(causePrettyError(error, interrupts[0].annotations)) | |
| } | |
| ;(Error as ErrorWithStackTraceLimit).stackTraceLimit = prevStackLimit | |
| return errors | |
| } | |
| /** @internal */ | |
| export const causePrettyError = ( | |
| original: Record<string, unknown> | Error, | |
| annotations?: ReadonlyMap<string, unknown> | |
| ): Error => { | |
| const kind = typeof original | |
| let error: Error | |
| if (original && kind === "object") { | |
| error = new globalThis.Error(causePrettyMessage(original), { | |
| cause: original.cause ? causePrettyError(original.cause as any) : undefined | |
| }) | |
| if (typeof original.name === "string") { | |
| error.name = original.name | |
| } | |
| if (typeof original.stack === "string") { | |
| error.stack = cleanErrorStack(original.stack, error, annotations) | |
| } else { | |
| const stack = `${error.name}: ${error.message}` | |
| error.stack = annotations ? addStackAnnotations(stack, annotations) : stack | |
| } | |
| for (const key of Object.keys(original)) { | |
| if (!(key in error)) { | |
| ;(error as any)[key] = (original as any)[key] | |
| } | |
| } | |
| } else { | |
| error = new globalThis.Error( | |
| !original ? `Unknown error: ${original}` : kind === "string" ? original as any : formatJson(original) | |
| ) | |
| } | |
| return error | |
| } | |
| const causePrettyMessage = (u: Record<string, unknown> | Error): string => { | |
| if (typeof u.message === "string") { | |
| return u.message | |
| } else if ( | |
| typeof u.toString === "function" | |
| && u.toString !== Object.prototype.toString | |
| && u.toString !== Array.prototype.toString | |
| ) { | |
| try { | |
| return u.toString() | |
| } catch { | |
| // something's off, rollback to json | |
| } | |
| } | |
| return formatJson(u) | |
| } | |
| const locationRegExp = /\((.*)\)/g | |
| const cleanErrorStack = ( | |
| stack: string, | |
| error: Error, | |
| annotations: ReadonlyMap<string, unknown> | undefined | |
| ): string => { | |
| const message = `${error.name}: ${error.message}` | |
| const lines = (stack.startsWith(message) ? stack.slice(message.length) : stack).split("\n") | |
| const out: Array<string> = [message] | |
| for (let i = 1; i < lines.length; i++) { | |
| if (/(?:Generator\.next|~effect\/Effect)/.test(lines[i])) { | |
| break | |
| } | |
| out.push(lines[i]) | |
| } | |
| return annotations ? addStackAnnotations(out.join("\n"), annotations) : out.join("\n") | |
| } | |
| const addStackAnnotations = (stack: string, annotations: ReadonlyMap<string, unknown>) => { | |
| const frame = annotations?.get(CauseStackTrace.key) as StackFrame | undefined | |
| if (frame) { | |
| stack = `${stack}\n${currentStackTrace(frame)}` | |
| } | |
| return stack | |
| } | |
| const interruptCauseStack = (error: Error, interrupts: Array<Cause.Interrupt>): string => { | |
| const out: Array<string> = [`${error.name}: ${error.message}`] | |
| for (const current of interrupts) { | |
| const fiberId = current.fiberId !== undefined ? `#${current.fiberId}` : "unknown" | |
| const frame = current.annotations.get(InterruptorStackTrace.key) as StackFrame | undefined | |
| out.push(` at fiber (${fiberId})`) | |
| if (frame) out.push(currentStackTrace(frame)) | |
| } | |
| return out.join("\n") | |
| } | |
| const currentStackTrace = (frame: StackFrame): string => { | |
| const out: Array<string> = [] | |
| let current: StackFrame | undefined = frame | |
| let i = 0 | |
| while (current && i < 10) { | |
| const stack = current.stack() | |
| if (stack) { | |
| const locationMatchAll = stack.matchAll(locationRegExp) | |
| let match = false | |
| for (const [, location] of locationMatchAll) { | |
| match = true | |
| out.push(` at ${current.name} (${location})`) | |
| } | |
| if (!match) { | |
| out.push(` at ${current.name} (${stack.replace(/^at /, "")})`) | |
| } | |
| } else { | |
| out.push(` at ${current.name}`) | |
| } | |
| current = current.parent | |
| i++ | |
| } | |
| return out.join("\n") | |
| } | |
| /** @internal */ | |
| export const causePretty = <E>(cause: Cause.Cause<E>): string => | |
| causePrettyErrors<E>(cause).map((e) => | |
| e.cause ? `${e.stack} {\n${renderErrorCause(e.cause as Error, " ")}\n}` : e.stack | |
| ) | |
| .join("\n") | |
| const renderErrorCause = (cause: Error, prefix: string) => { | |
| const lines = cause.stack!.split("\n") | |
| let stack = `${prefix}[cause]: ${lines[0]}` | |
| for (let i = 1, len = lines.length; i < len; i++) { | |
| stack += `\n${prefix}${lines[i]}` | |
| } | |
| if (cause.cause) { | |
| stack += ` {\n${renderErrorCause(cause.cause as Error, `${prefix} `)}\n${prefix}}` | |
| } | |
| return stack | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // Fiber | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const FiberTypeId = `~effect/Fiber/${version}` as const | |
| const fiberVariance = { | |
| _A: identity, | |
| _E: identity | |
| } | |
| const fiberIdStore = { id: 0 } | |
| /** @internal */ | |
| export const getCurrentFiber = (): Fiber.Fiber<any, any> | undefined => (globalThis as any)[currentFiberTypeId] | |
| /** @internal */ | |
| export class FiberImpl<A = any, E = any> implements Fiber.Fiber<A, E> { | |
| constructor( | |
| context: Context.Context<never>, | |
| interruptible: boolean = true | |
| ) { | |
| this[FiberTypeId] = fiberVariance as any | |
| this.setContext(context) | |
| this.id = ++fiberIdStore.id | |
| this.currentOpCount = 0 | |
| this.currentLoopCount = 0 | |
| this.interruptible = interruptible | |
| this._stack = [] | |
| this._observers = [] | |
| this._exit = undefined | |
| this._children = undefined | |
| this._interruptedCause = undefined | |
| this._yielded = undefined | |
| this.runtimeMetrics?.recordFiberStart(this.context) | |
| } | |
| readonly [FiberTypeId]: Fiber.Fiber.Variance<A, E> | |
| readonly id: number | |
| interruptible: boolean | |
| currentOpCount: number | |
| currentLoopCount: number | |
| readonly _stack: Array<Primitive> | |
| readonly _observers: Array<(exit: Exit.Exit<A, E>) => void> | |
| _exit: Exit.Exit<A, E> | undefined | |
| _currentExit: Exit.Exit<A, E> | undefined | |
| _children: Set<FiberImpl<any, any>> | undefined | |
| _interruptedCause: Cause.Cause<never> | undefined | |
| _yielded: Exit.Exit<any, any> | (() => void) | undefined | |
| // set in setContext | |
| context!: Context.Context<never> | |
| currentScheduler!: Scheduler.Scheduler | |
| currentTracerContext: Tracer.Tracer["context"] | |
| currentSpan: Tracer.AnySpan | undefined | |
| currentLogLevel!: LogLevel.LogLevel | |
| minimumLogLevel!: LogLevel.LogLevel | |
| currentStackFrame: StackFrame | undefined | |
| runtimeMetrics: Metric.FiberRuntimeMetricsService | undefined | |
| maxOpsBeforeYield!: number | |
| currentPreventYield!: boolean | |
| _dispatcher: Scheduler.SchedulerDispatcher | undefined = undefined | |
| get currentDispatcher(): Scheduler.SchedulerDispatcher { | |
| return this._dispatcher ??= this.currentScheduler.makeDispatcher() | |
| } | |
| getRef<X>(ref: Context.Reference<X>): X { | |
| return Context.getReferenceUnsafe(this.context, ref) | |
| } | |
| addObserver(cb: (exit: Exit.Exit<A, E>) => void): () => void { | |
| if (this._exit) { | |
| cb(this._exit) | |
| return constVoid | |
| } | |
| this._observers.push(cb) | |
| return () => { | |
| const index = this._observers.indexOf(cb) | |
| if (index >= 0) { | |
| this._observers.splice(index, 1) | |
| } | |
| } | |
| } | |
| interruptUnsafe(fiberId?: number | undefined, annotations?: Context.Context<never> | undefined): void { | |
| if (this._exit) { | |
| return | |
| } | |
| let cause = causeInterrupt(fiberId) | |
| if (this.currentStackFrame) { | |
| cause = causeAnnotate(cause, Context.make(CauseStackTrace, this.currentStackFrame)) | |
| } | |
| if (annotations) { | |
| cause = causeAnnotate(cause, annotations) | |
| } | |
| this._interruptedCause = this._interruptedCause | |
| ? causeCombine(this._interruptedCause, cause) | |
| : cause | |
| if (this.interruptible) { | |
| this.evaluate(failCause(this._interruptedCause) as any) | |
| } | |
| } | |
| pollUnsafe(): Exit.Exit<A, E> | undefined { | |
| return this._exit | |
| } | |
| evaluate(effect: Primitive): void { | |
| if (this._exit) { | |
| return | |
| } else if (this._yielded !== undefined) { | |
| const yielded = this._yielded as () => void | |
| this._yielded = undefined | |
| yielded() | |
| } | |
| const exit = this.runLoop(effect) | |
| if (exit === Yield) { | |
| return | |
| } | |
| // the interruptChildren middleware is added in Effect.forkChild, so it can be | |
| // tree-shaken if not used | |
| const interruptChildren = fiberMiddleware.interruptChildren && | |
| fiberMiddleware.interruptChildren(this) | |
| if (interruptChildren !== undefined) { | |
| return this.evaluate(flatMap(interruptChildren, () => exit) as any) | |
| } | |
| this._exit = exit | |
| this.runtimeMetrics?.recordFiberEnd(this.context, this._exit) | |
| for (let i = 0; i < this._observers.length; i++) { | |
| this._observers[i](exit) | |
| } | |
| this._observers.length = 0 | |
| } | |
| runLoop(effect: Primitive): Exit.Exit<A, E> | Yield { | |
| const prevFiber = (globalThis as any)[currentFiberTypeId] | |
| ;(globalThis as any)[currentFiberTypeId] = this | |
| let yielding = false | |
| let current: Primitive | Yield = effect | |
| this.currentOpCount = 0 | |
| const currentLoop = ++this.currentLoopCount | |
| try { | |
| while (true) { | |
| this.currentOpCount++ | |
| if ( | |
| !yielding && | |
| !this.currentPreventYield && | |
| this.currentScheduler.shouldYield(this as any) | |
| ) { | |
| yielding = true | |
| const prev = current | |
| current = flatMap(yieldNow, () => prev as any) as any | |
| } | |
| current = this.currentTracerContext | |
| ? this.currentTracerContext(current as any, this) | |
| : (current as any)[evaluate](this) | |
| if (currentLoop !== this.currentLoopCount) { | |
| // another effect has taken over the loop, | |
| return Yield | |
| } else if (current === Yield) { | |
| const yielded = this._yielded! | |
| if (ExitTypeId in yielded) { | |
| this._yielded = undefined | |
| return yielded | |
| } | |
| return Yield | |
| } | |
| } | |
| } catch (error) { | |
| if (!hasProperty(current, evaluate)) { | |
| return exitDie(`Fiber.runLoop: Not a valid effect: ${String(current)}`) | |
| } | |
| return this.runLoop(exitDie(error) as any) | |
| } finally { | |
| ;(globalThis as any)[currentFiberTypeId] = prevFiber | |
| } | |
| } | |
| getCont<S extends contA | contE>(symbol: S): | |
| | (Primitive & Record<S, (value: any, fiber: FiberImpl) => Primitive>) | |
| | undefined | |
| { | |
| while (true) { | |
| const op = this._stack.pop() | |
| if (!op) return undefined | |
| const cont = op[contAll] && op[contAll](this) | |
| if (cont) { | |
| ;(cont as any)[symbol] = cont | |
| return cont as any | |
| } | |
| if (op[symbol]) return op as any | |
| } | |
| } | |
| yieldWith(value: Exit.Exit<any, any> | (() => void)): Yield { | |
| this._yielded = value | |
| return Yield | |
| } | |
| children(): Set<Fiber.Fiber<any, any>> { | |
| return (this._children ??= new Set()) | |
| } | |
| pipe() { | |
| return pipeArguments(this, arguments) | |
| } | |
| setContext(context: Context.Context<never>): void { | |
| this.context = context | |
| const scheduler = this.getRef(Scheduler.Scheduler) | |
| if (scheduler !== this.currentScheduler) { | |
| this.currentScheduler = scheduler | |
| this._dispatcher = undefined | |
| } | |
| this.currentSpan = context.mapUnsafe.get(Tracer.ParentSpanKey) | |
| this.currentLogLevel = this.getRef(CurrentLogLevel) | |
| this.minimumLogLevel = this.getRef(MinimumLogLevel) | |
| this.currentStackFrame = context.mapUnsafe.get(CurrentStackFrame.key) | |
| this.maxOpsBeforeYield = this.getRef(Scheduler.MaxOpsBeforeYield) | |
| this.currentPreventYield = this.getRef(Scheduler.PreventSchedulerYield) | |
| this.runtimeMetrics = context.mapUnsafe.get(InternalMetric.FiberRuntimeMetricsKey) | |
| const currentTracer = context.mapUnsafe.get(Tracer.TracerKey) | |
| this.currentTracerContext = currentTracer ? currentTracer["context"] : undefined | |
| } | |
| get currentSpanLocal(): Tracer.Span | undefined { | |
| return this.currentSpan?._tag === "Span" ? this.currentSpan : undefined | |
| } | |
| } | |
| const fiberMiddleware = { | |
| interruptChildren: undefined as | |
| | ((fiber: FiberImpl) => Effect.Effect<void> | undefined) | |
| | undefined | |
| } | |
| const fiberStackAnnotations = (fiber: Fiber.Fiber<any, any>) => { | |
| if (!fiber.currentStackFrame) return undefined | |
| const annotations = new Map<string, unknown>() | |
| annotations.set(CauseStackTrace.key, fiber.currentStackFrame) | |
| return Context.makeUnsafe(annotations) | |
| } | |
| const fiberInterruptChildren = (fiber: FiberImpl) => { | |
| if (fiber._children === undefined || fiber._children.size === 0) { | |
| return undefined | |
| } | |
| return fiberInterruptAll(fiber._children) | |
| } | |
| /** @internal */ | |
| export const fiberAwait = <A, E>( | |
| self: Fiber.Fiber<A, E> | |
| ): Effect.Effect<Exit.Exit<A, E>> => { | |
| const impl = self as FiberImpl<A, E> | |
| if (impl._exit) return succeed(impl._exit) | |
| return callback((resume) => { | |
| if (impl._exit) return resume(succeed(impl._exit)) | |
| return sync(self.addObserver((exit) => resume(succeed(exit)))) | |
| }) | |
| } | |
| /** @internal */ | |
| export const fiberAwaitAll = <Fiber extends Fiber.Fiber<any, any>>( | |
| self: Iterable<Fiber> | |
| ): Effect.Effect< | |
| Array< | |
| Exit.Exit< | |
| Fiber extends Fiber.Fiber<infer _A, infer _E> ? _A : never, | |
| Fiber extends Fiber.Fiber<infer _A, infer _E> ? _E : never | |
| > | |
| > | |
| > => | |
| callback((resume) => { | |
| const iter = self[Symbol.iterator]() as Iterator<FiberImpl> | |
| const exits: Array<Exit.Exit<any, any>> = [] | |
| let cancel: (() => void) | undefined = undefined | |
| function loop() { | |
| let result = iter.next() | |
| while (!result.done) { | |
| if (result.value._exit) { | |
| exits.push(result.value._exit) | |
| result = iter.next() | |
| continue | |
| } | |
| cancel = result.value.addObserver((exit) => { | |
| exits.push(exit) | |
| loop() | |
| }) | |
| return | |
| } | |
| resume(succeed(exits)) | |
| } | |
| loop() | |
| return sync(() => cancel?.()) | |
| }) | |
| /** @internal */ | |
| export const fiberJoin = <A, E>(self: Fiber.Fiber<A, E>): Effect.Effect<A, E> => { | |
| const impl = self as FiberImpl<A, E> | |
| if (impl._exit) return impl._exit | |
| return callback((resume) => { | |
| if (impl._exit) return resume(impl._exit) | |
| return sync(self.addObserver(resume)) | |
| }) | |
| } | |
| /** @internal */ | |
| export const fiberJoinAll = <A extends Iterable<Fiber.Fiber<any, any>>>(self: A): Effect.Effect< | |
| Arr.ReadonlyArray.With<A, A extends Iterable<Fiber.Fiber<infer _A, infer _E>> ? _A : never>, | |
| A extends Fiber.Fiber<infer _A, infer _E> ? _E : never | |
| > => | |
| callback((resume) => { | |
| const fibers = Array.from(self) | |
| if (fibers.length === 0) return resume(succeed(Arr.empty() as any)) | |
| const out = new Array<any>(fibers.length) as Arr.NonEmptyArray<any> | |
| const cancels = Arr.empty<() => void>() | |
| let done = 0 | |
| let failed = false | |
| for (let i = 0; i < fibers.length; i++) { | |
| if (failed) break | |
| cancels.push(fibers[i].addObserver((exit) => { | |
| done++ | |
| if (exit._tag === "Failure") { | |
| failed = true | |
| cancels.forEach((cancel) => cancel()) | |
| return resume(exit as any) | |
| } | |
| out[i] = exit.value | |
| if (done === fibers.length) { | |
| resume(succeed(out)) | |
| } | |
| })) | |
| } | |
| }) | |
| /** @internal */ | |
| export const fiberInterrupt = <A, E>( | |
| self: Fiber.Fiber<A, E> | |
| ): Effect.Effect<void> => withFiber((fiber) => fiberInterruptAs(self, fiber.id)) | |
| /** @internal */ | |
| export const fiberInterruptAs: { | |
| ( | |
| fiberId: number | undefined, | |
| annotations?: Context.Context<never> | undefined | |
| ): <A, E>(self: Fiber.Fiber<A, E>) => Effect.Effect<void> | |
| <A, E>( | |
| self: Fiber.Fiber<A, E>, | |
| fiberId: number | undefined, | |
| annotations?: Context.Context<never> | undefined | |
| ): Effect.Effect<void> | |
| } = dual( | |
| (args) => hasProperty(args[0], FiberTypeId), | |
| <A, E>( | |
| self: Fiber.Fiber<A, E>, | |
| fiberId: number | undefined, | |
| annotations?: Context.Context<never> | undefined | |
| ): Effect.Effect<void> => | |
| withFiber((parent) => { | |
| let ann = fiberStackAnnotations(parent) | |
| ann = ann && annotations ? Context.merge(ann, annotations) : ann ?? annotations | |
| self.interruptUnsafe(fiberId, ann) | |
| return asVoid(fiberAwait(self)) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const fiberInterruptAll = <A extends Iterable<Fiber.Fiber<any, any>>>( | |
| fibers: A | |
| ): Effect.Effect<void> => | |
| withFiber((parent) => { | |
| const annotations = fiberStackAnnotations(parent) | |
| for (const fiber of fibers) { | |
| fiber.interruptUnsafe(parent.id, annotations) | |
| } | |
| return asVoid(fiberAwaitAll(fibers)) | |
| }) | |
| /** @internal */ | |
| export const fiberInterruptAllAs: { | |
| (fiberId: number): <A extends Iterable<Fiber.Fiber<any, any>>>(fibers: A) => Effect.Effect<void> | |
| <A extends Iterable<Fiber.Fiber<any, any>>>(fibers: A, fiberId: number): Effect.Effect<void> | |
| } = dual(2, <A extends Iterable<Fiber.Fiber<any, any>>>( | |
| fibers: A, | |
| fiberId: number | |
| ): Effect.Effect<void> => | |
| withFiber((parent) => { | |
| const annotations = fiberStackAnnotations(parent) | |
| for (const fiber of fibers) fiber.interruptUnsafe(fiberId, annotations) | |
| return asVoid(fiberAwaitAll(fibers)) | |
| })) | |
| /** @internal */ | |
| export const succeed: <A>(value: A) => Effect.Effect<A> = exitSucceed | |
| /** @internal */ | |
| export const failCause: <E>(cause: Cause.Cause<E>) => Effect.Effect<never, E> = exitFailCause | |
| /** @internal */ | |
| export const fail: <E>(error: E) => Effect.Effect<never, E> = exitFail | |
| /** @internal */ | |
| export const sync: <A>(thunk: LazyArg<A>) => Effect.Effect<A> = makePrimitive({ | |
| op: "Sync", | |
| [evaluate](fiber): Primitive | Yield { | |
| const value = this[args]() | |
| const cont = fiber.getCont(contA) | |
| return cont ? cont[contA](value, fiber) : fiber.yieldWith(exitSucceed(value)) | |
| } | |
| }) | |
| /** @internal */ | |
| export const suspend: <A, E, R>( | |
| evaluate: LazyArg<Effect.Effect<A, E, R>> | |
| ) => Effect.Effect<A, E, R> = makePrimitive({ | |
| op: "Suspend", | |
| [evaluate](_fiber) { | |
| return this[args]() | |
| } | |
| }) | |
| /** @internal */ | |
| export const fromOption: <A>(option: Option.Option<A>) => Effect.Effect<A, Cause.NoSuchElementError> = Option.match({ | |
| onNone: () => fail(new NoSuchElementError("Effect.fromOption: Option.none")), | |
| onSome: succeed | |
| }) | |
| /** @internal */ | |
| export const fromResult: <A, E>(result: Result.Result<A, E>) => Effect.Effect<A, E> = Result.match({ | |
| onFailure: fail, | |
| onSuccess: succeed | |
| }) | |
| /** @internal */ | |
| export const fromNullishOr = <A>(value: A): Effect.Effect<NonNullable<A>, Cause.NoSuchElementError> => | |
| value == null ? fail(new NoSuchElementError()) : succeed(value) | |
| /** @internal */ | |
| export const yieldNowWith: (priority?: number) => Effect.Effect<void> = makePrimitive({ | |
| op: "Yield", | |
| [evaluate](fiber) { | |
| let resumed = false | |
| fiber.currentDispatcher.scheduleTask(() => { | |
| if (resumed) return | |
| fiber.evaluate(exitVoid as any) | |
| }, this[args] ?? 0) | |
| return fiber.yieldWith(() => { | |
| resumed = true | |
| }) | |
| } | |
| }) | |
| /** @internal */ | |
| export const yieldNow: Effect.Effect<void> = yieldNowWith(0) | |
| /** @internal */ | |
| export const succeedSome = <A>(a: A): Effect.Effect<Option.Option<A>> => succeed(Option.some(a)) | |
| /** @internal */ | |
| export const succeedNone: Effect.Effect<Option.Option<never>> = succeed( | |
| Option.none() | |
| ) | |
| /** @internal */ | |
| export const failCauseSync = <E>( | |
| evaluate: LazyArg<Cause.Cause<E>> | |
| ): Effect.Effect<never, E> => suspend(() => failCause(internalCall(evaluate))) | |
| /** @internal */ | |
| export const die = (defect: unknown): Effect.Effect<never> => exitDie(defect) | |
| /** @internal */ | |
| export const failSync = <E>(error: LazyArg<E>): Effect.Effect<never, E> => suspend(() => fail(internalCall(error))) | |
| /** @internal */ | |
| const void_: Effect.Effect<void> = succeed(void 0) | |
| /** @internal */ | |
| export { void_ as void } | |
| /** @internal */ | |
| const try_ = <A, E>(options: { | |
| try: LazyArg<A> | |
| catch: (error: unknown) => E | |
| }): Effect.Effect<A, E> => | |
| suspend(() => { | |
| try { | |
| return succeed(internalCall(options.try)) | |
| } catch (err) { | |
| return fail(internalCall(() => options.catch(err))) | |
| } | |
| }) | |
| /** @internal */ | |
| export { try_ as try } | |
| /** @internal */ | |
| export const promise = <A>( | |
| evaluate: (signal: AbortSignal) => PromiseLike<A> | |
| ): Effect.Effect<A> => | |
| callbackOptions<A>(function(resume, signal) { | |
| internalCall(() => evaluate(signal!)).then( | |
| (a) => resume(succeed(a)), | |
| (e) => resume(die(e)) | |
| ) | |
| }, evaluate.length !== 0) | |
| /** @internal */ | |
| export const tryPromise = <A, E = Cause.UnknownError>( | |
| options: { | |
| readonly try: (signal: AbortSignal) => PromiseLike<A> | |
| readonly catch: (error: unknown) => E | |
| } | ((signal: AbortSignal) => PromiseLike<A>) | |
| ): Effect.Effect<A, E> => { | |
| const f = typeof options === "function" ? options : options.try | |
| const catcher = typeof options === "function" | |
| ? ((cause: unknown) => new UnknownError(cause, "An error occurred in Effect.tryPromise")) | |
| : options.catch | |
| return callbackOptions<A, E>(function(resume, signal) { | |
| try { | |
| internalCall(() => f(signal!)).then( | |
| (a) => resume(succeed(a)), | |
| (e) => resume(fail(internalCall(() => catcher(e)) as E)) | |
| ) | |
| } catch (err) { | |
| resume(fail(internalCall(() => catcher(err)) as E)) | |
| } | |
| }, eval.length !== 0) | |
| } | |
| /** @internal */ | |
| export const withFiberId = <A, E, R>( | |
| f: (fiberId: number) => Effect.Effect<A, E, R> | |
| ): Effect.Effect<A, E, R> => withFiber((fiber) => f(fiber.id)) | |
| /** @internal */ | |
| export const fiber = withFiber(succeed) | |
| /** @internal */ | |
| export const fiberId = withFiberId(succeed) | |
| const callbackOptions: <A, E = never, R = never>( | |
| register: ( | |
| this: Scheduler.Scheduler, | |
| resume: (effect: Effect.Effect<A, E, R>) => void, | |
| signal?: AbortSignal | |
| ) => void | Effect.Effect<void, never, R>, | |
| withSignal: boolean | |
| ) => Effect.Effect<A, E, R> = makePrimitive({ | |
| op: "Async", | |
| single: false, | |
| [evaluate](fiber) { | |
| const register = internalCall(() => this[args][0].bind(fiber.currentScheduler)) | |
| let resumed = false | |
| let yielded: boolean | Primitive = false | |
| const controller = this[args][1] ? new AbortController() : undefined | |
| const onCancel = register((effect) => { | |
| if (resumed) return | |
| resumed = true | |
| if (yielded) { | |
| fiber.evaluate(effect as any) | |
| } else { | |
| yielded = effect as any | |
| } | |
| }, controller?.signal) | |
| if (yielded !== false) return yielded | |
| yielded = true | |
| fiber._yielded = () => { | |
| resumed = true | |
| } | |
| if (controller === undefined && onCancel === undefined) { | |
| return Yield | |
| } | |
| fiber._stack.push( | |
| asyncFinalizer(() => { | |
| resumed = true | |
| controller?.abort() | |
| return onCancel ?? exitVoid | |
| }) | |
| ) | |
| return Yield | |
| } | |
| }) | |
| const asyncFinalizer: ( | |
| onInterrupt: () => Effect.Effect<void, any, any> | |
| ) => Primitive = makePrimitive({ | |
| op: "AsyncFinalizer", | |
| [contAll](fiber) { | |
| if (fiber.interruptible) { | |
| fiber.interruptible = false | |
| fiber._stack.push(setInterruptibleTrue) | |
| } | |
| }, | |
| [contE](cause, _fiber) { | |
| return hasInterrupts(cause) | |
| ? flatMap(this[args](), () => failCause(cause)) | |
| : failCause(cause) | |
| } | |
| }) | |
| /** @internal */ | |
| export const callback = <A, E = never, R = never>( | |
| register: ( | |
| this: Scheduler.Scheduler, | |
| resume: (effect: Effect.Effect<A, E, R>) => void, | |
| signal: AbortSignal | |
| ) => void | Effect.Effect<void, never, R> | |
| ): Effect.Effect<A, E, R> => callbackOptions(register as any, register.length >= 2) | |
| /** @internal */ | |
| export const never: Effect.Effect<never> = callback<never>(constVoid) | |
| /** @internal */ | |
| export const gen = < | |
| Self, | |
| Eff extends Effect.Effect<any, any, any>, | |
| AEff | |
| >( | |
| ...args: | |
| | [options: { readonly self: Self }, body: (this: Self) => Generator<Eff, AEff, never>] | |
| | [body: () => Generator<Eff, AEff, never>] | |
| ): Effect.Effect< | |
| AEff, | |
| [Eff] extends [never] ? never | |
| : [Eff] extends [Effect.Effect<infer _A, infer E, infer _R>] ? E | |
| : never, | |
| [Eff] extends [never] ? never | |
| : [Eff] extends [Effect.Effect<infer _A, infer _E, infer R>] ? R | |
| : never | |
| > => | |
| suspend(() => | |
| fromIteratorUnsafe( | |
| args.length === 1 ? args[0]() : (args[1].call(args[0].self) as any) | |
| ) | |
| ) | |
| /** @internal */ | |
| export const fnUntraced: Effect.fn.Untraced = ( | |
| body: Function, | |
| ...pipeables: Array<any> | |
| ) => { | |
| const fn = pipeables.length === 0 | |
| ? function(this: any) { | |
| return suspend(() => fromIteratorUnsafe(body.apply(this, arguments))) | |
| } | |
| : function(this: any) { | |
| let effect = suspend(() => fromIteratorUnsafe(body.apply(this, arguments))) | |
| for (let i = 0; i < pipeables.length; i++) { | |
| effect = pipeables[i](effect, ...arguments) | |
| } | |
| return effect | |
| } | |
| return defineFunctionLength(body.length, fn) | |
| } | |
| const defineFunctionLength = <F extends Function>(length: number, fn: F): F => | |
| Object.defineProperty(fn, "length", { | |
| value: length, | |
| configurable: true | |
| }) | |
| const fnStackCleaner = makeStackCleaner(2) | |
| /** @internal */ | |
| export const fn: typeof Effect.fn = function() { | |
| const nameFirst = typeof arguments[0] === "string" | |
| const name = nameFirst ? arguments[0] : "Effect.fn" | |
| const spanOptions = nameFirst ? arguments[1] : undefined | |
| const prevLimit = globalThis.Error.stackTraceLimit | |
| globalThis.Error.stackTraceLimit = 2 | |
| const defError = new globalThis.Error() | |
| globalThis.Error.stackTraceLimit = prevLimit | |
| if (nameFirst) { | |
| return (body: Function | { readonly self: any }, ...pipeables: Array<Function>) => | |
| makeFn(name, body, defError, pipeables, nameFirst, spanOptions) | |
| } | |
| return makeFn( | |
| name, | |
| arguments[0], | |
| defError, | |
| Array.prototype.slice.call(arguments, 1), | |
| nameFirst, | |
| spanOptions | |
| ) | |
| } as any | |
| const makeFn = ( | |
| name: string, | |
| bodyOrOptions: Function | { readonly self: any }, | |
| defError: Error, | |
| pipeables: Array<Function>, | |
| addSpan: boolean, | |
| spanOptions: Tracer.SpanOptionsNoTrace | undefined | |
| ) => { | |
| const body = typeof bodyOrOptions === "function" | |
| ? bodyOrOptions | |
| : (pipeables.pop()!).bind(bodyOrOptions.self) | |
| return defineFunctionLength(body.length, function(this: any, ...args: Array<any>) { | |
| let result = suspend(() => { | |
| const iter = body.apply(this, arguments) | |
| return isEffect(iter) ? iter : fromIteratorUnsafe(iter) | |
| }) | |
| for (let i = 0; i < pipeables.length; i++) { | |
| result = pipeables[i](result, ...args) | |
| } | |
| if (!isEffect(result)) { | |
| return result | |
| } | |
| const prevLimit = globalThis.Error.stackTraceLimit | |
| globalThis.Error.stackTraceLimit = 2 | |
| const callError = new globalThis.Error() | |
| globalThis.Error.stackTraceLimit = prevLimit | |
| return updateService( | |
| addSpan ? | |
| useSpan(name, spanOptions!, (span) => provideParentSpan(result, span)) : | |
| result, | |
| CurrentStackFrame, | |
| (prev) => ({ | |
| name, | |
| stack: fnStackCleaner(() => callError.stack), | |
| parent: { | |
| name: `${name} (definition)`, | |
| stack: fnStackCleaner(() => defError.stack), | |
| parent: prev | |
| } | |
| }) | |
| ) | |
| }) | |
| } | |
| /** @internal */ | |
| export const fnUntracedEager: Effect.fn.Untraced = ( | |
| body: Function, | |
| ...pipeables: Array<any> | |
| ) => | |
| defineFunctionLength( | |
| body.length, | |
| pipeables.length === 0 | |
| ? function(this: any) { | |
| return fromIteratorEagerUnsafe(() => body.apply(this, arguments)) | |
| } | |
| : function(this: any) { | |
| let effect = fromIteratorEagerUnsafe(() => body.apply(this, arguments)) | |
| for (const pipeable of pipeables) { | |
| effect = pipeable(effect) | |
| } | |
| return effect | |
| } | |
| ) | |
| const fromIteratorEagerUnsafe = ( | |
| evaluate: () => Iterator<Effect.Effect<any, any, any>> | |
| ): Effect.Effect<any, any, any> => { | |
| try { | |
| const iterator = evaluate() | |
| let value: any = undefined | |
| // Try to resolve synchronously in a loop | |
| while (true) { | |
| const state = iterator.next(value) | |
| if (state.done) { | |
| return succeed(state.value) | |
| } | |
| const primitive = state.value as any | |
| if (primitive && primitive._tag === "Success") { | |
| value = primitive.value | |
| continue | |
| } else if (primitive && primitive._tag === "Failure") { | |
| return state.value | |
| } else { | |
| let isFirstExecution = true | |
| return suspend(() => { | |
| if (isFirstExecution) { | |
| isFirstExecution = false | |
| return flatMap(state.value, (value) => fromIteratorUnsafe(iterator, value)) | |
| } else { | |
| return suspend(() => fromIteratorUnsafe(evaluate())) | |
| } | |
| }) | |
| } | |
| } | |
| } catch (error) { | |
| return die(error) | |
| } | |
| } | |
| const fromIteratorUnsafe: ( | |
| iterator: Iterator<Effect.Effect<any, any, any>>, | |
| initial?: undefined | |
| ) => Effect.Effect<any, any, any> = makePrimitive({ | |
| op: "Iterator", | |
| single: false, | |
| [contA](value, fiber) { | |
| const iter = this[args][0] | |
| while (true) { | |
| const state = iter.next(value) | |
| if (state.done) return succeed(state.value) | |
| if (!effectIsExit(state.value)) { | |
| fiber._stack.push(this) | |
| return state.value | |
| } else if (state.value._tag === "Failure") { | |
| return state.value | |
| } | |
| value = state.value.value | |
| } | |
| }, | |
| [evaluate](this: any, fiber: FiberImpl) { | |
| return this[contA](this[args][1], fiber) | |
| } | |
| }) | |
| // ---------------------------------------------------------------------------- | |
| // mapping & sequencing | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const as: { | |
| <A, B>( | |
| value: B | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E, R> | |
| <A, E, R, B>(self: Effect.Effect<A, E, R>, value: B): Effect.Effect<B, E, R> | |
| } = dual( | |
| 2, | |
| <A, E, R, B>( | |
| self: Effect.Effect<A, E, R>, | |
| value: B | |
| ): Effect.Effect<B, E, R> => { | |
| const b = succeed(value) | |
| return flatMap(self, (_) => b) | |
| } | |
| ) | |
| /** @internal */ | |
| export const asSome = <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ): Effect.Effect<Option.Option<A>, E, R> => map(self, Option.some) | |
| /** @internal */ | |
| export const flip = <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ): Effect.Effect<E, A, R> => | |
| matchEffect(self, { | |
| onFailure: succeed, | |
| onSuccess: fail | |
| }) | |
| /** @internal */ | |
| export const andThen: { | |
| <A, B, E2, R2>( | |
| f: (a: A) => Effect.Effect<B, E2, R2> | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E | E2, R | R2> | |
| <B, E2, R2>( | |
| f: Effect.Effect<B, E2, R2> | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E | E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (a: A) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<B, E | E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<B, E | E2, R | R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: ((a: A) => Effect.Effect<B, E2, R2>) | Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<B, E | E2, R | R2> => | |
| flatMap(self, (a) => isEffect(f) ? f : internalCall(() => (f as (a: A) => Effect.Effect<B, E2, R2>)(a))) | |
| ) | |
| /** @internal */ | |
| export const tap: { | |
| <A, B, E2, R2>( | |
| f: (a: NoInfer<A>) => Effect.Effect<B, E2, R2> | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2> | |
| <B, E2, R2>( | |
| f: Effect.Effect<B, E2, R2> | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (a: NoInfer<A>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: ((a: A) => Effect.Effect<B, E2, R2>) | Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> => | |
| flatMap(self, (a) => as(isEffect(f) ? f : internalCall(() => (f as (a: A) => Effect.Effect<B, E2, R2>)(a)), a)) | |
| ) | |
| /** @internal */ | |
| export const asVoid = <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ): Effect.Effect<void, E, R> => flatMap(self, (_) => exitVoid) | |
| /** @internal */ | |
| export const sandbox = <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ): Effect.Effect<A, Cause.Cause<E>, R> => catchCause(self, fail) | |
| /** @internal */ | |
| export const raceAll = <Eff extends Effect.Effect<any, any, any>>( | |
| all: Iterable<Eff>, | |
| options?: { | |
| readonly onWinner?: (options: { | |
| readonly fiber: Fiber.Fiber<any, any> | |
| readonly index: number | |
| readonly parentFiber: Fiber.Fiber<any, any> | |
| }) => void | |
| } | |
| ): Effect.Effect< | |
| Effect.Success<Eff>, | |
| Effect.Error<Eff>, | |
| Effect.Services<Eff> | |
| > => | |
| withFiber((parent) => | |
| callback((resume) => { | |
| const effects = Arr.fromIterable(all) | |
| const len = effects.length | |
| let doneCount = 0 | |
| let done = false | |
| const fibers = new Set<Fiber.Fiber<any, any>>() | |
| const failures: Array<Cause.Reason<any>> = [] | |
| const onExit = (exit: Exit.Exit<any, any>, fiber: Fiber.Fiber<any, any>, i: number) => { | |
| doneCount++ | |
| if (exit._tag === "Failure") { | |
| failures.push(...exit.cause.reasons) | |
| if (doneCount >= len) { | |
| resume(failCause(causeFromReasons(failures))) | |
| } | |
| return | |
| } | |
| const isWinner = !done | |
| done = true | |
| resume( | |
| fibers.size === 0 | |
| ? exit | |
| : flatMap(uninterruptible(fiberInterruptAll(fibers)), () => exit) | |
| ) | |
| if (isWinner && options?.onWinner) { | |
| options.onWinner({ fiber, index: i, parentFiber: parent }) | |
| } | |
| } | |
| for (let i = 0; i < len; i++) { | |
| const fiber = forkUnsafe(parent, effects[i], true, true, false) | |
| fibers.add(fiber) | |
| fiber.addObserver((exit) => { | |
| fibers.delete(fiber) | |
| onExit(exit, fiber, i) | |
| }) | |
| if (done) break | |
| } | |
| return fiberInterruptAll(fibers) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const raceAllFirst = <Eff extends Effect.Effect<any, any, any>>( | |
| all: Iterable<Eff>, | |
| options?: { | |
| readonly onWinner?: (options: { | |
| readonly fiber: Fiber.Fiber<any, any> | |
| readonly index: number | |
| readonly parentFiber: Fiber.Fiber<any, any> | |
| }) => void | |
| } | |
| ): Effect.Effect< | |
| Effect.Success<Eff>, | |
| Effect.Error<Eff>, | |
| Effect.Services<Eff> | |
| > => | |
| withFiber((parent) => | |
| callback((resume) => { | |
| let done = false | |
| const fibers = new Set<Fiber.Fiber<any, any>>() | |
| const onExit = (exit: Exit.Exit<any, any>) => { | |
| done = true | |
| resume( | |
| fibers.size === 0 | |
| ? exit | |
| : flatMap(uninterruptible(fiberInterruptAll(fibers)), () => exit) | |
| ) | |
| } | |
| let i = 0 | |
| for (const effect of all) { | |
| if (done) break | |
| const index = i++ | |
| const fiber = forkUnsafe(parent, effect, true, true, false) | |
| fibers.add(fiber) | |
| fiber.addObserver((exit) => { | |
| fibers.delete(fiber) | |
| const isWinner = !done | |
| onExit(exit) | |
| if (isWinner && options?.onWinner) { | |
| options.onWinner({ fiber, index, parentFiber: parent }) | |
| } | |
| }) | |
| } | |
| return fiberInterruptAll(fibers) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const race: { | |
| <A2, E2, R2>( | |
| that: Effect.Effect<A2, E2, R2>, | |
| options?: { | |
| readonly onWinner?: (options: { | |
| readonly fiber: Fiber.Fiber<any, any> | |
| readonly index: number | |
| readonly parentFiber: Fiber.Fiber<any, any> | |
| }) => void | |
| } | |
| ): <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A | A2, E | E2, R | R2> | |
| <A, E, R, A2, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| that: Effect.Effect<A2, E2, R2>, | |
| options?: { | |
| readonly onWinner?: (options: { | |
| readonly fiber: Fiber.Fiber<any, any> | |
| readonly index: number | |
| readonly parentFiber: Fiber.Fiber<any, any> | |
| }) => void | |
| } | |
| ): Effect.Effect<A | A2, E | E2, R | R2> | |
| } = dual( | |
| (args) => isEffect(args[1]), | |
| <A, E, R, A2, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| that: Effect.Effect<A2, E2, R2>, | |
| options?: { | |
| readonly onWinner?: (options: { | |
| readonly fiber: Fiber.Fiber<any, any> | |
| readonly index: number | |
| readonly parentFiber: Fiber.Fiber<any, any> | |
| }) => void | |
| } | |
| ): Effect.Effect<A | A2, E | E2, R | R2> => raceAll([self, that], options) | |
| ) | |
| /** @internal */ | |
| export const raceFirst: { | |
| <A2, E2, R2>( | |
| that: Effect.Effect<A2, E2, R2>, | |
| options?: { | |
| readonly onWinner?: (options: { | |
| readonly fiber: Fiber.Fiber<any, any> | |
| readonly index: number | |
| readonly parentFiber: Fiber.Fiber<any, any> | |
| }) => void | |
| } | |
| ): <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A | A2, E | E2, R | R2> | |
| <A, E, R, A2, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| that: Effect.Effect<A2, E2, R2>, | |
| options?: { | |
| readonly onWinner?: (options: { | |
| readonly fiber: Fiber.Fiber<any, any> | |
| readonly index: number | |
| readonly parentFiber: Fiber.Fiber<any, any> | |
| }) => void | |
| } | |
| ): Effect.Effect<A | A2, E | E2, R | R2> | |
| } = dual( | |
| (args) => isEffect(args[1]), | |
| <A, E, R, A2, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| that: Effect.Effect<A2, E2, R2>, | |
| options?: { | |
| readonly onWinner?: (options: { | |
| readonly fiber: Fiber.Fiber<any, any> | |
| readonly index: number | |
| readonly parentFiber: Fiber.Fiber<any, any> | |
| }) => void | |
| } | |
| ): Effect.Effect<A | A2, E | E2, R | R2> => raceAllFirst([self, that], options) | |
| ) | |
| /** @internal */ | |
| export const flatMap: { | |
| <A, B, E2, R2>( | |
| f: (a: A) => Effect.Effect<B, E2, R2> | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E | E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (a: A) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<B, E | E2, R | R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (a: A) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<B, E | E2, R | R2> => { | |
| const onSuccess = Object.create(OnSuccessProto) | |
| onSuccess[args] = self | |
| onSuccess[contA] = f.length !== 1 ? (a: A) => f(a) : f | |
| return onSuccess | |
| } | |
| ) | |
| const OnSuccessProto = makePrimitiveProto({ | |
| op: "OnSuccess", | |
| [evaluate](this: any, fiber: FiberImpl): Primitive { | |
| fiber._stack.push(this) | |
| return this[args] | |
| } | |
| }) | |
| /** @internal */ | |
| export const matchCauseEffectEager: { | |
| <E, A2, E2, R2, A, A3, E3, R3>(options: { | |
| readonly onFailure: (cause: Cause.Cause<E>) => Effect.Effect<A2, E2, R2> | |
| readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3> | |
| }): <R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R> | |
| <A, E, R, A2, E2, R2, A3, E3, R3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (cause: Cause.Cause<E>) => Effect.Effect<A2, E2, R2> | |
| readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3> | |
| } | |
| ): Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R> | |
| } = dual( | |
| 2, | |
| <A, E, R, A2, E2, R2, A3, E3, R3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (cause: Cause.Cause<E>) => Effect.Effect<A2, E2, R2> | |
| readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3> | |
| } | |
| ): Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R> => { | |
| if (effectIsExit(self)) { | |
| return self._tag === "Success" | |
| ? options.onSuccess(self.value) | |
| : options.onFailure(self.cause) | |
| } | |
| return matchCauseEffect(self, options) | |
| } | |
| ) | |
| /** @internal */ | |
| export const effectIsExit = <A, E, R>(effect: Effect.Effect<A, E, R>): effect is Exit.Exit<A, E> => ExitTypeId in effect | |
| /** @internal */ | |
| export const flatMapEager: { | |
| <A, B, E2, R2>( | |
| f: (a: A) => Effect.Effect<B, E2, R2> | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E | E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (a: A) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<B, E | E2, R | R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (a: A) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<B, E | E2, R | R2> => { | |
| if (effectIsExit(self)) { | |
| return self._tag === "Success" ? f(self.value) : self as Exit.Exit<never, E> | |
| } | |
| return flatMap(self, f) | |
| } | |
| ) | |
| // ---------------------------------------------------------------------------- | |
| // mapping & sequencing | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const flatten = <A, E, R, E2, R2>( | |
| self: Effect.Effect<Effect.Effect<A, E, R>, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> => flatMap(self, identity) | |
| /** @internal */ | |
| export const map: { | |
| <A, B>( | |
| f: (a: A) => B | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E, R> | |
| <A, E, R, B>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (a: A) => B | |
| ): Effect.Effect<B, E, R> | |
| } = dual( | |
| 2, | |
| <A, E, R, B>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (a: A) => B | |
| ): Effect.Effect<B, E, R> => flatMap(self, (a) => succeed(internalCall(() => f(a)))) | |
| ) | |
| /** @internal */ | |
| export const mapEager: { | |
| <A, B>( | |
| f: (a: A) => B | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E, R> | |
| <A, E, R, B>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (a: A) => B | |
| ): Effect.Effect<B, E, R> | |
| } = dual( | |
| 2, | |
| <A, E, R, B>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (a: A) => B | |
| ): Effect.Effect<B, E, R> => effectIsExit(self) ? exitMap(self, f) : map(self, f) | |
| ) | |
| /** @internal */ | |
| export const mapErrorEager: { | |
| <E, E2>( | |
| f: (e: E) => E2 | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E2, R> | |
| <A, E, R, E2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (e: E) => E2 | |
| ): Effect.Effect<A, E2, R> | |
| } = dual( | |
| 2, | |
| <A, E, R, E2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (e: E) => E2 | |
| ): Effect.Effect<A, E2, R> => effectIsExit(self) ? exitMapError(self, f) : mapError(self, f) | |
| ) | |
| /** @internal */ | |
| export const mapBothEager: { | |
| <E, E2, A, A2>( | |
| options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } | |
| ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A2, E2, R> | |
| <A, E, R, E2, A2>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } | |
| ): Effect.Effect<A2, E2, R> | |
| } = dual( | |
| 2, | |
| <A, E, R, E2, A2>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } | |
| ): Effect.Effect<A2, E2, R> => effectIsExit(self) ? exitMapBoth(self, options) : mapBoth(self, options) | |
| ) | |
| /** @internal */ | |
| export const catchEager: { | |
| <E, B, E2, R2>( | |
| f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2> | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A | B, E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A | B, E2, R | R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A | B, E2, R | R2> => { | |
| if (effectIsExit(self)) { | |
| if (self._tag === "Success") return self as Exit.Exit<A> | |
| const error = findError(self.cause) | |
| if (Result.isFailure(error)) return self as Exit.Exit<never> | |
| return f(error.success) | |
| } | |
| return catch_(self, f) | |
| } | |
| ) | |
| // ---------------------------------------------------------------------------- | |
| // Exit | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const exitInterrupt = (fiberId?: number | undefined): Exit.Exit<never> => exitFailCause(causeInterrupt(fiberId)) | |
| /** @internal */ | |
| export const exitIsSuccess = <A, E>( | |
| self: Exit.Exit<A, E> | |
| ): self is Exit.Success<A, E> => self._tag === "Success" | |
| /** @internal */ | |
| export const exitFilterSuccess = <A, E>( | |
| self: Exit.Exit<A, E> | |
| ): Result.Result<Exit.Success<A>, Exit.Failure<never, E>> => | |
| self._tag === "Success" ? Result.succeed(self as any) : Result.fail(self as any) | |
| /** @internal */ | |
| export const exitFilterValue = <A, E>( | |
| self: Exit.Exit<A, E> | |
| ): Result.Result<A, Exit.Failure<never, E>> => | |
| self._tag === "Success" ? Result.succeed(self.value) : Result.fail(self as any) | |
| /** @internal */ | |
| export const exitIsFailure = <A, E>( | |
| self: Exit.Exit<A, E> | |
| ): self is Exit.Failure<A, E> => self._tag === "Failure" | |
| /** @internal */ | |
| export const exitFilterFailure = <A, E>( | |
| self: Exit.Exit<A, E> | |
| ): Result.Result<Exit.Failure<never, E>, Exit.Success<A>> => | |
| self._tag === "Failure" ? Result.succeed(self as any) : Result.fail(self as any) | |
| /** @internal */ | |
| export const exitFilterCause = <A, E>( | |
| self: Exit.Exit<A, E> | |
| ): Result.Result<Cause.Cause<E>, Exit.Success<A>> => | |
| self._tag === "Failure" ? Result.succeed(self.cause) : Result.fail(self as any) | |
| /** @internal */ | |
| export const exitFindError = Filter.composePassthrough( | |
| exitFilterCause, | |
| findError | |
| ) | |
| /** @internal */ | |
| export const exitFindDefect = Filter.composePassthrough( | |
| exitFilterCause, | |
| findDefect | |
| ) | |
| /** @internal */ | |
| export const exitHasInterrupts = <A, E>( | |
| self: Exit.Exit<A, E> | |
| ): self is Exit.Failure<A, E> => self._tag === "Failure" && hasInterrupts(self.cause) | |
| /** @internal */ | |
| export const exitHasDies = <A, E>( | |
| self: Exit.Exit<A, E> | |
| ): self is Exit.Failure<A, E> => self._tag === "Failure" && hasDies(self.cause) | |
| /** @internal */ | |
| export const exitHasFails = <A, E>( | |
| self: Exit.Exit<A, E> | |
| ): self is Exit.Failure<A, E> => self._tag === "Failure" && hasFails(self.cause) | |
| /** @internal */ | |
| export const exitVoid: Exit.Exit<void> = exitSucceed(void 0) | |
| /** @internal */ | |
| export const exitMap: { | |
| <A, B>(f: (a: A) => B): <E>(self: Exit.Exit<A, E>) => Exit.Exit<B, E> | |
| <A, E, B>(self: Exit.Exit<A, E>, f: (a: A) => B): Exit.Exit<B, E> | |
| } = dual( | |
| 2, | |
| <A, E, B>(self: Exit.Exit<A, E>, f: (a: A) => B): Exit.Exit<B, E> => | |
| self._tag === "Success" ? exitSucceed(f(self.value)) : (self as any) | |
| ) | |
| /** @internal */ | |
| export const exitMapError: { | |
| <E, E2>(f: (a: NoInfer<E>) => E2): <A>(self: Exit.Exit<A, E>) => Exit.Exit<A, E2> | |
| <A, E, E2>(self: Exit.Exit<A, E>, f: (a: NoInfer<E>) => E2): Exit.Exit<A, E2> | |
| } = dual( | |
| 2, | |
| <A, E, E2>(self: Exit.Exit<A, E>, f: (a: NoInfer<E>) => E2): Exit.Exit<A, E2> => { | |
| if (self._tag === "Success") return self as Exit.Exit<A> | |
| const error = findError(self.cause) | |
| if (Result.isFailure(error)) return self as Exit.Exit<never> | |
| return exitFail(f(error.success)) | |
| } | |
| ) | |
| /** @internal */ | |
| export const exitMapBoth: { | |
| <E, E2, A, A2>( | |
| options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } | |
| ): (self: Exit.Exit<A, E>) => Exit.Exit<A2, E2> | |
| <A, E, E2, A2>( | |
| self: Exit.Exit<A, E>, | |
| options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } | |
| ): Exit.Exit<A2, E2> | |
| } = dual( | |
| 2, | |
| <A, E, E2, A2>( | |
| self: Exit.Exit<A, E>, | |
| options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } | |
| ): Exit.Exit<A2, E2> => { | |
| if (self._tag === "Success") return exitSucceed(options.onSuccess(self.value)) | |
| const error = findError(self.cause) | |
| if (Result.isFailure(error)) return self as Exit.Exit<never> | |
| return exitFail(options.onFailure(error.success)) | |
| } | |
| ) | |
| /** @internal */ | |
| export const exitAs: { | |
| <B>(b: B): <A, E>(self: Exit.Exit<A, E>) => Exit.Exit<B, E> | |
| <A, E, B>(self: Exit.Exit<A, E>, b: B): Exit.Exit<B, E> | |
| } = dual( | |
| 2, | |
| <A, E, B>(self: Exit.Exit<A, E>, b: B): Exit.Exit<B, E> => exitIsSuccess(self) ? exitSucceed(b) : (self as any) | |
| ) | |
| /** @internal */ | |
| export const exitZipRight: { | |
| <A2, E2>( | |
| that: Exit.Exit<A2, E2> | |
| ): <A, E>(self: Exit.Exit<A, E>) => Exit.Exit<A2, E | E2> | |
| <A, E, A2, E2>( | |
| self: Exit.Exit<A, E>, | |
| that: Exit.Exit<A2, E2> | |
| ): Exit.Exit<A2, E | E2> | |
| } = dual( | |
| 2, | |
| <A, E, A2, E2>( | |
| self: Exit.Exit<A, E>, | |
| that: Exit.Exit<A2, E2> | |
| ): Exit.Exit<A2, E | E2> => (exitIsSuccess(self) ? that : (self as any)) | |
| ) | |
| /** @internal */ | |
| export const exitMatch: { | |
| <A, E, X1, X2>(options: { | |
| readonly onSuccess: (a: NoInfer<A>) => X1 | |
| readonly onFailure: (cause: Cause.Cause<NoInfer<E>>) => X2 | |
| }): (self: Exit.Exit<A, E>) => X1 | X2 | |
| <A, E, X1, X2>( | |
| self: Exit.Exit<A, E>, | |
| options: { | |
| readonly onSuccess: (a: A) => X1 | |
| readonly onFailure: (cause: Cause.Cause<E>) => X2 | |
| } | |
| ): X1 | X2 | |
| } = dual( | |
| 2, | |
| <A, E, X1, X2>( | |
| self: Exit.Exit<A, E>, | |
| options: { | |
| readonly onSuccess: (a: A) => X1 | |
| readonly onFailure: (cause: Cause.Cause<E>) => X2 | |
| } | |
| ): X1 | X2 => | |
| exitIsSuccess(self) | |
| ? options.onSuccess(self.value) | |
| : options.onFailure(self.cause) | |
| ) | |
| /** @internal */ | |
| export const exitAsVoid: <A, E>(self: Exit.Exit<A, E>) => Exit.Exit<void, E> = exitAs(void 0) | |
| /** @internal */ | |
| export const exitAsVoidAll = <I extends Iterable<Exit.Exit<any, any>>>( | |
| exits: I | |
| ): Exit.Exit< | |
| void, | |
| I extends Iterable<Exit.Exit<infer _A, infer _E>> ? _E : never | |
| > => { | |
| const failures: Array<Cause.Reason<any>> = [] | |
| for (const exit of exits) { | |
| if (exit._tag === "Failure") { | |
| failures.push(...exit.cause.reasons) | |
| } | |
| } | |
| return failures.length === 0 ? exitVoid : exitFailCause(causeFromReasons(failures)) | |
| } | |
| /** @internal */ | |
| export const exitGetSuccess = <A, E>(self: Exit.Exit<A, E>): Option.Option<A> => | |
| exitIsSuccess(self) ? Option.some(self.value) : Option.none() | |
| /** @internal */ | |
| export const exitGetCause = <A, E>(self: Exit.Exit<A, E>): Option.Option<Cause.Cause<E>> => | |
| exitIsFailure(self) ? Option.some(self.cause) : Option.none() | |
| /** @internal */ | |
| export const exitFindErrorOption = <A, E>(self: Exit.Exit<A, E>): Option.Option<E> => { | |
| const error = exitFindError(self) | |
| return Result.isFailure(error) ? Option.none() : Option.some(error.success) | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // environment | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const service = <I, S>(service: Context.Key<I, S>): Effect.Effect<S, never, I> => service | |
| /** @internal */ | |
| export const serviceOption = <I, S>( | |
| service: Context.Key<I, S> | |
| ): Effect.Effect<Option.Option<S>> => withFiber((fiber) => succeed(Context.getOption(fiber.context, service))) | |
| /** @internal */ | |
| export const serviceOptional = <I, S>( | |
| service: Context.Key<I, S> | |
| ): Effect.Effect<S, Cause.NoSuchElementError> => | |
| withFiber((fiber) => | |
| fiber.context.mapUnsafe.has(service.key) | |
| ? succeed(Context.getUnsafe(fiber.context, service)) | |
| : fail(new NoSuchElementError()) | |
| ) | |
| /** @internal */ | |
| export const updateContext: { | |
| <R2, R>( | |
| f: (context: Context.Context<R2>) => Context.Context<NoInfer<R>> | |
| ): <A, E>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R2> | |
| <A, E, R, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (context: Context.Context<R2>) => Context.Context<NoInfer<R>> | |
| ): Effect.Effect<A, E, R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (context: Context.Context<R2>) => Context.Context<NoInfer<R>> | |
| ): Effect.Effect<A, E, R2> => | |
| withFiber<A, E, R2>((fiber) => { | |
| const prevContext = fiber.context as Context.Context<R2> | |
| const nextContext = f(prevContext) | |
| if (prevContext === nextContext) return self as any | |
| fiber.setContext(nextContext) | |
| return onExitPrimitive(self, () => { | |
| fiber.setContext(prevContext) | |
| return undefined | |
| }) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const updateService: { | |
| <I, A>( | |
| service: Context.Key<I, A>, | |
| f: (value: A) => A | |
| ): <XA, E, R>(self: Effect.Effect<XA, E, R>) => Effect.Effect<XA, E, R | I> | |
| <XA, E, R, I, A>( | |
| self: Effect.Effect<XA, E, R>, | |
| service: Context.Key<I, A>, | |
| f: (value: A) => A | |
| ): Effect.Effect<XA, E, R | I> | |
| } = dual( | |
| 3, | |
| <XA, E, R, I, A>( | |
| self: Effect.Effect<XA, E, R>, | |
| service: Context.Key<I, A>, | |
| f: (value: A) => A | |
| ): Effect.Effect<XA, E, R | I> => | |
| updateContext(self, (s) => { | |
| const prev = Context.getUnsafe(s, service) | |
| const next = f(prev) | |
| if (prev === next) return s | |
| return Context.add(s, service, next) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const context = <R = never>(): Effect.Effect<Context.Context<R>> => getContext as any | |
| const getContext = withFiber((fiber) => succeed(fiber.context)) | |
| /** @internal */ | |
| export const contextWith = <R, A, E, R2>( | |
| f: (context: Context.Context<R>) => Effect.Effect<A, E, R2> | |
| ): Effect.Effect<A, E, R | R2> => withFiber((fiber) => f(fiber.context as Context.Context<R>)) | |
| /** @internal */ | |
| export const provideContext: { | |
| <XR>( | |
| context: Context.Context<XR> | |
| ): <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A, E, Exclude<R, XR>> | |
| <A, E, R, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| context: Context.Context<XR> | |
| ): Effect.Effect<A, E, Exclude<R, XR>> | |
| } = dual( | |
| 2, | |
| <A, E, R, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| context: Context.Context<XR> | |
| ): Effect.Effect<A, E, Exclude<R, XR>> => { | |
| if (effectIsExit(self)) return self as any | |
| return updateContext(self, Context.merge(context)) as any | |
| } | |
| ) | |
| /** @internal */ | |
| export const provideService: { | |
| <I, S>( | |
| service: Context.Key<I, S> | |
| ): { | |
| (implementation: S): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, I>> | |
| <A, E, R>(self: Effect.Effect<A, E, R>, implementation: S): Effect.Effect<A, E, Exclude<R, I>> | |
| } | |
| <I, S>( | |
| key: Context.Key<I, S>, | |
| implementation: S | |
| ): <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A, E, Exclude<R, I>> | |
| <A, E, R, I, S>( | |
| self: Effect.Effect<A, E, R>, | |
| service: Context.Key<I, S>, | |
| implementation: S | |
| ): Effect.Effect<A, E, Exclude<R, I>> | |
| } = function(this: any) { | |
| if (arguments.length === 1) { | |
| return dual(2, (self, impl) => provideServiceImpl(self, arguments[0], impl)) as any | |
| } | |
| return dual(3, (self, service, impl) => provideServiceImpl(self, service, impl)) | |
| .apply(this, arguments as any) as any | |
| } | |
| const provideServiceImpl = <A, E, R, I, S>( | |
| self: Effect.Effect<A, E, R>, | |
| service: Context.Key<I, S>, | |
| implementation: S | |
| ): Effect.Effect<A, E, Exclude<R, I>> => | |
| updateContext(self, (s) => { | |
| const prev = s.mapUnsafe.get(service.key) | |
| if (prev === implementation) return s | |
| return Context.add(s, service, implementation) | |
| }) as any | |
| /** @internal */ | |
| export const provideServiceEffect: { | |
| <I, S, E2, R2>( | |
| service: Context.Key<I, S>, | |
| acquire: Effect.Effect<S, E2, R2> | |
| ): <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A, E | E2, Exclude<R, I> | R2> | |
| <A, E, R, I, S, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| service: Context.Key<I, S>, | |
| acquire: Effect.Effect<S, E2, R2> | |
| ): Effect.Effect<A, E | E2, Exclude<R, I> | R2> | |
| } = dual( | |
| 3, | |
| <A, E, R, I, S, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| service: Context.Key<I, S>, | |
| acquire: Effect.Effect<S, E2, R2> | |
| ): Effect.Effect<A, E | E2, Exclude<R, I> | R2> => | |
| flatMap(acquire, (implementation) => provideService(self, service, implementation)) | |
| ) | |
| /** @internal */ | |
| export const withConcurrency: { | |
| ( | |
| concurrency: "unbounded" | number | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| concurrency: "unbounded" | number | |
| ): Effect.Effect<A, E, R> | |
| } = provideService(CurrentConcurrency) | |
| // ---------------------------------------------------------------------------- | |
| // zipping | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const zip: { | |
| <A2, E2, R2>( | |
| that: Effect.Effect<A2, E2, R2>, | |
| options?: { readonly concurrent?: boolean | undefined } | undefined | |
| ): <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<[A, A2], E2 | E, R2 | R> | |
| <A, E, R, A2, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| that: Effect.Effect<A2, E2, R2>, | |
| options?: { readonly concurrent?: boolean | undefined } | |
| ): Effect.Effect<[A, A2], E | E2, R | R2> | |
| } = dual( | |
| (args) => isEffect(args[1]), | |
| <A, E, R, A2, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| that: Effect.Effect<A2, E2, R2>, | |
| options?: { readonly concurrent?: boolean | undefined } | |
| ): Effect.Effect<[A, A2], E | E2, R | R2> => zipWith(self, that, (a, a2) => [a, a2], options) | |
| ) | |
| /** @internal */ | |
| export const zipWith: { | |
| <A2, E2, R2, A, B>( | |
| that: Effect.Effect<A2, E2, R2>, | |
| f: (a: A, b: A2) => B, | |
| options?: { readonly concurrent?: boolean | undefined } | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E2 | E, R2 | R> | |
| <A, E, R, A2, E2, R2, B>( | |
| self: Effect.Effect<A, E, R>, | |
| that: Effect.Effect<A2, E2, R2>, | |
| f: (a: A, b: A2) => B, | |
| options?: { readonly concurrent?: boolean | undefined } | |
| ): Effect.Effect<B, E2 | E, R2 | R> | |
| } = dual( | |
| (args) => isEffect(args[1]), | |
| <A, E, R, A2, E2, R2, B>( | |
| self: Effect.Effect<A, E, R>, | |
| that: Effect.Effect<A2, E2, R2>, | |
| f: (a: A, b: A2) => B, | |
| options?: { readonly concurrent?: boolean | undefined } | |
| ): Effect.Effect<B, E2 | E, R2 | R> => | |
| options?.concurrent | |
| // Use `all` exclusively for concurrent cases, as it introduces additional overhead due to the management of concurrency | |
| ? map(all([self, that], { concurrency: 2 }), ([a, a2]) => internalCall(() => f(a, a2))) | |
| : flatMap(self, (a) => map(that, (a2) => internalCall(() => f(a, a2)))) | |
| ) | |
| // ---------------------------------------------------------------------------- | |
| // filtering & conditionals | |
| // ---------------------------------------------------------------------------- | |
| /* @internal */ | |
| export const filterOrFail: { | |
| <A, E2, B extends A>( | |
| refinement: Predicate.Refinement<NoInfer<A>, B>, | |
| orFailWith: (a: NoInfer<A>) => E2 | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E2 | E, R> | |
| <A, E2>( | |
| predicate: Predicate.Predicate<NoInfer<A>>, | |
| orFailWith: (a: NoInfer<A>) => E2 | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E2 | E, R> | |
| <A, B extends A>( | |
| refinement: Predicate.Refinement<NoInfer<A>, B> | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, Cause.NoSuchElementError | E, R> | |
| <A>( | |
| predicate: Predicate.Predicate<NoInfer<A>> | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, Cause.NoSuchElementError | E, R> | |
| <A, E, R, E2, B extends A>( | |
| self: Effect.Effect<A, E, R>, | |
| refinement: Predicate.Refinement<NoInfer<A>, B>, | |
| orFailWith: (a: NoInfer<A>) => E2 | |
| ): Effect.Effect<B, E2 | E, R> | |
| <A, E, R, E2>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<NoInfer<A>>, | |
| orFailWith: (a: NoInfer<A>) => E2 | |
| ): Effect.Effect<A, E2 | E, R> | |
| <A, E, R, B extends A>( | |
| self: Effect.Effect<A, E, R>, | |
| refinement: Predicate.Refinement<NoInfer<A>, B> | |
| ): Effect.Effect<B, E | Cause.NoSuchElementError, R> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<NoInfer<A>> | |
| ): Effect.Effect<A, E | Cause.NoSuchElementError, R> | |
| } = dual((args) => isEffect(args[0]), <A, E, R, E2>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<NoInfer<A>>, | |
| orFailWith?: (a: any) => E2 | |
| ): Effect.Effect<any, E | E2 | Cause.NoSuchElementError, R> => | |
| filterOrElse( | |
| self, | |
| predicate as any, | |
| orFailWith ? (a: any) => fail(orFailWith(a)) : () => fail(new NoSuchElementError() as E2) | |
| )) | |
| /** @internal */ | |
| export const when: { | |
| <E2 = never, R2 = never>( | |
| condition: Effect.Effect<boolean, E2, R2> | |
| ): <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<Option.Option<A>, E | E2, R | R2> | |
| <A, E, R, E2 = never, R2 = never>( | |
| self: Effect.Effect<A, E, R>, | |
| condition: Effect.Effect<boolean, E2, R2> | |
| ): Effect.Effect<Option.Option<A>, E | E2, R | R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, E2 = never, R2 = never>( | |
| self: Effect.Effect<A, E, R>, | |
| condition: Effect.Effect<boolean, E2, R2> | |
| ): Effect.Effect<Option.Option<A>, E | E2, R | R2> => flatMap(condition, (pass) => pass ? asSome(self) : succeedNone) | |
| ) | |
| // ---------------------------------------------------------------------------- | |
| // repetition | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const replicate: { | |
| ( | |
| n: number | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Array<Effect.Effect<A, E, R>> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| n: number | |
| ): Array<Effect.Effect<A, E, R>> | |
| } = dual( | |
| 2, | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| n: number | |
| ): Array<Effect.Effect<A, E, R>> => Array.from({ length: n }, () => self) | |
| ) | |
| /** @internal */ | |
| export const replicateEffect: { | |
| ( | |
| n: number, | |
| options?: { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard?: false | undefined | |
| } | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Array<A>, E, R> | |
| ( | |
| n: number, | |
| options: { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard: true | |
| } | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<void, E, R> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| n: number, | |
| options?: { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard?: false | undefined | |
| } | |
| ): Effect.Effect<Array<A>, E, R> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| n: number, | |
| options: { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard: true | |
| } | |
| ): Effect.Effect<void, E, R> | |
| } = dual( | |
| (args) => isEffect(args[0]), | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| n: number, | |
| options: { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard: true | |
| } | |
| ): Effect.Effect<void, E, R> => all(replicate(self, n), options) | |
| ) | |
| /** @internal */ | |
| export const forever: { | |
| < | |
| Arg extends Effect.Effect<any, any, any> | { | |
| readonly disableYield?: boolean | undefined | |
| } | undefined = { | |
| readonly disableYield?: boolean | undefined | |
| } | |
| >( | |
| effectOrOptions: Arg, | |
| options?: { | |
| readonly disableYield?: boolean | undefined | |
| } | undefined | |
| ): [Arg] extends [Effect.Effect<infer _A, infer _E, infer _R>] ? Effect.Effect<never, _E, _R> | |
| : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<never, E, R> | |
| } = dual((args) => isEffect(args[0]), <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| options?: { | |
| readonly disableYield?: boolean | undefined | |
| } | |
| ): Effect.Effect<never, E, R> => | |
| whileLoop({ | |
| while: constTrue, | |
| body: constant(options?.disableYield ? self : flatMap(self, (_) => yieldNow)), | |
| step: constVoid | |
| }) as any) | |
| // ---------------------------------------------------------------------------- | |
| // error handling | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const catchCause: { | |
| <E, B, E2, R2>( | |
| f: (cause: NoInfer<Cause.Cause<E>>) => Effect.Effect<B, E2, R2> | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A | B, E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (cause: NoInfer<Cause.Cause<E>>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A | B, E2, R | R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (cause: NoInfer<Cause.Cause<E>>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A | B, E2, R | R2> => { | |
| const onFailure = Object.create(OnFailureProto) | |
| onFailure[args] = self | |
| onFailure[contE] = f.length !== 1 ? (cause: Cause.Cause<E>) => f(cause) : f | |
| return onFailure | |
| } | |
| ) | |
| const OnFailureProto = makePrimitiveProto({ | |
| op: "OnFailure", | |
| [evaluate](this: any, fiber: FiberImpl): Primitive { | |
| fiber._stack.push(this as any) | |
| return this[args] | |
| } | |
| }) | |
| /** @internal */ | |
| export const catchCauseIf: { | |
| <E, B, E2, R2>( | |
| predicate: Predicate.Predicate<Cause.Cause<E>>, | |
| f: (cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2> | |
| ): <A, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A | B, E | E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<Cause.Cause<E>>, | |
| f: (cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A | B, E | E2, R | R2> | |
| } = dual( | |
| 3, | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<Cause.Cause<E>>, | |
| f: (cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A | B, E | E2, R | R2> => | |
| catchCause(self, (cause): Effect.Effect<B, E | E2, R2> => { | |
| if (!predicate(cause)) { | |
| return failCause(cause) as any | |
| } | |
| return internalCall(() => f(cause)) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const catchCauseFilter: { | |
| <E, B, E2, R2, EB, X extends Cause.Cause<any>>( | |
| filter: Filter.Filter<Cause.Cause<E>, EB, X>, | |
| f: (failure: EB, cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2> | |
| ): <A, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A | B, Cause.Cause.Error<X> | E2, R | R2> | |
| <A, E, R, B, E2, R2, EB, X extends Cause.Cause<any>>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<Cause.Cause<E>, EB, X>, | |
| f: (failure: EB, cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A | B, Cause.Cause.Error<X> | E2, R | R2> | |
| } = dual( | |
| 3, | |
| <A, E, R, B, E2, R2, EB, X extends Cause.Cause<any>>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<Cause.Cause<E>, EB, X>, | |
| f: (failure: EB, cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A | B, Cause.Cause.Error<X> | E2, R | R2> => | |
| catchCause(self, (cause): Effect.Effect<B, Cause.Cause.Error<X> | E2, R2> => { | |
| const eb = filter(cause) | |
| return Result.isFailure(eb) ? failCause(eb.failure) : internalCall(() => f(eb.success, cause)) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const catch_: { | |
| <E, B, E2, R2>( | |
| f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2> | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A | B, E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A | B, E2, R | R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (a: NoInfer<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A | B, E2, R | R2> => catchCauseFilter(self, findError as any, (e: any) => f(e)) as any | |
| ) | |
| /** @internal */ | |
| export const catchNoSuchElement = <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ): Effect.Effect<Option.Option<A>, Exclude<E, Cause.NoSuchElementError>, R> => | |
| matchEffect(self, { | |
| onFailure: (error) => | |
| isNoSuchElementError(error) | |
| ? succeedNone | |
| : fail(error as Exclude<E, Cause.NoSuchElementError>), | |
| onSuccess: succeedSome | |
| }) | |
| /** @internal */ | |
| export const catchDefect: { | |
| <E, B, E2, R2>( | |
| f: (defect: unknown) => Effect.Effect<B, E2, R2> | |
| ): <A, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A | B, E | E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (defect: unknown) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A | B, E | E2, R | R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (defect: unknown) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A | B, E | E2, R | R2> => catchCauseFilter(self, findDefect as any, f as any) as any | |
| ) | |
| /** @internal */ | |
| export const tapCause: { | |
| <E, B, E2, R2>( | |
| f: (cause: NoInfer<Cause.Cause<E>>) => Effect.Effect<B, E2, R2> | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (cause: NoInfer<Cause.Cause<E>>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (cause: NoInfer<Cause.Cause<E>>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> => | |
| catchCause(self, (cause) => andThen(internalCall(() => f(cause)), failCause(cause))) | |
| ) | |
| /** @internal */ | |
| export const tapCauseIf: { | |
| <E, B, E2, R2>( | |
| predicate: Predicate.Predicate<Cause.Cause<E>>, | |
| f: (cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2> | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<Cause.Cause<E>>, | |
| f: (cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> | |
| } = dual( | |
| 3, | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<Cause.Cause<E>>, | |
| f: (cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> => | |
| catchCauseIf( | |
| self, | |
| predicate, | |
| (cause) => andThen(internalCall(() => f(cause)), failCause(cause)) | |
| ) | |
| ) | |
| /** @internal */ | |
| export const tapCauseFilter: { | |
| <E, B, E2, R2, EB, X extends Cause.Cause<any>>( | |
| filter: Filter.Filter<Cause.Cause<E>, EB, X>, | |
| f: (a: EB, cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2> | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2> | |
| <A, E, R, B, E2, R2, EB, X extends Cause.Cause<any>>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<Cause.Cause<E>, EB, X>, | |
| f: (a: EB, cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> | |
| } = dual( | |
| 3, | |
| <A, E, R, B, E2, R2, EB, X extends Cause.Cause<any>>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<Cause.Cause<E>, EB, X>, | |
| f: (a: EB, cause: Cause.Cause<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> => | |
| catchCause(self, (cause) => { | |
| const result = filter(cause) | |
| if (Result.isFailure(result)) { | |
| return failCause(cause) | |
| } | |
| return andThen(internalCall(() => f(result.success, cause)), failCause(cause)) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const tapError: { | |
| <E, B, E2, R2>( | |
| f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2> | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (e: NoInfer<E>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> => tapCauseFilter(self, findError as any, (e: any) => f(e)) as any | |
| ) | |
| /** @internal */ | |
| export const tapErrorTag: { | |
| <const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>, E, A1, E1, R1>( | |
| k: K, | |
| f: ( | |
| e: ExtractTag<NoInfer<E>, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K> | |
| ) => Effect.Effect<A1, E1, R1> | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E1, R1 | R> | |
| < | |
| A, | |
| E, | |
| R, | |
| const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>, | |
| R1, | |
| E1, | |
| A1 | |
| >( | |
| self: Effect.Effect<A, E, R>, | |
| k: K, | |
| f: (e: ExtractTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A1, E1, R1> | |
| ): Effect.Effect<A, E | E1, R | R1> | |
| } = dual( | |
| 3, | |
| < | |
| A, | |
| E, | |
| R, | |
| const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>, | |
| R1, | |
| E1, | |
| A1 | |
| >( | |
| self: Effect.Effect<A, E, R>, | |
| k: K, | |
| f: (e: ExtractTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A1, E1, R1> | |
| ): Effect.Effect<A, E | E1, R | R1> => { | |
| const predicate = Array.isArray(k) | |
| ? ((e: E): e is ExtractTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K> => | |
| hasProperty(e, "_tag") && k.includes(e._tag)) | |
| : isTagged(k as string) | |
| return tapError( | |
| self, | |
| (error) => | |
| predicate(error) | |
| ? f(error as ExtractTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) | |
| : void_ | |
| ) | |
| } | |
| ) | |
| /** @internal */ | |
| export const tapDefect: { | |
| <E, B, E2, R2>( | |
| f: (defect: unknown) => Effect.Effect<B, E2, R2> | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | E2, R | R2> | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (defect: unknown) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (defect: unknown) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A, E | E2, R | R2> => tapCauseFilter(self, findDefect as any, (_: any) => f(_)) as any | |
| ) | |
| /** @internal */ | |
| export const catchIf: { | |
| <E, EB extends E, A2, E2, R2, A3 = unassigned, E3 = never, R3 = never>( | |
| refinement: Predicate.Refinement<NoInfer<E>, EB>, | |
| f: (e: EB) => Effect.Effect<A2, E2, R2>, | |
| orElse?: ((e: Exclude<E, EB>) => Effect.Effect<A3, E3, R3>) | undefined | |
| ): <A, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect< | |
| A | A2 | Exclude<A3, unassigned>, | |
| E2 | E3 | (A3 extends unassigned ? Exclude<E, EB> : never), | |
| R | R2 | R3 | |
| > | |
| <E, A2, E2, R2, A3 = unassigned, E3 = never, R3 = never>( | |
| predicate: Predicate.Predicate<NoInfer<E>>, | |
| f: (e: NoInfer<E>) => Effect.Effect<A2, E2, R2>, | |
| orElse?: ((e: NoInfer<E>) => Effect.Effect<A3, E3, R3>) | undefined | |
| ): <A, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A | A2 | Exclude<A3, unassigned>, E2 | E3 | (A3 extends unassigned ? E : never), R | R2 | R3> | |
| <A, E, R, EB extends E, A2, E2, R2, A3 = unassigned, E3 = never, R3 = never>( | |
| self: Effect.Effect<A, E, R>, | |
| refinement: Predicate.Refinement<E, EB>, | |
| f: (e: EB) => Effect.Effect<A2, E2, R2>, | |
| orElse?: ((e: Exclude<E, EB>) => Effect.Effect<A3, E3, R3>) | undefined | |
| ): Effect.Effect< | |
| A | A2 | Exclude<A3, unassigned>, | |
| E2 | E3 | (A3 extends unassigned ? Exclude<E, EB> : never), | |
| R | R2 | R3 | |
| > | |
| <A, E, R, A2, E2, R2, A3 = unassigned, E3 = never, R3 = never>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<E>, | |
| f: (e: E) => Effect.Effect<A2, E2, R2>, | |
| orElse?: ((e: E) => Effect.Effect<A3, E3, R3>) | undefined | |
| ): Effect.Effect<A | A2 | Exclude<A3, unassigned>, E2 | E3 | (A3 extends unassigned ? E : never), R | R2 | R3> | |
| } = dual( | |
| (args) => isEffect(args[0]), | |
| <A, E, R, A2, E2, R2, A3 = never, E3 = E, R3 = never>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<E>, | |
| f: (e: E) => Effect.Effect<A2, E2, R2>, | |
| orElse?: ((e: E) => Effect.Effect<A3, E3, R3>) | undefined | |
| ): Effect.Effect<A | A2 | A3, E2 | E3, R | R2 | R3> => | |
| catchCause(self, (cause): Effect.Effect<A2 | A3, E2 | E3, R2 | R3> => { | |
| const error = findError(cause) | |
| if (Result.isFailure(error)) return failCause(error.failure) | |
| if (!predicate(error.success)) { | |
| return orElse ? internalCall(() => orElse(error.success as any)) : failCause(cause as any as Cause.Cause<E3>) | |
| } | |
| return internalCall(() => f(error.success as any)) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const catchFilter: { | |
| <E, EB, A2, E2, R2, X, A3 = unassigned, E3 = never, R3 = never>( | |
| filter: Filter.Filter<NoInfer<E>, EB, X>, | |
| f: (e: EB) => Effect.Effect<A2, E2, R2>, | |
| orElse?: ((e: X) => Effect.Effect<A3, E3, R3>) | undefined | |
| ): <A, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A | A2 | Exclude<A3, unassigned>, E2 | E3 | (A3 extends unassigned ? X : never), R | R2 | R3> | |
| <A, E, R, EB, A2, E2, R2, X, A3 = unassigned, E3 = never, R3 = never>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<NoInfer<E>, EB, X>, | |
| f: (e: EB) => Effect.Effect<A2, E2, R2>, | |
| orElse?: ((e: X) => Effect.Effect<A3, E3, R3>) | undefined | |
| ): Effect.Effect<A | A2 | Exclude<A3, unassigned>, E2 | E3 | (A3 extends unassigned ? X : never), R | R2 | R3> | |
| } = dual( | |
| (args) => isEffect(args[0]), | |
| <A, E, R, EB, A2, E2, R2, X, A3 = never, E3 = X, R3 = never>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<NoInfer<E>, EB, X>, | |
| f: (e: EB) => Effect.Effect<A2, E2, R2>, | |
| orElse?: ((e: X) => Effect.Effect<A3, E3, R3>) | undefined | |
| ): Effect.Effect<A | A2 | A3, E2 | E3, R | R2 | R3> => | |
| catchCause(self, (cause): Effect.Effect<A2 | A3, E2 | E3, R2 | R3> => { | |
| const error = findError(cause) | |
| if (Result.isFailure(error)) return failCause(error.failure) | |
| const result = filter(error.success) | |
| if (Result.isFailure(result)) { | |
| return orElse ? internalCall(() => orElse(result.failure as any)) : failCause(cause as any as Cause.Cause<E3>) | |
| } | |
| return internalCall(() => f(result.success)) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const catchTag: { | |
| < | |
| const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>, | |
| E, | |
| A1, | |
| E1, | |
| R1, | |
| A2 = unassigned, | |
| E2 = never, | |
| R2 = never | |
| >( | |
| k: K, | |
| f: ( | |
| e: ExtractTag<NoInfer<E>, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K> | |
| ) => Effect.Effect<A1, E1, R1>, | |
| orElse?: | |
| | ((e: ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A2, E2, R2>) | |
| | undefined | |
| ): <A, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect< | |
| A | A1 | Exclude<A2, unassigned>, | |
| | E1 | |
| | E2 | |
| | (A2 extends unassigned ? ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K> : never), | |
| R | R1 | R2 | |
| > | |
| < | |
| A, | |
| E, | |
| R, | |
| const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>, | |
| R1, | |
| E1, | |
| A1, | |
| A2 = unassigned, | |
| E2 = never, | |
| R2 = never | |
| >( | |
| self: Effect.Effect<A, E, R>, | |
| k: K, | |
| f: (e: ExtractTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A1, E1, R1>, | |
| orElse?: | |
| | ((e: ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A2, E2, R2>) | |
| | undefined | |
| ): Effect.Effect< | |
| A | A1 | Exclude<A2, unassigned>, | |
| | E1 | |
| | E2 | |
| | (A2 extends unassigned ? ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K> : never), | |
| R | R1 | R2 | |
| > | |
| } = dual( | |
| (args) => isEffect(args[0]), | |
| < | |
| A, | |
| E, | |
| R, | |
| const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>, | |
| R1, | |
| E1, | |
| A1, | |
| A2 = never, | |
| E2 = ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>, | |
| R2 = never | |
| >( | |
| self: Effect.Effect<A, E, R>, | |
| k: K, | |
| f: (e: ExtractTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A1, E1, R1>, | |
| orElse?: | |
| | ((e: ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<A2, E2, R2>) | |
| | undefined | |
| ): Effect.Effect<A | A1 | A2, E1 | E2, R | R1 | R2> => { | |
| const pred = Array.isArray(k) | |
| ? ((e: E): e is any => hasProperty(e, "_tag") && k.includes(e._tag)) | |
| : isTagged(k as string) | |
| return catchIf(self, pred, f, orElse as any) as any | |
| } | |
| ) | |
| /** @internal */ | |
| export const catchTags: { | |
| < | |
| E, | |
| Cases extends (E extends { _tag: string } ? { | |
| [K in E["_tag"]]+?: (error: Extract<E, { _tag: K }>) => Effect.Effect<any, any, any> | |
| } : | |
| {}), | |
| A2 = unassigned, | |
| E2 = never, | |
| R2 = never | |
| >( | |
| cases: Cases, | |
| orElse?: ((e: Exclude<E, { _tag: keyof Cases }>) => Effect.Effect<A2, E2, R2>) | undefined | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect< | |
| | A | |
| | Exclude<A2, unassigned> | |
| | { | |
| [K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<infer A, any, any>) ? A : never | |
| }[keyof Cases], | |
| | E2 | |
| | (A2 extends unassigned ? Exclude<E, { _tag: keyof Cases }> : never) | |
| | { | |
| [K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<any, infer E, any>) ? E : never | |
| }[keyof Cases], | |
| | R | |
| | R2 | |
| | { | |
| [K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<any, any, infer R>) ? R : never | |
| }[keyof Cases] | |
| > | |
| < | |
| R, | |
| E, | |
| A, | |
| Cases extends (E extends { _tag: string } ? { | |
| [K in E["_tag"]]+?: (error: Extract<E, { _tag: K }>) => Effect.Effect<any, any, any> | |
| } : | |
| {}), | |
| A2 = unassigned, | |
| E2 = never, | |
| R2 = never | |
| >( | |
| self: Effect.Effect<A, E, R>, | |
| cases: Cases, | |
| orElse?: ((e: Exclude<E, { _tag: keyof Cases }>) => Effect.Effect<A2, E2, R2>) | undefined | |
| ): Effect.Effect< | |
| | A | |
| | Exclude<A2, unassigned> | |
| | { | |
| [K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<infer A, any, any>) ? A : never | |
| }[keyof Cases], | |
| | E2 | |
| | (A2 extends unassigned ? Exclude<E, { _tag: keyof Cases }> : never) | |
| | { | |
| [K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<any, infer E, any>) ? E : never | |
| }[keyof Cases], | |
| | R | |
| | R2 | |
| | { | |
| [K in keyof Cases]: Cases[K] extends ((...args: Array<any>) => Effect.Effect<any, any, infer R>) ? R : never | |
| }[keyof Cases] | |
| > | |
| } = dual((args) => isEffect(args[0]), (self: Effect.Effect<any, any, any>, cases: Record<string, any>, orElse: any) => { | |
| let keys: Array<string> | |
| return catchFilter( | |
| self, | |
| (e) => { | |
| keys ??= Object.keys(cases) | |
| return hasProperty(e, "_tag") && isString(e["_tag"]) && keys.includes(e["_tag"]) | |
| ? Result.succeed(e) | |
| : Result.fail(e) | |
| }, | |
| (e: any) => internalCall(() => cases[e["_tag"] as string](e)), | |
| orElse | |
| ) as any | |
| }) | |
| /** @internal */ | |
| export const catchReason: { | |
| < | |
| K extends Tags<E>, | |
| E, | |
| RK extends ReasonTags<ExtractTag<NoInfer<E>, K>>, | |
| A2, | |
| E2, | |
| R2, | |
| A3 = unassigned, | |
| E3 = never, | |
| R3 = never | |
| >( | |
| errorTag: K, | |
| reasonTag: RK, | |
| f: ( | |
| reason: ExtractReason<ExtractTag<NoInfer<E>, K>, RK>, | |
| error: NarrowReason<ExtractTag<NoInfer<E>, K>, RK> | |
| ) => Effect.Effect<A2, E2, R2>, | |
| orElse?: | |
| | (( | |
| reasons: ExcludeReason<ExtractTag<NoInfer<E>, K>, RK>, | |
| error: OmitReason<ExtractTag<NoInfer<E>, K>, RK> | |
| ) => Effect.Effect<A3, E3, R3>) | |
| | undefined | |
| ): <A, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect< | |
| A | A2 | Exclude<A3, unassigned>, | |
| ExcludeTag<E, K> | E2 | E3 | (A3 extends unassigned ? ExtractTag<E, K> : never), | |
| R | R2 | R3 | |
| > | |
| < | |
| A, | |
| E, | |
| R, | |
| K extends Tags<E>, | |
| RK extends ReasonTags<ExtractTag<E, K>>, | |
| A2, | |
| E2, | |
| R2, | |
| A3 = unassigned, | |
| E3 = never, | |
| R3 = never | |
| >( | |
| self: Effect.Effect<A, E, R>, | |
| errorTag: K, | |
| reasonTag: RK, | |
| f: ( | |
| reason: ExtractReason<ExtractTag<E, K>, RK>, | |
| error: NarrowReason<ExtractTag<E, K>, RK> | |
| ) => Effect.Effect<A2, E2, R2>, | |
| orElse?: | |
| | (( | |
| reasons: ExcludeReason<ExtractTag<E, K>, RK>, | |
| error: OmitReason<ExtractTag<E, K>, RK> | |
| ) => Effect.Effect<A3, E3, R3>) | |
| | undefined | |
| ): Effect.Effect< | |
| A | A2 | Exclude<A3, unassigned>, | |
| ExcludeTag<E, K> | E2 | E3 | (A3 extends unassigned ? ExtractTag<E, K> : never), | |
| R | R2 | R3 | |
| > | |
| } = dual( | |
| (args) => isEffect(args[0]), | |
| < | |
| A, | |
| E, | |
| R, | |
| K extends Tags<E>, | |
| RK extends ReasonTags<ExtractTag<E, K>>, | |
| A2, | |
| E2, | |
| R2, | |
| A3 = unassigned, | |
| E3 = never, | |
| R3 = never | |
| >( | |
| self: Effect.Effect<A, E, R>, | |
| errorTag: K, | |
| reasonTag: RK, | |
| f: (reason: ExtractReason<ExtractTag<E, K>, RK>, error: ExtractTag<E, K>) => Effect.Effect<A2, E2, R2>, | |
| orElse?: | |
| | (( | |
| reasons: ExcludeReason<ExtractTag<E, K>, RK>, | |
| error: OmitReason<ExtractTag<E, K>, RK> | |
| ) => Effect.Effect<A3, E3, R3>) | |
| | undefined | |
| ): Effect.Effect< | |
| A | A2 | Exclude<A3, unassigned>, | |
| ExcludeTag<E, K> | E2 | E3 | (A3 extends unassigned ? ExtractTag<E, K> : never), | |
| R | R2 | R3 | |
| > => | |
| catchIf( | |
| self, | |
| ((e: any) => isTagged(e, errorTag) && hasProperty(e, "reason")) as any, | |
| (e: any): Effect.Effect<A2 | A3, E | E2 | E3, R2 | R3> => { | |
| const reason = e.reason as any | |
| if (isTagged(reason, reasonTag)) return f(reason as any, e) | |
| return orElse ? internalCall(() => orElse(reason, e)) : fail(e) | |
| } | |
| ) as any | |
| ) | |
| /** @internal */ | |
| export const catchReasons: { | |
| < | |
| K extends Tags<E>, | |
| E, | |
| Cases extends { | |
| [RK in ReasonTags<ExtractTag<NoInfer<E>, K>>]+?: ( | |
| reason: ExtractReason<ExtractTag<NoInfer<E>, K>, RK>, | |
| error: NarrowReason<ExtractTag<NoInfer<E>, K>, RK> | |
| ) => Effect.Effect<any, any, any> | |
| }, | |
| A2 = unassigned, | |
| E2 = never, | |
| R2 = never | |
| >( | |
| errorTag: K, | |
| cases: Cases, | |
| orElse?: | |
| | (( | |
| reason: ExcludeReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>>, | |
| error: OmitReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>> | |
| ) => Effect.Effect<A2, E2, R2>) | |
| | undefined | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect< | |
| | A | |
| | Exclude<A2, unassigned> | |
| | { [RK in keyof Cases]: Cases[RK] extends (...args: Array<any>) => Effect.Effect<infer A, any, any> ? A : never }[ | |
| keyof Cases | |
| ], | |
| | ExcludeTag<E, K> | |
| | E2 | |
| | (A2 extends unassigned ? ExtractTag<E, K> : never) | |
| | { [RK in keyof Cases]: Cases[RK] extends (...args: Array<any>) => Effect.Effect<any, infer E, any> ? E : never }[ | |
| keyof Cases | |
| ], | |
| | R | |
| | R2 | |
| | { [RK in keyof Cases]: Cases[RK] extends (...args: Array<any>) => Effect.Effect<any, any, infer R> ? R : never }[ | |
| keyof Cases | |
| ] | |
| > | |
| < | |
| A, | |
| E, | |
| R, | |
| K extends Tags<E>, | |
| Cases extends { | |
| [RK in ReasonTags<ExtractTag<E, K>>]+?: ( | |
| reason: ExtractReason<ExtractTag<E, K>, RK>, | |
| error: NarrowReason<ExtractTag<E, K>, RK> | |
| ) => Effect.Effect<any, any, any> | |
| }, | |
| A2 = unassigned, | |
| E2 = never, | |
| R2 = never | |
| >( | |
| self: Effect.Effect<A, E, R>, | |
| errorTag: K, | |
| cases: Cases, | |
| orElse?: | |
| | (( | |
| reason: ExcludeReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>>, | |
| error: OmitReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>> | |
| ) => Effect.Effect<A2, E2, R2>) | |
| | undefined | |
| ): Effect.Effect< | |
| | A | |
| | Exclude<A2, unassigned> | |
| | { [RK in keyof Cases]: Cases[RK] extends (...args: Array<any>) => Effect.Effect<infer A, any, any> ? A : never }[ | |
| keyof Cases | |
| ], | |
| | ExcludeTag<E, K> | |
| | E2 | |
| | (A2 extends unassigned ? ExtractTag<E, K> : never) | |
| | { [RK in keyof Cases]: Cases[RK] extends (...args: Array<any>) => Effect.Effect<any, infer E, any> ? E : never }[ | |
| keyof Cases | |
| ], | |
| | R | |
| | R2 | |
| | { [RK in keyof Cases]: Cases[RK] extends (...args: Array<any>) => Effect.Effect<any, any, infer R> ? R : never }[ | |
| keyof Cases | |
| ] | |
| > | |
| } = dual((args) => isEffect(args[0]), (self, errorTag, cases, orElse) => { | |
| let keys: Array<string> | |
| return catchIf( | |
| self, | |
| ((e: any) => | |
| isTagged(e, errorTag) && | |
| hasProperty(e, "reason") && | |
| hasProperty(e.reason, "_tag") && | |
| isString(e.reason._tag)) as any, | |
| (e: any) => { | |
| const reason = e.reason | |
| keys ??= Object.keys(cases) | |
| if (keys.includes(reason._tag)) { | |
| return internalCall(() => (cases as any)[reason._tag](reason, e)) | |
| } | |
| return orElse ? internalCall(() => orElse(reason, e)) : fail(e) | |
| } | |
| ) | |
| }) | |
| /** @internal */ | |
| export const unwrapReason: { | |
| < | |
| K extends Effect.TagsWithReason<E>, | |
| E | |
| >( | |
| errorTag: K | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, ExcludeTag<E, K> | ReasonOf<ExtractTag<E, K>>, R> | |
| < | |
| A, | |
| E, | |
| R, | |
| K extends Effect.TagsWithReason<E> | |
| >( | |
| self: Effect.Effect<A, E, R>, | |
| errorTag: K | |
| ): Effect.Effect<A, ExcludeTag<E, K> | ReasonOf<ExtractTag<E, K>>, R> | |
| } = dual( | |
| 2, | |
| < | |
| A, | |
| E, | |
| R, | |
| K extends Effect.TagsWithReason<E> | |
| >( | |
| self: Effect.Effect<A, E, R>, | |
| errorTag: K | |
| ): Effect.Effect<A, ExcludeTag<E, K> | ReasonOf<ExtractTag<E, K>>, R> => | |
| catchFilter( | |
| self, | |
| (e: any) => { | |
| if (isTagged(e, errorTag) && hasProperty(e, "reason")) { | |
| return Result.succeed(e.reason) | |
| } | |
| return Result.fail(e) | |
| }, | |
| fail as any | |
| ) as any | |
| ) | |
| /** @internal */ | |
| export const mapErrorCause: { | |
| <E, E2>( | |
| f: (e: Cause.Cause<E>) => Cause.Cause<E2> | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E2, R> | |
| <A, E, R, E2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (e: Cause.Cause<E>) => Cause.Cause<E2> | |
| ): Effect.Effect<A, E2, R> | |
| } = dual( | |
| 2, | |
| <A, E, R, E2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (e: Cause.Cause<E>) => Cause.Cause<E2> | |
| ): Effect.Effect<A, E2, R> => catchCause(self, (cause) => failCauseSync(() => f(cause))) | |
| ) | |
| /** @internal */ | |
| export const mapError: { | |
| <E, E2>( | |
| f: (e: E) => E2 | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E2, R> | |
| <A, E, R, E2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (e: E) => E2 | |
| ): Effect.Effect<A, E2, R> | |
| } = dual( | |
| 2, | |
| <A, E, R, E2>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (e: E) => E2 | |
| ): Effect.Effect<A, E2, R> => catch_(self, (error) => failSync(() => f(error))) | |
| ) | |
| /* @internal */ | |
| export const mapBoth: { | |
| <E, E2, A, A2>( | |
| options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } | |
| ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A2, E2, R> | |
| <A, E, R, E2, A2>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } | |
| ): Effect.Effect<A2, E2, R> | |
| } = dual(2, <A, E, R, E2, A2>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } | |
| ): Effect.Effect<A2, E2, R> => | |
| matchEffect(self, { | |
| onFailure: (e) => failSync(() => options.onFailure(e)), | |
| onSuccess: (a) => sync(() => options.onSuccess(a)) | |
| })) | |
| /** @internal */ | |
| export const orDie = <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ): Effect.Effect<A, never, R> => catch_(self, die) | |
| /** @internal */ | |
| export const orElseSucceed: { | |
| <B>( | |
| f: LazyArg<B> | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A | B, never, R> | |
| <A, E, R, B>( | |
| self: Effect.Effect<A, E, R>, | |
| f: LazyArg<B> | |
| ): Effect.Effect<A | B, never, R> | |
| } = dual( | |
| 2, | |
| <A, E, R, B>( | |
| self: Effect.Effect<A, E, R>, | |
| f: LazyArg<B> | |
| ): Effect.Effect<A | B, never, R> => catch_(self, (_) => sync(f)) | |
| ) | |
| /** @internal */ | |
| export const firstSuccessOf = <Eff extends Effect.Effect<any, any, any>>( | |
| effects: Iterable<Eff> | |
| ): Effect.Effect<Effect.Success<Eff>, Effect.Error<Eff>, Effect.Services<Eff>> => | |
| suspend(() => { | |
| const iterator = effects[Symbol.iterator]() | |
| let state = iterator.next() | |
| if (state.done) { | |
| return die(new Error("Received an empty collection of effects")) | |
| } | |
| function loop(current: IteratorYieldResult<Eff>): Eff { | |
| const next = iterator.next() | |
| if (next.done) return current.value | |
| return catch_(current.value, (_) => loop(next)) as any | |
| } | |
| return loop(state) | |
| }) | |
| /** @internal */ | |
| export const eventually = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, never, R> => | |
| catch_(self, (_) => flatMap(yieldNow, () => eventually(self))) | |
| /** @internal */ | |
| export const ignore: < | |
| Arg extends Effect.Effect<any, any, any> | { | |
| readonly log?: boolean | LogLevel.Severity | undefined | |
| readonly message?: string | undefined | |
| } | undefined = { | |
| readonly log?: boolean | LogLevel.Severity | undefined | |
| readonly message?: string | undefined | |
| } | |
| >( | |
| effectOrOptions: Arg, | |
| options?: { | |
| readonly log?: boolean | LogLevel.Severity | undefined | |
| readonly message?: string | undefined | |
| } | undefined | |
| ) => [Arg] extends [Effect.Effect<infer _A, infer _E, infer _R>] ? Effect.Effect<void, never, _R> | |
| : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<void, never, R> = dual( | |
| (args) => isEffect(args[0]), | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| options?: { | |
| readonly log?: boolean | LogLevel.Severity | undefined | |
| readonly message?: string | undefined | |
| } | undefined | |
| ): Effect.Effect<void, never, R> => { | |
| if (!options?.log) { | |
| return matchEffect(self, { onFailure: (_) => void_, onSuccess: (_) => void_ }) | |
| } | |
| const logEffect = logWithLevel(options.log === true ? undefined : options.log) | |
| return matchCauseEffect(self, { | |
| onFailure(cause) { | |
| const failure = findFail(cause) | |
| return Result.isFailure(failure) | |
| ? failCause(failure.failure) | |
| : options.message === undefined | |
| ? logEffect(cause) | |
| : logEffect(options.message, cause) | |
| }, | |
| onSuccess: (_) => void_ | |
| }) | |
| } | |
| ) | |
| /** @internal */ | |
| export const ignoreCause: < | |
| Arg extends Effect.Effect<any, any, any> | { | |
| readonly log?: boolean | LogLevel.Severity | undefined | |
| readonly message?: string | undefined | |
| } | undefined = { | |
| readonly log?: boolean | LogLevel.Severity | undefined | |
| readonly message?: string | undefined | |
| } | |
| >( | |
| effectOrOptions: Arg, | |
| options?: { | |
| readonly log?: boolean | LogLevel.Severity | undefined | |
| readonly message?: string | undefined | |
| } | undefined | |
| ) => [Arg] extends [Effect.Effect<infer _A, infer _E, infer _R>] ? Effect.Effect<void, never, _R> | |
| : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<void, never, R> = dual( | |
| (args) => isEffect(args[0]), | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| options?: { | |
| readonly log?: boolean | LogLevel.Severity | undefined | |
| readonly message?: string | undefined | |
| } | undefined | |
| ): Effect.Effect<void, never, R> => { | |
| if (!options?.log) { | |
| return matchCauseEffect(self, { onFailure: (_) => void_, onSuccess: (_) => void_ }) | |
| } | |
| const logEffect = logWithLevel(options.log === true ? undefined : options.log) | |
| return matchCauseEffect(self, { | |
| onFailure: (cause) => options.message === undefined ? logEffect(cause) : logEffect(options.message, cause), | |
| onSuccess: (_) => void_ | |
| }) | |
| } | |
| ) | |
| /** @internal */ | |
| export const option = <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ): Effect.Effect<Option.Option<A>, never, R> => match(self, { onFailure: Option.none, onSuccess: Option.some }) | |
| /** @internal */ | |
| export const result = <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ): Effect.Effect<Result.Result<A, E>, never, R> => | |
| matchEager(self, { onFailure: Result.fail, onSuccess: Result.succeed }) | |
| // ---------------------------------------------------------------------------- | |
| // pattern matching | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const matchCauseEffect: { | |
| <E, A2, E2, R2, A, A3, E3, R3>(options: { | |
| readonly onFailure: (cause: Cause.Cause<E>) => Effect.Effect<A2, E2, R2> | |
| readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3> | |
| }): <R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R> | |
| <A, E, R, A2, E2, R2, A3, E3, R3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (cause: Cause.Cause<E>) => Effect.Effect<A2, E2, R2> | |
| readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3> | |
| } | |
| ): Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R> | |
| } = dual( | |
| 2, | |
| <A, E, R, A2, E2, R2, A3, E3, R3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (cause: Cause.Cause<E>) => Effect.Effect<A2, E2, R2> | |
| readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3> | |
| } | |
| ): Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R> => { | |
| const primitive = Object.create(OnSuccessAndFailureProto) | |
| primitive[args] = self | |
| primitive[contA] = options.onSuccess.length !== 1 ? (a: A) => options.onSuccess(a) : options.onSuccess | |
| primitive[contE] = options.onFailure.length !== 1 | |
| ? (cause: Cause.Cause<E>) => options.onFailure(cause) | |
| : options.onFailure | |
| return primitive | |
| } | |
| ) | |
| const OnSuccessAndFailureProto = makePrimitiveProto({ | |
| op: "OnSuccessAndFailure", | |
| [evaluate](this: any, fiber: FiberImpl): Primitive { | |
| fiber._stack.push(this) | |
| return this[args] | |
| } | |
| }) | |
| /** @internal */ | |
| export const matchCause: { | |
| <E, A2, A, A3>(options: { | |
| readonly onFailure: (cause: Cause.Cause<E>) => A2 | |
| readonly onSuccess: (a: A) => A3 | |
| }): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A2 | A3, never, R> | |
| <A, E, R, A2, A3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (cause: Cause.Cause<E>) => A2 | |
| readonly onSuccess: (a: A) => A3 | |
| } | |
| ): Effect.Effect<A2 | A3, never, R> | |
| } = dual( | |
| 2, | |
| <A, E, R, A2, A3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (cause: Cause.Cause<E>) => A2 | |
| readonly onSuccess: (a: A) => A3 | |
| } | |
| ): Effect.Effect<A2 | A3, never, R> => | |
| matchCauseEffect(self, { | |
| onFailure: (cause) => sync(() => options.onFailure(cause)), | |
| onSuccess: (value) => sync(() => options.onSuccess(value)) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const matchEffect: { | |
| <E, A2, E2, R2, A, A3, E3, R3>(options: { | |
| readonly onFailure: (e: E) => Effect.Effect<A2, E2, R2> | |
| readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3> | |
| }): <R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R> | |
| <A, E, R, A2, E2, R2, A3, E3, R3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (e: E) => Effect.Effect<A2, E2, R2> | |
| readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3> | |
| } | |
| ): Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R> | |
| } = dual( | |
| 2, | |
| <A, E, R, A2, E2, R2, A3, E3, R3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (e: E) => Effect.Effect<A2, E2, R2> | |
| readonly onSuccess: (a: A) => Effect.Effect<A3, E3, R3> | |
| } | |
| ): Effect.Effect<A2 | A3, E2 | E3, R2 | R3 | R> => | |
| matchCauseEffect(self, { | |
| onFailure: (cause) => { | |
| const fail = cause.reasons.find(isFailReason) | |
| return fail | |
| ? internalCall(() => options.onFailure(fail.error)) | |
| : failCause(cause as Cause.Cause<never>) | |
| }, | |
| onSuccess: options.onSuccess | |
| }) | |
| ) | |
| /** @internal */ | |
| export const match: { | |
| <E, A2, A, A3>(options: { | |
| readonly onFailure: (error: E) => A2 | |
| readonly onSuccess: (value: A) => A3 | |
| }): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A2 | A3, never, R> | |
| <A, E, R, A2, A3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (error: E) => A2 | |
| readonly onSuccess: (value: A) => A3 | |
| } | |
| ): Effect.Effect<A2 | A3, never, R> | |
| } = dual( | |
| 2, | |
| <A, E, R, A2, A3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (error: E) => A2 | |
| readonly onSuccess: (value: A) => A3 | |
| } | |
| ): Effect.Effect<A2 | A3, never, R> => | |
| matchEffect(self, { | |
| onFailure: (error) => sync(() => options.onFailure(error)), | |
| onSuccess: (value) => sync(() => options.onSuccess(value)) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const matchEager: { | |
| <E, A2, A, A3>(options: { | |
| readonly onFailure: (error: E) => A2 | |
| readonly onSuccess: (value: A) => A3 | |
| }): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A2 | A3, never, R> | |
| <A, E, R, A2, A3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (error: E) => A2 | |
| readonly onSuccess: (value: A) => A3 | |
| } | |
| ): Effect.Effect<A2 | A3, never, R> | |
| } = dual( | |
| 2, | |
| <A, E, R, A2, A3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (error: E) => A2 | |
| readonly onSuccess: (value: A) => A3 | |
| } | |
| ): Effect.Effect<A2 | A3, never, R> => { | |
| if (effectIsExit(self)) { | |
| if (self._tag === "Success") return exitSucceed(options.onSuccess(self.value)) | |
| const error = findError(self.cause) | |
| if (Result.isFailure(error)) return self as Exit.Exit<never> | |
| return exitSucceed(options.onFailure(error.success)) | |
| } | |
| return match(self, options) | |
| } | |
| ) | |
| /** @internal */ | |
| export const matchCauseEager: { | |
| <E, A2, A, A3>(options: { | |
| readonly onFailure: (cause: Cause.Cause<E>) => A2 | |
| readonly onSuccess: (value: A) => A3 | |
| }): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A2 | A3, never, R> | |
| <A, E, R, A2, A3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (cause: Cause.Cause<E>) => A2 | |
| readonly onSuccess: (value: A) => A3 | |
| } | |
| ): Effect.Effect<A2 | A3, never, R> | |
| } = dual( | |
| 2, | |
| <A, E, R, A2, A3>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly onFailure: (cause: Cause.Cause<E>) => A2 | |
| readonly onSuccess: (value: A) => A3 | |
| } | |
| ): Effect.Effect<A2 | A3, never, R> => { | |
| if (effectIsExit(self)) { | |
| if (self._tag === "Success") return exitSucceed(options.onSuccess(self.value)) | |
| return exitSucceed(options.onFailure(self.cause)) | |
| } | |
| return matchCause(self, options) | |
| } | |
| ) | |
| /** @internal */ | |
| export const exit = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<Exit.Exit<A, E>, never, R> => | |
| effectIsExit(self) ? exitSucceed(self) : exitPrimitive(self) | |
| const exitPrimitive: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Exit.Exit<A, E>, never, R> = | |
| makePrimitive({ | |
| op: "Exit", | |
| [evaluate](fiber): Primitive { | |
| fiber._stack.push(this) | |
| return this[args] as any | |
| }, | |
| [contA](value, _, exit) { | |
| return succeed(exit ?? exitSucceed(value)) | |
| }, | |
| [contE](cause, _, exit) { | |
| return succeed(exit ?? exitFailCause(cause)) | |
| } | |
| }) | |
| // ---------------------------------------------------------------------------- | |
| // Condition checking | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const isFailure: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<boolean, never, R> = matchEager({ | |
| onFailure: () => true, | |
| onSuccess: () => false | |
| }) | |
| /** @internal */ | |
| export const isSuccess: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<boolean, never, R> = matchEager({ | |
| onFailure: () => false, | |
| onSuccess: () => true | |
| }) | |
| // ---------------------------------------------------------------------------- | |
| // delays & timeouts | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const delay: { | |
| ( | |
| duration: Duration.Input | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| duration: Duration.Input | |
| ): Effect.Effect<A, E, R> | |
| } = dual( | |
| 2, | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| duration: Duration.Input | |
| ): Effect.Effect<A, E, R> => andThen(sleep(duration), self) | |
| ) | |
| /** @internal */ | |
| export const timeoutOrElse: { | |
| <A2, E2, R2>(options: { | |
| readonly duration: Duration.Input | |
| readonly orElse: LazyArg<Effect.Effect<A2, E2, R2>> | |
| }): <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A | A2, E | E2, R | R2> | |
| <A, E, R, A2, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly duration: Duration.Input | |
| readonly orElse: LazyArg<Effect.Effect<A2, E2, R2>> | |
| } | |
| ): Effect.Effect<A | A2, E | E2, R | R2> | |
| } = dual( | |
| 2, | |
| <A, E, R, A2, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| options: { | |
| readonly duration: Duration.Input | |
| readonly orElse: LazyArg<Effect.Effect<A2, E2, R2>> | |
| } | |
| ): Effect.Effect<A | A2, E | E2, R | R2> => | |
| raceFirst( | |
| self, | |
| flatMap(sleep(options.duration), options.orElse) | |
| ) | |
| ) | |
| /** @internal */ | |
| export const timeout: { | |
| ( | |
| duration: Duration.Input | |
| ): <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A, E | Cause.TimeoutError, R> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| duration: Duration.Input | |
| ): Effect.Effect<A, E | Cause.TimeoutError, R> | |
| } = dual( | |
| 2, | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| duration: Duration.Input | |
| ): Effect.Effect<A, E | TimeoutError, R> => | |
| timeoutOrElse(self, { | |
| duration, | |
| orElse: () => fail(new TimeoutError()) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const timeoutOption: { | |
| ( | |
| duration: Duration.Input | |
| ): <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<Option.Option<A>, E, R> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| duration: Duration.Input | |
| ): Effect.Effect<Option.Option<A>, E, R> | |
| } = dual( | |
| 2, | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| duration: Duration.Input | |
| ): Effect.Effect<Option.Option<A>, E, R> => | |
| raceFirst( | |
| asSome(self), | |
| as(sleep(duration), Option.none()) | |
| ) | |
| ) | |
| /** @internal */ | |
| export const timed = <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ): Effect.Effect<[duration: Duration.Duration, result: A], E, R> => | |
| clockWith((clock) => { | |
| const start = clock.currentTimeNanosUnsafe() | |
| return map(self, (a) => [Duration.nanos(clock.currentTimeNanosUnsafe() - start), a]) | |
| }) | |
| // ---------------------------------------------------------------------------- | |
| // resources & finalization | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const ScopeTypeId = "~effect/Scope" | |
| /** @internal */ | |
| export const ScopeCloseableTypeId = "~effect/Scope/Closeable" | |
| /** @internal */ | |
| export const scopeTag: Context.Service<Scope.Scope, Scope.Scope> = Context.Service<Scope.Scope>("effect/Scope") | |
| /** @internal */ | |
| export const scopeClose = <A, E>(self: Scope.Scope, exit_: Exit.Exit<A, E>) => | |
| suspend(() => scopeCloseUnsafe(self, exit_) ?? void_) | |
| /** @internal */ | |
| export const scopeCloseUnsafe = <A, E>(self: Scope.Scope, exit_: Exit.Exit<A, E>) => { | |
| if (self.state._tag === "Closed") return | |
| const closed: Scope.State.Closed = { _tag: "Closed", exit: exit_ } | |
| if (self.state._tag === "Empty") { | |
| self.state = closed | |
| return | |
| } | |
| const { finalizers } = self.state | |
| self.state = closed | |
| if (finalizers.size === 0) { | |
| return | |
| } else if (finalizers.size === 1) { | |
| return finalizers.values().next().value!(exit_) | |
| } | |
| return scopeCloseFinalizers(self, finalizers, exit_) | |
| } | |
| const scopeCloseFinalizers = fnUntraced(function*<A, E>( | |
| self: Scope.Scope, | |
| finalizers: Scope.State.Open["finalizers"], | |
| exit_: Exit.Exit<A, E> | |
| ) { | |
| let exits: Array<Exit.Exit<any, never>> = [] | |
| const fibers: Array<Fiber.Fiber<any, never>> = [] | |
| const arr = Array.from(finalizers.values()) | |
| const parent = getCurrentFiber()! | |
| for (let i = arr.length - 1; i >= 0; i--) { | |
| const finalizer = arr[i] | |
| if (self.strategy === "sequential") { | |
| exits.push(yield* exit(finalizer(exit_))) | |
| } else { | |
| fibers.push(forkUnsafe(parent, finalizer(exit_), true, true, "inherit")) | |
| } | |
| } | |
| if (fibers.length > 0) { | |
| exits = yield* fiberAwaitAll(fibers) | |
| } | |
| return yield* exitAsVoidAll(exits) | |
| }) | |
| /** @internal */ | |
| export const scopeFork = (scope: Scope.Scope, finalizerStrategy?: "sequential" | "parallel") => | |
| sync(() => scopeForkUnsafe(scope, finalizerStrategy)) | |
| /** @internal */ | |
| export const scopeForkUnsafe = (scope: Scope.Scope, finalizerStrategy?: "sequential" | "parallel") => { | |
| const newScope = scopeMakeUnsafe(finalizerStrategy) | |
| if (scope.state._tag === "Closed") { | |
| newScope.state = scope.state | |
| return newScope | |
| } | |
| const key = {} | |
| scopeAddFinalizerUnsafe(scope, key, (exit) => scopeClose(newScope, exit)) | |
| scopeAddFinalizerUnsafe(newScope, key, (_) => sync(() => scopeRemoveFinalizerUnsafe(scope, key))) | |
| return newScope | |
| } | |
| /** @internal */ | |
| export const scopeAddFinalizerExit = ( | |
| scope: Scope.Scope, | |
| finalizer: (exit: Exit.Exit<any, any>) => Effect.Effect<unknown> | |
| ): Effect.Effect<void> => { | |
| return suspend(() => { | |
| if (scope.state._tag === "Closed") { | |
| return finalizer(scope.state.exit) | |
| } | |
| scopeAddFinalizerUnsafe(scope, {}, finalizer) | |
| return void_ | |
| }) | |
| } | |
| /** @internal */ | |
| export const scopeAddFinalizer = ( | |
| scope: Scope.Scope, | |
| finalizer: Effect.Effect<unknown> | |
| ): Effect.Effect<void> => scopeAddFinalizerExit(scope, constant(finalizer)) | |
| /** @internal */ | |
| export const scopeAddFinalizerUnsafe = ( | |
| scope: Scope.Scope, | |
| key: {}, | |
| finalizer: (exit: Exit.Exit<any, any>) => Effect.Effect<unknown> | |
| ): void => { | |
| if (scope.state._tag === "Empty") { | |
| scope.state = { _tag: "Open", finalizers: new Map([[key, finalizer]]) } | |
| } else if (scope.state._tag === "Open") { | |
| scope.state.finalizers.set(key, finalizer) | |
| } | |
| } | |
| /** @internal */ | |
| export const scopeRemoveFinalizerUnsafe = ( | |
| scope: Scope.Scope, | |
| key: {} | |
| ): void => { | |
| if (scope.state._tag === "Open") { | |
| scope.state.finalizers.delete(key) | |
| } | |
| } | |
| /** @internal */ | |
| export const scopeMakeUnsafe = (finalizerStrategy: "sequential" | "parallel" = "sequential"): Scope.Closeable => ({ | |
| [ScopeCloseableTypeId]: ScopeCloseableTypeId, | |
| [ScopeTypeId]: ScopeTypeId, | |
| strategy: finalizerStrategy, | |
| state: constScopeEmpty | |
| }) | |
| const constScopeEmpty = { _tag: "Empty" } as const | |
| /** @internal */ | |
| export const scopeMake = (finalizerStrategy?: "sequential" | "parallel"): Effect.Effect<Scope.Closeable> => | |
| sync(() => scopeMakeUnsafe(finalizerStrategy)) | |
| /** @internal */ | |
| export const scope: Effect.Effect<Scope.Scope, never, Scope.Scope> = scopeTag | |
| /** @internal */ | |
| export const provideScope: { | |
| (value: Scope.Scope): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Scope.Scope>> | |
| <A, E, R>(self: Effect.Effect<A, E, R>, value: Scope.Scope): Effect.Effect<A, E, Exclude<R, Scope.Scope>> | |
| } = provideService(scopeTag) | |
| /** @internal */ | |
| export const scoped = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, Exclude<R, Scope.Scope>> => | |
| withFiber((fiber) => { | |
| const prev = fiber.context | |
| const scope = scopeMakeUnsafe() | |
| fiber.setContext(Context.add(fiber.context, scopeTag, scope)) | |
| return onExitPrimitive(self, (exit) => { | |
| fiber.setContext(prev) | |
| return scopeCloseUnsafe(scope, exit) | |
| }) | |
| }) as any | |
| /** @internal */ | |
| export const scopeUse: { | |
| ( | |
| scope: Scope.Closeable | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Scope.Scope>> | |
| <A, E, R>(self: Effect.Effect<A, E, R>, scope: Scope.Closeable): Effect.Effect<A, E, Exclude<R, Scope.Scope>> | |
| } = dual( | |
| 2, | |
| <A, E, R>(self: Effect.Effect<A, E, R>, scope: Scope.Closeable): Effect.Effect<A, E, Exclude<R, Scope.Scope>> => | |
| onExit(provideScope(self, scope), (exit) => suspend(() => scopeCloseUnsafe(scope, exit) ?? void_)) | |
| ) | |
| /** @internal */ | |
| export const scopedWith = <A, E, R>( | |
| f: (scope: Scope.Scope) => Effect.Effect<A, E, R> | |
| ): Effect.Effect<A, E, R> => | |
| suspend(() => { | |
| const scope = scopeMakeUnsafe() | |
| return onExit(f(scope), (exit) => suspend(() => scopeCloseUnsafe(scope, exit) ?? void_)) | |
| }) | |
| /** @internal */ | |
| export const acquireRelease = <A, E, R, R2>( | |
| acquire: Effect.Effect<A, E, R>, | |
| release: (a: A, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<unknown, never, R2>, | |
| options?: { readonly interruptible?: boolean } | |
| ): Effect.Effect<A, E, R | R2 | Scope.Scope> => | |
| contextWith((context: Context.Context<R2>) => | |
| uninterruptibleMask((restore) => | |
| flatMap( | |
| scope, | |
| (scope) => | |
| tap( | |
| options?.interruptible ? restore(acquire) : acquire, | |
| (a) => scopeAddFinalizerExit(scope, (exit) => provideContext(release(a, exit), context)) | |
| ) | |
| ) | |
| ) | |
| ) | |
| /** @internal */ | |
| export const addFinalizer = <R>( | |
| finalizer: (exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void, never, R> | |
| ): Effect.Effect<void, never, R | Scope.Scope> => | |
| flatMap( | |
| scope, | |
| (scope) => | |
| contextWith((context: Context.Context<R>) => | |
| scopeAddFinalizerExit(scope, (exit) => provideContext(finalizer(exit), context)) | |
| ) | |
| ) | |
| /** @internal */ | |
| export const onExitPrimitive: <A, E, R, XE = never, XR = never>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (exit: Exit.Exit<A, E>) => Effect.Effect<void, XE, XR> | undefined, | |
| interruptible?: boolean | |
| ) => Effect.Effect<A, E | XE, R | XR> = makePrimitive({ | |
| op: "OnExit", | |
| single: false, | |
| [evaluate](fiber: FiberImpl) { | |
| fiber._stack.push(this) | |
| return this[args][0] | |
| }, | |
| [contAll](fiber) { | |
| if (fiber.interruptible && this[args][2] !== true) { | |
| fiber._stack.push(setInterruptibleTrue) | |
| fiber.interruptible = false | |
| } | |
| }, | |
| [contA](value, _, exit) { | |
| exit ??= exitSucceed(value) | |
| const eff = this[args][1](exit) | |
| return eff ? flatMap(eff, (_) => exit) : exit | |
| }, | |
| [contE](cause, _, exit) { | |
| exit ??= exitFailCause(cause) | |
| const eff = this[args][1](exit) | |
| return eff ? flatMap(eff, (_) => exit) : exit | |
| } | |
| }) | |
| /** @internal */ | |
| export const onExit: { | |
| <A, E, XE = never, XR = never>( | |
| f: (exit: Exit.Exit<A, E>) => Effect.Effect<void, XE, XR> | |
| ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR> | |
| <A, E, R, XE = never, XR = never>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (exit: Exit.Exit<A, E>) => Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> | |
| } = dual(2, onExitPrimitive) | |
| /** @internal */ | |
| export const ensuring: { | |
| <XE, XR>( | |
| finalizer: Effect.Effect<void, XE, XR> | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR> | |
| <A, E, R, XE, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| finalizer: Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> | |
| } = dual( | |
| 2, | |
| <A, E, R, XE, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| finalizer: Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> => onExit(self, (_) => finalizer) | |
| ) | |
| /** @internal */ | |
| export const onExitIf: { | |
| <A, E, XE, XR>( | |
| predicate: Predicate.Predicate<Exit.Exit<NoInfer<A>, NoInfer<E>>>, | |
| f: (exit: Exit.Exit<NoInfer<A>, NoInfer<E>>) => Effect.Effect<void, XE, XR> | |
| ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR> | |
| <A, E, R, XE, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<Exit.Exit<NoInfer<A>, NoInfer<E>>>, | |
| f: (exit: Exit.Exit<NoInfer<A>, NoInfer<E>>) => Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> | |
| } = dual( | |
| 3, | |
| <A, E, R, XE, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<Exit.Exit<NoInfer<A>, NoInfer<E>>>, | |
| f: (exit: Exit.Exit<NoInfer<A>, NoInfer<E>>) => Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> => | |
| onExit(self, (exit) => { | |
| if (!predicate(exit)) { | |
| return void_ | |
| } | |
| return f(exit) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const onExitFilter: { | |
| <A, E, XE, XR, B, X>( | |
| filter: Filter.Filter<Exit.Exit<NoInfer<A>, NoInfer<E>>, B, X>, | |
| f: (b: B, exit: Exit.Exit<NoInfer<A>, NoInfer<E>>) => Effect.Effect<void, XE, XR> | |
| ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR> | |
| <A, E, R, XE, XR, B, X>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<Exit.Exit<NoInfer<A>, NoInfer<E>>, B, X>, | |
| f: (b: B, exit: Exit.Exit<NoInfer<A>, NoInfer<E>>) => Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> | |
| } = dual( | |
| 3, | |
| <A, E, R, XE, XR, B, X>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<Exit.Exit<NoInfer<A>, NoInfer<E>>, B, X>, | |
| f: (b: B, exit: Exit.Exit<NoInfer<A>, NoInfer<E>>) => Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> => | |
| onExit(self, (exit) => { | |
| const b = filter(exit) | |
| return Result.isFailure(b) ? void_ : f(b.success, exit) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const onError: { | |
| <A, E, XE, XR>( | |
| f: (cause: Cause.Cause<NoInfer<E>>) => Effect.Effect<void, XE, XR> | |
| ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR> | |
| <A, E, R, XE, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (cause: Cause.Cause<NoInfer<E>>) => Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> | |
| } = dual( | |
| 2, | |
| <A, E, R, XE, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| f: (cause: Cause.Cause<NoInfer<E>>) => Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> => onExitFilter(self, exitFilterCause as any, f as any) as any | |
| ) | |
| /** @internal */ | |
| export const onErrorIf: { | |
| <E, XE, XR>( | |
| predicate: Predicate.Predicate<Cause.Cause<E>>, | |
| f: (cause: Cause.Cause<E>) => Effect.Effect<void, XE, XR> | |
| ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR> | |
| <A, E, R, XE, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<Cause.Cause<E>>, | |
| f: (cause: Cause.Cause<E>) => Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> | |
| } = dual( | |
| 3, | |
| <A, E, R, XE, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<Cause.Cause<E>>, | |
| f: (cause: Cause.Cause<E>) => Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> => | |
| onExitIf( | |
| self, | |
| (exit): exit is Exit.Failure<A, E> => { | |
| if (exit._tag !== "Failure") { | |
| return false | |
| } | |
| return predicate(exit.cause) | |
| }, | |
| (exit) => f((exit as Exit.Failure<A, E>).cause) | |
| ) as any | |
| ) | |
| /** @internal */ | |
| export const onErrorFilter: { | |
| <A, E, EB, X, XE, XR>( | |
| filter: Filter.Filter<Cause.Cause<E>, EB, X>, | |
| f: (failure: EB, cause: Cause.Cause<E>) => Effect.Effect<void, XE, XR> | |
| ): <R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR> | |
| <A, E, R, EB, X, XE, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<Cause.Cause<E>, EB, X>, | |
| f: (failure: EB, cause: Cause.Cause<E>) => Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> | |
| } = dual( | |
| 3, | |
| <A, E, R, EB, X, XE, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<Cause.Cause<E>, EB, X>, | |
| f: (failure: EB, cause: Cause.Cause<E>) => Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> => | |
| onExit(self, (exit) => { | |
| if (exit._tag !== "Failure") { | |
| return void_ | |
| } | |
| const result = filter(exit.cause) | |
| return Result.isFailure(result) ? void_ : f(result.success, exit.cause) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const onInterrupt: { | |
| <XE, XR>( | |
| finalizer: (interruptors: ReadonlySet<number>) => Effect.Effect<void, XE, XR> | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | XE, R | XR> | |
| <A, E, R, XE, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| finalizer: (interruptors: ReadonlySet<number>) => Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> | |
| } = dual( | |
| 2, | |
| <A, E, R, XE, XR>( | |
| self: Effect.Effect<A, E, R>, | |
| finalizer: (interruptors: ReadonlySet<number>) => Effect.Effect<void, XE, XR> | |
| ): Effect.Effect<A, E | XE, R | XR> => onErrorFilter(causeFilterInterruptors as any, finalizer)(self) as any | |
| ) | |
| /** @internal */ | |
| export const acquireUseRelease = <Resource, E, R, A, E2, R2, E3, R3>( | |
| acquire: Effect.Effect<Resource, E, R>, | |
| use: (a: Resource) => Effect.Effect<A, E2, R2>, | |
| release: (a: Resource, exit: Exit.Exit<A, E2>) => Effect.Effect<void, E3, R3> | |
| ): Effect.Effect<A, E | E2 | E3, R | R2 | R3> => | |
| uninterruptibleMask((restore) => | |
| flatMap(acquire, (a) => | |
| onExitPrimitive( | |
| restore(use(a)), | |
| (exit) => release(a, exit), | |
| true | |
| )) | |
| ) | |
| /** @internal */ | |
| export const acquireDisposable = <A extends AsyncDisposable | Disposable, E, R>( | |
| acquire: Effect.Effect<A, E, R> | |
| ): Effect.Effect<A, E, R | Scope.Scope> => | |
| acquireRelease(acquire, (resource) => | |
| hasProperty(resource, Symbol.asyncDispose) | |
| ? promise(() => resource[Symbol.asyncDispose]()) | |
| : sync(() => resource[Symbol.dispose]())) | |
| // ---------------------------------------------------------------------------- | |
| // Caching | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const cachedInvalidateWithTTL: { | |
| (timeToLive: Duration.Input): <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<[Effect.Effect<A, E, R>, Effect.Effect<void>]> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| timeToLive: Duration.Input | |
| ): Effect.Effect<[Effect.Effect<A, E, R>, Effect.Effect<void>]> | |
| } = dual(2, <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| ttl: Duration.Input | |
| ): Effect.Effect<[Effect.Effect<A, E, R>, Effect.Effect<void>]> => | |
| sync(() => { | |
| const ttlMillis = Duration.toMillis(Duration.fromInputUnsafe(ttl)) | |
| const isFinite = Number.isFinite(ttlMillis) | |
| const latch = makeLatchUnsafe(false) | |
| let expiresAt = 0 | |
| let running = false | |
| let exit: Exit.Exit<A, E> | undefined | |
| const wait = flatMap(latch.await, () => exit!) | |
| return [ | |
| withFiber((fiber) => { | |
| const clock = fiber.getRef(ClockRef) | |
| const now = isFinite ? clock.currentTimeMillisUnsafe() : 0 | |
| if (running || now < expiresAt) return exit ?? wait | |
| running = true | |
| latch.closeUnsafe() | |
| exit = undefined | |
| return onExit(self, (exit_) => | |
| sync(() => { | |
| running = false | |
| expiresAt = clock.currentTimeMillisUnsafe() + ttlMillis | |
| exit = exit_ | |
| latch.openUnsafe() | |
| })) | |
| }), | |
| sync(() => { | |
| expiresAt = 0 | |
| latch.closeUnsafe() | |
| exit = undefined | |
| }) | |
| ] | |
| })) | |
| /** @internal */ | |
| export const cachedWithTTL: { | |
| ( | |
| timeToLive: Duration.Input | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Effect.Effect<A, E, R>> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| timeToLive: Duration.Input | |
| ): Effect.Effect<Effect.Effect<A, E, R>> | |
| } = dual( | |
| 2, | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| timeToLive: Duration.Input | |
| ): Effect.Effect<Effect.Effect<A, E, R>> => map(cachedInvalidateWithTTL(self, timeToLive), (tuple) => tuple[0]) | |
| ) | |
| /** @internal */ | |
| export const cached = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<Effect.Effect<A, E, R>> => | |
| cachedWithTTL(self, Duration.infinity) | |
| // ---------------------------------------------------------------------------- | |
| // interruption | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const interrupt: Effect.Effect<never> = withFiber((fiber) => failCause(causeInterrupt(fiber.id))) | |
| /** @internal */ | |
| export const uninterruptible = <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ): Effect.Effect<A, E, R> => | |
| withFiber((fiber) => { | |
| if (!fiber.interruptible) return self | |
| fiber.interruptible = false | |
| fiber._stack.push(setInterruptibleTrue) | |
| return self | |
| }) | |
| const setInterruptible: (interruptible: boolean) => Primitive = makePrimitive({ | |
| op: "SetInterruptible", | |
| [contAll](fiber) { | |
| fiber.interruptible = this[args] | |
| if (fiber._interruptedCause && fiber.interruptible) { | |
| return () => failCause(fiber._interruptedCause!) | |
| } | |
| } | |
| }) | |
| const setInterruptibleTrue = setInterruptible(true) | |
| const setInterruptibleFalse = setInterruptible(false) | |
| /** @internal */ | |
| export const interruptible = <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ): Effect.Effect<A, E, R> => | |
| withFiber((fiber) => { | |
| if (fiber.interruptible) return self | |
| fiber.interruptible = true | |
| fiber._stack.push(setInterruptibleFalse) | |
| if (fiber._interruptedCause) return failCause(fiber._interruptedCause) | |
| return self | |
| }) | |
| /** @internal */ | |
| export const uninterruptibleMask = <A, E, R>( | |
| f: ( | |
| restore: <A, E, R>( | |
| effect: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A, E, R> | |
| ): Effect.Effect<A, E, R> => | |
| withFiber((fiber) => { | |
| if (!fiber.interruptible) return f(identity) | |
| fiber.interruptible = false | |
| fiber._stack.push(setInterruptibleTrue) | |
| return f(interruptible) | |
| }) | |
| /** @internal */ | |
| export const interruptibleMask = <A, E, R>( | |
| f: ( | |
| restore: <A, E, R>( | |
| effect: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A, E, R> | |
| ) => Effect.Effect<A, E, R> | |
| ): Effect.Effect<A, E, R> => | |
| withFiber((fiber) => { | |
| if (fiber.interruptible) return f(identity) | |
| fiber.interruptible = true | |
| fiber._stack.push(setInterruptibleFalse) | |
| return f(uninterruptible) | |
| }) | |
| /** @internal */ | |
| export const abortSignal: Effect.Effect<AbortSignal, never, Scope.Scope> = map( | |
| acquireRelease( | |
| sync(() => new AbortController()), | |
| (controller) => sync(() => controller.abort()) | |
| ), | |
| (_) => _.signal | |
| ) | |
| // ======================================================================== | |
| // collecting & elements | |
| // ======================================================================== | |
| /** @internal */ | |
| export const all = < | |
| const Arg extends | |
| | Iterable<Effect.Effect<any, any, any>> | |
| | Record<string, Effect.Effect<any, any, any>>, | |
| O extends { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard?: boolean | undefined | |
| readonly mode?: "default" | "result" | undefined | |
| } | |
| >( | |
| arg: Arg, | |
| options?: O | |
| ): Effect.All.Return<Arg, O> => { | |
| if (isIterable(arg)) { | |
| return options?.mode === "result" | |
| ? (forEach as any)(arg, result, options) | |
| : (forEach as any)(arg, identity, options) | |
| } else if (options?.discard) { | |
| return options.mode === "result" | |
| ? (forEach as any)(Object.values(arg), result, options) | |
| : (forEach as any)(Object.values(arg), identity, options) | |
| } | |
| return suspend(() => { | |
| const out: Record<string, unknown> = {} | |
| return as( | |
| forEach( | |
| Object.entries(arg), | |
| ([key, effect]) => | |
| map(options?.mode === "result" ? result(effect) : effect, (value) => { | |
| out[key] = value | |
| }), | |
| { | |
| discard: true, | |
| concurrency: options?.concurrency | |
| } | |
| ), | |
| out | |
| ) | |
| }) as any | |
| } | |
| /** @internal */ | |
| export const partition: { | |
| <A, B, E, R>( | |
| f: (a: A, i: number) => Effect.Effect<B, E, R>, | |
| options?: { readonly concurrency?: Concurrency | undefined } | |
| ): (elements: Iterable<A>) => Effect.Effect<[excluded: Array<E>, satisfying: Array<B>], never, R> | |
| <A, B, E, R>( | |
| elements: Iterable<A>, | |
| f: (a: A, i: number) => Effect.Effect<B, E, R>, | |
| options?: { readonly concurrency?: Concurrency | undefined } | |
| ): Effect.Effect<[excluded: Array<E>, satisfying: Array<B>], never, R> | |
| } = dual( | |
| (args) => isIterable(args[0]) && !isEffect(args[0]), | |
| <A, B, E, R>( | |
| elements: Iterable<A>, | |
| f: (a: A, i: number) => Effect.Effect<B, E, R>, | |
| options?: { readonly concurrency?: Concurrency | undefined } | |
| ): Effect.Effect<[excluded: Array<E>, satisfying: Array<B>], never, R> => | |
| map( | |
| forEach(elements, (a, i) => result(f(a, i)), options), | |
| (results) => Arr.partition(results, identity) | |
| ) | |
| ) | |
| /** @internal */ | |
| export const validate: { | |
| <A, B, E, R>( | |
| f: (a: A, i: number) => Effect.Effect<B, E, R>, | |
| options?: { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard?: false | undefined | |
| } | undefined | |
| ): (elements: Iterable<A>) => Effect.Effect<Array<B>, Arr.NonEmptyArray<E>, R> | |
| <A, B, E, R>( | |
| f: (a: A, i: number) => Effect.Effect<B, E, R>, | |
| options: { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard: true | |
| } | |
| ): (elements: Iterable<A>) => Effect.Effect<void, Arr.NonEmptyArray<E>, R> | |
| <A, B, E, R>( | |
| elements: Iterable<A>, | |
| f: (a: A, i: number) => Effect.Effect<B, E, R>, | |
| options?: { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard?: false | undefined | |
| } | undefined | |
| ): Effect.Effect<Array<B>, Arr.NonEmptyArray<E>, R> | |
| <A, B, E, R>( | |
| elements: Iterable<A>, | |
| f: (a: A, i: number) => Effect.Effect<B, E, R>, | |
| options: { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard: true | |
| } | |
| ): Effect.Effect<void, Arr.NonEmptyArray<E>, R> | |
| } = dual( | |
| (args) => isIterable(args[0]) && !isEffect(args[0]), | |
| <A, B, E, R>( | |
| elements: Iterable<A>, | |
| f: (a: A, i: number) => Effect.Effect<B, E, R>, | |
| options?: { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard?: boolean | undefined | |
| } | undefined | |
| ): Effect.Effect<Array<B> | void, Arr.NonEmptyArray<E>, R> => | |
| flatMap( | |
| partition(elements, f, { concurrency: options?.concurrency }), | |
| ([excluded, satisfying]) => { | |
| if (Arr.isArrayNonEmpty(excluded)) { | |
| return fail(excluded) | |
| } | |
| return options?.discard ? void_ : succeed(satisfying) | |
| } | |
| ) | |
| ) | |
| /** @internal */ | |
| export const findFirst: { | |
| <A, E, R>( | |
| predicate: (a: NoInfer<A>, i: number) => Effect.Effect<boolean, E, R> | |
| ): (elements: Iterable<A>) => Effect.Effect<Option.Option<A>, E, R> | |
| <A, E, R>( | |
| elements: Iterable<A>, | |
| predicate: (a: NoInfer<A>, i: number) => Effect.Effect<boolean, E, R> | |
| ): Effect.Effect<Option.Option<A>, E, R> | |
| } = dual( | |
| (args) => isIterable(args[0]) && !isEffect(args[0]), | |
| <A, E, R>( | |
| elements: Iterable<A>, | |
| predicate: (a: A, i: number) => Effect.Effect<boolean, E, R> | |
| ): Effect.Effect<Option.Option<A>, E, R> => | |
| suspend(() => { | |
| const iterator = elements[Symbol.iterator]() | |
| const next = iterator.next() | |
| if (!next.done) { | |
| return findFirstLoop(iterator, 0, predicate, next.value) | |
| } | |
| return succeed(Option.none()) | |
| }) | |
| ) | |
| const findFirstLoop = <A, E, R>( | |
| iterator: Iterator<A>, | |
| index: number, | |
| predicate: (a: A, i: number) => Effect.Effect<boolean, E, R>, | |
| value: A | |
| ): Effect.Effect<Option.Option<A>, E, R> => | |
| flatMap(predicate(value, index), (keep) => { | |
| if (keep) { | |
| return succeed(Option.some(value)) | |
| } | |
| const next = iterator.next() | |
| if (!next.done) { | |
| return findFirstLoop(iterator, index + 1, predicate, next.value) | |
| } | |
| return succeed(Option.none()) | |
| }) | |
| /** @internal */ | |
| export const findFirstFilter: { | |
| <A, B, X, E, R>( | |
| filter: (input: NoInfer<A>, i: number) => Effect.Effect<Result.Result<B, X>, E, R> | |
| ): (elements: Iterable<A>) => Effect.Effect<Option.Option<B>, E, R> | |
| <A, B, X, E, R>( | |
| elements: Iterable<A>, | |
| filter: (input: NoInfer<A>, i: number) => Effect.Effect<Result.Result<B, X>, E, R> | |
| ): Effect.Effect<Option.Option<B>, E, R> | |
| } = dual( | |
| (args) => isIterable(args[0]) && !isEffect(args[0]), | |
| <A, B, X, E, R>( | |
| elements: Iterable<A>, | |
| filter: (input: A, i: number) => Effect.Effect<Result.Result<B, X>, E, R> | |
| ): Effect.Effect<Option.Option<B>, E, R> => | |
| suspend(() => { | |
| const iterator = elements[Symbol.iterator]() | |
| const next = iterator.next() | |
| if (!next.done) { | |
| return findFirstFilterLoop(iterator, 0, filter, next.value) | |
| } | |
| return succeed(Option.none()) | |
| }) | |
| ) | |
| const findFirstFilterLoop = <A, B, X, E, R>( | |
| iterator: Iterator<A>, | |
| index: number, | |
| filter: (input: A, i: number) => Effect.Effect<Result.Result<B, X>, E, R>, | |
| value: A | |
| ): Effect.Effect<Option.Option<B>, E, R> => | |
| flatMap(filter(value, index), (result) => { | |
| if (Result.isSuccess(result)) { | |
| return succeed(Option.some(result.success)) | |
| } | |
| const next = iterator.next() | |
| if (!next.done) { | |
| return findFirstFilterLoop(iterator, index + 1, filter, next.value) | |
| } | |
| return succeed(Option.none()) | |
| }) | |
| /** @internal */ | |
| export const whileLoop: <A, E, R>(options: { | |
| readonly while: LazyArg<boolean> | |
| readonly body: LazyArg<Effect.Effect<A, E, R>> | |
| readonly step: (a: A) => void | |
| }) => Effect.Effect<void, E, R> = makePrimitive({ | |
| op: "While", | |
| [contA](value, fiber) { | |
| this[args].step(value) | |
| if (this[args].while()) { | |
| fiber._stack.push(this) | |
| return this[args].body() | |
| } | |
| return exitVoid | |
| }, | |
| [evaluate](fiber) { | |
| if (this[args].while()) { | |
| fiber._stack.push(this) | |
| return this[args].body() | |
| } | |
| return exitVoid | |
| } | |
| }) | |
| /** @internal */ | |
| export const forEach: { | |
| <B, E, R, S extends Iterable<any>, const Discard extends boolean = false>( | |
| f: (a: Arr.ReadonlyArray.Infer<S>, i: number) => Effect.Effect<B, E, R>, | |
| options?: { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard?: Discard | undefined | |
| } | undefined | |
| ): ( | |
| self: S | |
| ) => Effect.Effect<Discard extends false ? Arr.ReadonlyArray.With<S, B> : void, E, R> | |
| <B, E, R, S extends Iterable<any>, const Discard extends boolean = false>( | |
| self: S, | |
| f: (a: Arr.ReadonlyArray.Infer<S>, i: number) => Effect.Effect<B, E, R>, | |
| options?: { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard?: Discard | undefined | |
| } | undefined | |
| ): Effect.Effect<Discard extends false ? Arr.ReadonlyArray.With<S, B> : void, E, R> | |
| } = dual((args) => typeof args[1] === "function", <A, B, E, R>( | |
| iterable: Iterable<A>, | |
| f: (a: A, index: number) => Effect.Effect<B, E, R>, | |
| options?: { | |
| readonly concurrency?: Concurrency | undefined | |
| readonly discard?: boolean | undefined | |
| } | |
| ): Effect.Effect<any, E, R> => | |
| withFiber((parent) => { | |
| const concurrencyOption = options?.concurrency === "inherit" | |
| ? parent.getRef(CurrentConcurrency) | |
| : (options?.concurrency ?? 1) | |
| const concurrency = concurrencyOption === "unbounded" | |
| ? Number.POSITIVE_INFINITY | |
| : Math.max(1, concurrencyOption) | |
| if (concurrency === 1) { | |
| return forEachSequential(iterable, f, options) | |
| } | |
| const items = Arr.fromIterable(iterable) | |
| let length = items.length | |
| if (length === 0) { | |
| return options?.discard ? void_ : succeed([]) | |
| } | |
| const out: Array<B> | undefined = options?.discard | |
| ? undefined | |
| : new Array(length) | |
| const eff = forEachConcurrent({ f, out }, items, { concurrency }) | |
| return eff ? as(eff, out as any) : succeed(out as any) | |
| })) | |
| const forEachSequential = <A, B, E, R>( | |
| iterable: Iterable<A>, | |
| f: (a: A, index: number) => Effect.Effect<B, E, R>, | |
| options?: { | |
| readonly discard?: boolean | undefined | |
| } | |
| ) => | |
| suspend(() => { | |
| const out: Array<B> | undefined = options?.discard ? undefined : [] | |
| const iterator = iterable[Symbol.iterator]() | |
| let state = iterator.next() | |
| let index = 0 | |
| return as( | |
| whileLoop({ | |
| while: () => !state.done, | |
| body: () => f(state.value!, index++), | |
| step: (b) => { | |
| if (out) out.push(b) | |
| state = iterator.next() | |
| } | |
| }), | |
| out | |
| ) | |
| }) | |
| const iterateEagerImpl = <S, A, X, E, R, E2>(options: { | |
| readonly onItem: (state: S, item: A, index: number) => Effect.Effect<X, E, R> | |
| readonly step: (state: NoInfer<S>, item: A, exit: Exit.Exit<X, E>, index: number) => Exit.Exit<void, E2> | void | |
| }): ( | |
| initialState: S, | |
| items: ReadonlyArray<A>, | |
| options?: { | |
| readonly concurrency?: number | undefined | |
| readonly start?: number | undefined | |
| readonly end?: number | undefined | |
| } | |
| ) => Effect.Effect<void, E | E2, R> | undefined => { | |
| const onItem = options.onItem | |
| const step = options.step | |
| return ( | |
| state: S, | |
| items: ReadonlyArray<A>, | |
| opts: { | |
| readonly concurrency?: number | undefined | |
| readonly start?: number | undefined | |
| readonly end?: number | undefined | |
| } | undefined | |
| ): Effect.Effect<void, E | E2, R> | undefined => { | |
| let index = opts?.start ?? 0 | |
| const end = opts?.end ?? items.length | |
| const concurrency = opts?.concurrency ?? 1 | |
| let done = false | |
| let parentFiber: Fiber.Fiber<any, any> | undefined | |
| let fibers: Set<Fiber.Fiber<any, any>> | undefined | |
| let resume: ((effect: Effect.Effect<void, E | E2, R>) => void) | undefined | |
| let interrupted = false | |
| let terminal: Exit.Exit<void, E | E2> | void | |
| let effect: Effect.Effect<X, E, R> | undefined | |
| const go = (): Effect.Effect<void, E | E2, R> | undefined => { | |
| let paused = false | |
| for (; !terminal && index < end; index++) { | |
| const item = items[index] | |
| const eff = effect ?? onItem(state, item, index) | |
| // fast case (already an exit) | |
| if (effectIsExit(eff)) { | |
| terminal = step(state, item, eff, index) | |
| if (terminal) break | |
| // Use flatMap for concurrency of 1 | |
| } else if (concurrency === 1) { | |
| return flatMap(exit(eff), (exit) => { | |
| terminal = step(state, item, exit, index) | |
| index++ | |
| return terminal ?? go() ?? void_ | |
| }) | |
| // We have an effect, so enter "async" mode | |
| } else if (!parentFiber) { | |
| return callback((cb) => { | |
| parentFiber = getCurrentFiber()! | |
| effect = eff | |
| resume = cb | |
| const result = go() | |
| if (result) return cb(result) | |
| return suspend(() => { | |
| terminal = exitVoid | |
| interrupted = true | |
| return fibers ? fiberInterruptAll(fibers) : void_ | |
| }) | |
| }) | |
| // Fork the effect with concurrency > 1 | |
| } else { | |
| // Clear the temporary effect from capturing the parentFiber | |
| effect = undefined | |
| const fiber = forkUnsafe(parentFiber, eff, true, true, "inherit") | |
| if (fiber._exit) { | |
| terminal = step(state, item, fiber._exit, index) | |
| if (terminal) break | |
| continue | |
| } | |
| // Add the fiber to the Set | |
| if (fibers) fibers.add(fiber) | |
| else fibers = new Set([fiber]) | |
| const currentIndex = index | |
| fiber.addObserver((exit) => { | |
| fibers!.delete(fiber) | |
| if (terminal) { | |
| if (!interrupted && exit._tag === "Failure") { | |
| for (const reason of exit.cause.reasons) { | |
| if (reason._tag === "Interrupt") continue | |
| else if (terminal._tag === "Failure") { | |
| ;(terminal.cause.reasons as Array<any>).push(reason) | |
| } else { | |
| terminal = exitFailCause(causeFromReasons([reason])) | |
| } | |
| } | |
| } | |
| } else { | |
| const result = step(state, item, exit, currentIndex) | |
| if (result) { | |
| terminal = result._tag === "Failure" | |
| ? exitFailCause(causeFromReasons(result.cause.reasons.slice())) | |
| : result | |
| go() | |
| } | |
| } | |
| if (paused) { | |
| const eff = go() | |
| if (eff) resume!(eff) | |
| } else if (done && fibers!.size === 0) { | |
| resume!(terminal ?? void_) | |
| } | |
| }) | |
| // Check if we have reached the concurrency limit | |
| if (fibers.size < concurrency) continue | |
| paused = true | |
| index++ | |
| return | |
| } | |
| } | |
| done = true | |
| if (terminal) { | |
| if (fibers && fibers.size > 0) { | |
| const annotations = fiberStackAnnotations(parentFiber!) | |
| fibers.forEach((f) => f.interruptUnsafe(parentFiber!.id, annotations)) | |
| return | |
| } | |
| if (resume || terminal._tag === "Failure") { | |
| return terminal | |
| } | |
| } else if (resume) { | |
| if (!fibers) { | |
| return exitVoid | |
| } else if (fibers.size === 0) { | |
| resume(void_) | |
| } | |
| } | |
| } | |
| return go() | |
| } | |
| } | |
| /** @internal */ | |
| export const iterateEager = <S, A>(): <X, E, R, E2>(options: { | |
| readonly onItem: (state: S, item: A, index: number) => Effect.Effect<X, E, R> | |
| readonly step: (state: NoInfer<S>, item: A, exit: Exit.Exit<X, E>, index: number) => Exit.Exit<void, E2> | void | |
| }) => ( | |
| initialState: S, | |
| items: ReadonlyArray<A>, | |
| options?: { | |
| readonly concurrency?: number | undefined | |
| readonly start?: number | undefined | |
| readonly end?: number | undefined | |
| } | |
| ) => Effect.Effect<void, E | E2, R> | undefined => iterateEagerImpl | |
| const forEachConcurrent = iterateEagerImpl({ | |
| onItem( | |
| state: { | |
| readonly f: (a: any, i: number) => Effect.Effect<any, any, any> | |
| readonly out: Array<any> | undefined | |
| }, | |
| item, | |
| index | |
| ) { | |
| return state.f(item, index) | |
| }, | |
| step(state, _, exit, index) { | |
| if (exit._tag === "Failure") return exit | |
| else if (state.out) { | |
| state.out[index] = exit.value | |
| } | |
| } | |
| }) | |
| /* @internal */ | |
| export const filterOrElse: { | |
| <A, C, E2, R2, B extends A>( | |
| refinement: Predicate.Refinement<NoInfer<A>, B>, | |
| orElse: (a: EqualsWith<A, B, NoInfer<A>, Exclude<NoInfer<A>, B>>) => Effect.Effect<C, E2, R2> | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B | C, E2 | E, R2 | R> | |
| <A, C, E2, R2>( | |
| predicate: Predicate.Predicate<NoInfer<A>>, | |
| orElse: (a: NoInfer<A>) => Effect.Effect<C, E2, R2> | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A | C, E2 | E, R2 | R> | |
| <A, E, R, C, E2, R2, B extends A>( | |
| self: Effect.Effect<A, E, R>, | |
| refinement: Predicate.Refinement<A, B>, | |
| orElse: (a: EqualsWith<A, B, A, Exclude<A, B>>) => Effect.Effect<C, E2, R2> | |
| ): Effect.Effect<B | C, E | E2, R | R2> | |
| <A, E, R, C, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<NoInfer<A>>, | |
| orElse: (a: NoInfer<A>) => Effect.Effect<C, E2, R2> | |
| ): Effect.Effect<A | C, E | E2, R | R2> | |
| } = dual(3, <A, E, R, B, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| predicate: Predicate.Predicate<A>, | |
| orElse: (a: A) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<A | B, E | E2, R | R2> => | |
| flatMap( | |
| self, | |
| (a) => predicate(a) ? succeed<A | B>(a) : orElse(a) | |
| )) | |
| /** @internal */ | |
| export const filterMapOrElse: { | |
| <A, B, X, C, E2, R2>( | |
| filter: Filter.Filter<NoInfer<A>, B, X>, | |
| orElse: (x: X) => Effect.Effect<C, E2, R2> | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B | C, E2 | E, R2 | R> | |
| <A, E, R, B, X, C, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<NoInfer<A>, B, X>, | |
| orElse: (x: X) => Effect.Effect<C, E2, R2> | |
| ): Effect.Effect<B | C, E | E2, R | R2> | |
| } = dual(3, <A, E, R, B, X, C, E2, R2>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<NoInfer<A>, B, X>, | |
| orElse: (x: X) => Effect.Effect<C, E2, R2> | |
| ): Effect.Effect<B | C, E | E2, R | R2> => | |
| flatMap( | |
| self, | |
| (a) => { | |
| const result = filter(a) | |
| return (Result.isFailure(result) | |
| ? orElse(result.failure) | |
| : succeed(result.success)) as Effect.Effect<B | C, E2, R2> | |
| } | |
| )) | |
| /* @internal */ | |
| export const filterMapOrFail: { | |
| <A, B, X, E2>( | |
| filter: Filter.Filter<NoInfer<A>, B, X>, | |
| orFailWith: (x: X) => E2 | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E2 | E, R> | |
| <A, B, X>( | |
| filter: Filter.Filter<NoInfer<A>, B, X> | |
| ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, Cause.NoSuchElementError | E, R> | |
| <A, E, R, B, X, E2>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<NoInfer<A>, B, X>, | |
| orFailWith: (x: X) => E2 | |
| ): Effect.Effect<B, E2 | E, R> | |
| <A, E, R, B, X>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<NoInfer<A>, B, X> | |
| ): Effect.Effect<B, Cause.NoSuchElementError | E, R> | |
| } = dual((args) => isEffect(args[0]), <A, E, R, B, X, E2>( | |
| self: Effect.Effect<A, E, R>, | |
| filter: Filter.Filter<NoInfer<A>, B, X>, | |
| orFailWith?: (x: X) => E2 | |
| ): Effect.Effect<B, E2 | Cause.NoSuchElementError | E, R> => | |
| filterMapOrElse( | |
| self, | |
| filter, | |
| orFailWith ? (x: X) => fail(orFailWith(x)) : () => fail(new NoSuchElementError() as E2) | |
| )) | |
| /** @internal */ | |
| export const filter: { | |
| <A, B extends A>( | |
| refinement: Predicate.Refinement<NoInfer<A>, B> | |
| ): (elements: Iterable<A>) => Effect.Effect<Array<B>> | |
| <A>( | |
| predicate: Predicate.Predicate<NoInfer<A>> | |
| ): (elements: Iterable<A>) => Effect.Effect<Array<A>> | |
| <A, E, R>( | |
| predicate: (a: NoInfer<A>, i: number) => Effect.Effect<boolean, E, R>, | |
| options?: { readonly concurrency?: Concurrency | undefined } | |
| ): (iterable: Iterable<A>) => Effect.Effect<Array<A>, E, R> | |
| <A, B extends A>( | |
| elements: Iterable<A>, | |
| refinement: Predicate.Refinement<A, B> | |
| ): Effect.Effect<Array<B>> | |
| <A>( | |
| elements: Iterable<A>, | |
| predicate: Predicate.Predicate<A> | |
| ): Effect.Effect<Array<A>> | |
| <A, E, R>( | |
| iterable: Iterable<A>, | |
| predicate: (a: NoInfer<A>, i: number) => Effect.Effect<boolean, E, R>, | |
| options?: { readonly concurrency?: Concurrency | undefined } | |
| ): Effect.Effect<Array<A>, E, R> | |
| } = dual( | |
| (args) => isIterable(args[0]) && !isEffect(args[0]), | |
| <A, E, R>( | |
| elements: Iterable<A>, | |
| predicate: | |
| | Predicate.Predicate<A> | |
| | ((a: A, i: number) => Effect.Effect<boolean, E, R>), | |
| options?: { readonly concurrency?: Concurrency | undefined } | |
| ): Effect.Effect<Array<A>, E, R> => | |
| suspend(() => { | |
| const out: Array<A> = [] | |
| return as( | |
| forEach( | |
| elements, | |
| (a, i) => { | |
| const result = (predicate as Function)(a, i) | |
| if (typeof result === "boolean") { | |
| if (result) out.push(a) | |
| return void_ as any | |
| } | |
| return map(result, (keep) => { | |
| if (keep) { | |
| out.push(a) | |
| } | |
| }) | |
| }, | |
| { | |
| discard: true, | |
| concurrency: options?.concurrency | |
| } | |
| ), | |
| out | |
| ) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const filterMap: { | |
| <A, B, X>( | |
| filter: Filter.Filter<NoInfer<A>, B, X> | |
| ): (elements: Iterable<A>) => Effect.Effect<Array<B>> | |
| <A, B, X>( | |
| elements: Iterable<A>, | |
| filter: Filter.Filter<NoInfer<A>, B, X> | |
| ): Effect.Effect<Array<B>> | |
| } = dual( | |
| (args) => isIterable(args[0]) && !isEffect(args[0]), | |
| <A, B, X>( | |
| elements: Iterable<A>, | |
| filter: Filter.Filter<A, B, X> | |
| ): Effect.Effect<Array<B>> => | |
| suspend(() => { | |
| const out: Array<B> = [] | |
| for (const a of elements) { | |
| const result = filter(a) | |
| if (Result.isSuccess(result)) { | |
| out.push(result.success) | |
| } | |
| } | |
| return succeed(out) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const filterMapEffect: { | |
| <A, B, X, E, R>( | |
| filter: Filter.FilterEffect<NoInfer<A>, B, X, E, R>, | |
| options?: { readonly concurrency?: Concurrency | undefined } | |
| ): (elements: Iterable<A>) => Effect.Effect<Array<B>, E, R> | |
| <A, B, X, E, R>( | |
| elements: Iterable<A>, | |
| filter: Filter.FilterEffect<NoInfer<A>, B, X, E, R>, | |
| options?: { readonly concurrency?: Concurrency | undefined } | |
| ): Effect.Effect<Array<B>, E, R> | |
| } = dual( | |
| (args) => isIterable(args[0]) && !isEffect(args[0]), | |
| <A, B, X, E, R>( | |
| elements: Iterable<A>, | |
| filter: Filter.FilterEffect<A, B, X, E, R>, | |
| options?: { readonly concurrency?: Concurrency | undefined } | |
| ): Effect.Effect<Array<B>, E, R> => | |
| suspend(() => { | |
| const out: Array<B> = [] | |
| return as( | |
| forEach( | |
| elements, | |
| (a) => | |
| map(filter(a), (result) => { | |
| if (Result.isSuccess(result)) { | |
| out.push(result.success) | |
| } | |
| }), | |
| { | |
| discard: true, | |
| concurrency: options?.concurrency | |
| } | |
| ), | |
| out | |
| ) | |
| }) | |
| ) | |
| // ---------------------------------------------------------------------------- | |
| // do notation | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const Do: Effect.Effect<{}> = succeed({}) | |
| /** @internal */ | |
| export const bindTo: { | |
| <N extends string>( | |
| name: N | |
| ): <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<Record<N, A>, E, R> | |
| <A, E, R, N extends string>( | |
| self: Effect.Effect<A, E, R>, | |
| name: N | |
| ): Effect.Effect<Record<N, A>, E, R> | |
| } = doNotation.bindTo<Effect.EffectTypeLambda>(map) | |
| /** @internal */ | |
| export const bind: { | |
| <N extends string, A extends Record<string, any>, B, E2, R2>( | |
| name: N, | |
| f: (a: NoInfer<A>) => Effect.Effect<B, E2, R2> | |
| ): <E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<Simplify<Omit<A, N> & Record<N, B>>, E | E2, R | R2> | |
| <A extends Record<string, any>, E, R, B, E2, R2, N extends string>( | |
| self: Effect.Effect<A, E, R>, | |
| name: N, | |
| f: (a: NoInfer<A>) => Effect.Effect<B, E2, R2> | |
| ): Effect.Effect<Simplify<Omit<A, N> & Record<N, B>>, E | E2, R | R2> | |
| } = doNotation.bind<Effect.EffectTypeLambda>(map, flatMap) | |
| /** @internal */ | |
| const let_: { | |
| <N extends string, A extends Record<string, any>, B>( | |
| name: N, | |
| f: (a: NoInfer<A>) => B | |
| ): <E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<Simplify<Omit<A, N> & Record<N, B>>, E, R> | |
| <A extends Record<string, any>, E, R, B, N extends string>( | |
| self: Effect.Effect<A, E, R>, | |
| name: N, | |
| f: (a: NoInfer<A>) => B | |
| ): Effect.Effect<Simplify<Omit<A, N> & Record<N, B>>, E, R> | |
| } = doNotation.let_<Effect.EffectTypeLambda>(map) | |
| /** @internal */ | |
| export { let_ as let } | |
| // ---------------------------------------------------------------------------- | |
| // fibers & forking | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const forkChild: { | |
| < | |
| Arg extends Effect.Effect<any, any, any> | { | |
| readonly startImmediately?: boolean | undefined | |
| readonly uninterruptible?: boolean | "inherit" | undefined | |
| } | undefined = { | |
| readonly startImmediately?: boolean | undefined | |
| readonly uninterruptible?: boolean | "inherit" | undefined | |
| } | |
| >( | |
| effectOrOptions: Arg, | |
| options?: { | |
| readonly startImmediately?: boolean | undefined | |
| readonly uninterruptible?: boolean | "inherit" | undefined | |
| } | undefined | |
| ): [Arg] extends [Effect.Effect<infer _A, infer _E, infer _R>] ? Effect.Effect<Fiber.Fiber<_A, _E>, never, _R> | |
| : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Fiber.Fiber<A, E>, never, R> | |
| } = dual((args) => isEffect(args[0]), <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| options?: { | |
| readonly startImmediately?: boolean | |
| readonly uninterruptible?: boolean | "inherit" | |
| } | |
| ): Effect.Effect<Fiber.Fiber<A, E>, never, R> => | |
| withFiber((fiber) => { | |
| interruptChildrenPatch() | |
| return succeed(forkUnsafe( | |
| fiber, | |
| self, | |
| options?.startImmediately, | |
| false, | |
| options?.uninterruptible ?? false | |
| )) | |
| })) | |
| /** @internal */ | |
| export const forkUnsafe = <FA, FE, A, E, R>( | |
| parent: Fiber.Fiber<FA, FE>, | |
| effect: Effect.Effect<A, E, R>, | |
| immediate = false, | |
| daemon = false, | |
| uninterruptible: boolean | "inherit" = false | |
| ): FiberImpl<A, E> => { | |
| const interruptible = uninterruptible === "inherit" ? parent.interruptible : !uninterruptible | |
| const child = new FiberImpl<A, E>(parent.context, interruptible) | |
| if (immediate) { | |
| child.evaluate(effect as any) | |
| } else { | |
| parent.currentDispatcher.scheduleTask(() => child.evaluate(effect as any), 0) | |
| } | |
| if (!daemon && !child._exit) { | |
| parent.children().add(child) | |
| child.addObserver(() => parent._children!.delete(child)) | |
| } | |
| return child | |
| } | |
| /** @internal */ | |
| export const forkDetach: { | |
| < | |
| Arg extends Effect.Effect<any, any, any> | { | |
| readonly startImmediately?: boolean | undefined | |
| readonly uninterruptible?: boolean | "inherit" | undefined | |
| } | undefined = { | |
| readonly startImmediately?: boolean | undefined | |
| readonly uninterruptible?: boolean | "inherit" | undefined | |
| } | |
| >( | |
| effectOrOptions: Arg, | |
| options?: { | |
| readonly startImmediately?: boolean | undefined | |
| readonly uninterruptible?: boolean | "inherit" | undefined | |
| } | undefined | |
| ): [Arg] extends [Effect.Effect<infer _A, infer _E, infer _R>] ? Effect.Effect<Fiber.Fiber<_A, _E>, never, _R> | |
| : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Fiber.Fiber<A, E>, never, R> | |
| } = dual((args) => isEffect(args[0]), <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| options?: { | |
| readonly startImmediately?: boolean | |
| readonly uninterruptible?: boolean | "inherit" | undefined | |
| } | |
| ): Effect.Effect<Fiber.Fiber<A, E>, never, R> => | |
| withFiber((fiber) => succeed(forkUnsafe(fiber, self, options?.startImmediately, true, options?.uninterruptible)))) | |
| /** @internal */ | |
| export const awaitAllChildren = <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ): Effect.Effect<A, E, R> => | |
| withFiber((fiber) => { | |
| const initialChildren = fiber._children && Arr.fromIterable(fiber._children) | |
| return onExit( | |
| self, | |
| (_) => { | |
| let children = fiber._children | |
| if (children === undefined || children.size === 0) { | |
| return void_ | |
| } else if (initialChildren) { | |
| children = Iterable.filter( | |
| children, | |
| (child: FiberImpl<any, any>) => !initialChildren.includes(child) | |
| ) as Set<FiberImpl<any, any>> | |
| } | |
| return asVoid(fiberAwaitAll(children)) | |
| } | |
| ) | |
| }) | |
| /** @internal */ | |
| export const forkIn: { | |
| ( | |
| scope: Scope.Scope, | |
| options?: { | |
| readonly startImmediately?: boolean | undefined | |
| readonly uninterruptible?: boolean | "inherit" | undefined | |
| } | |
| ): <A, E, R>( | |
| self: Effect.Effect<A, E, R> | |
| ) => Effect.Effect<Fiber.Fiber<A, E>, never, R> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| scope: Scope.Scope, | |
| options?: { | |
| readonly startImmediately?: boolean | undefined | |
| readonly uninterruptible?: boolean | "inherit" | undefined | |
| } | |
| ): Effect.Effect<Fiber.Fiber<A, E>, never, R> | |
| } = dual( | |
| (args) => isEffect(args[0]), | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| scope: Scope.Scope, | |
| options?: { | |
| readonly startImmediately?: boolean | undefined | |
| readonly uninterruptible?: boolean | "inherit" | undefined | |
| } | |
| ): Effect.Effect<Fiber.Fiber<A, E>, never, R> => | |
| withFiber((parent) => { | |
| const fiber = forkUnsafe(parent, self, options?.startImmediately, true, options?.uninterruptible) | |
| if (!(fiber as FiberImpl<any, any>)._exit) { | |
| if (scope.state._tag !== "Closed") { | |
| const key = {} | |
| const finalizer = () => withFiberId((interruptor) => interruptor === fiber.id ? void_ : fiberInterrupt(fiber)) | |
| scopeAddFinalizerUnsafe(scope, key, finalizer) | |
| fiber.addObserver(() => scopeRemoveFinalizerUnsafe(scope, key)) | |
| } else { | |
| fiber.interruptUnsafe(parent.id, fiberStackAnnotations(parent)) | |
| } | |
| } | |
| return succeed(fiber) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const forkScoped: { | |
| < | |
| Arg extends Effect.Effect<any, any, any> | { | |
| readonly startImmediately?: boolean | undefined | |
| readonly uninterruptible?: boolean | "inherit" | undefined | |
| } | undefined = { | |
| readonly startImmediately?: boolean | undefined | |
| readonly uninterruptible?: boolean | "inherit" | undefined | |
| } | |
| >( | |
| effectOrOptions: Arg, | |
| options?: { | |
| readonly startImmediately?: boolean | undefined | |
| readonly uninterruptible?: boolean | "inherit" | undefined | |
| } | undefined | |
| ): [Arg] extends [Effect.Effect<infer _A, infer _E, infer _R>] ? | |
| Effect.Effect<Fiber.Fiber<_A, _E>, never, _R | Scope.Scope> | |
| : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Fiber.Fiber<A, E>, never, R | Scope.Scope> | |
| } = dual((args) => isEffect(args[0]), <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| options?: { | |
| readonly startImmediately?: boolean | |
| readonly uninterruptible?: boolean | "inherit" | |
| } | |
| ): Effect.Effect<Fiber.Fiber<A, E>, never, R | Scope.Scope> => flatMap(scope, (scope) => forkIn(self, scope, options))) | |
| // ---------------------------------------------------------------------------- | |
| // execution | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const runForkWith = <R>(context: Context.Context<R>) => | |
| <A, E>( | |
| effect: Effect.Effect<A, E, R>, | |
| options?: Effect.RunOptions | undefined | |
| ): Fiber.Fiber<A, E> => { | |
| const fiber = new FiberImpl<A, E>( | |
| options?.scheduler ? Context.add(context, Scheduler.Scheduler, options.scheduler) : context, | |
| options?.uninterruptible !== true | |
| ) | |
| fiber.evaluate(effect as any) | |
| if (fiber._exit) return fiber | |
| if (options?.signal) { | |
| if (options.signal.aborted) { | |
| fiber.interruptUnsafe() | |
| } else { | |
| const abort = () => fiber.interruptUnsafe() | |
| options.signal.addEventListener("abort", abort, { once: true }) | |
| fiber.addObserver(() => options.signal!.removeEventListener("abort", abort)) | |
| } | |
| } | |
| if (options?.onFiberStart) { | |
| options.onFiberStart(fiber) | |
| } | |
| return fiber | |
| } | |
| /** @internal */ | |
| export const fiberRunIn: { | |
| (scope: Scope.Scope): <A, E>(self: Fiber.Fiber<A, E>) => Fiber.Fiber<A, E> | |
| <A, E>( | |
| self: Fiber.Fiber<A, E>, | |
| scope: Scope.Scope | |
| ): Fiber.Fiber<A, E> | |
| } = dual(2, <A, E>( | |
| self: FiberImpl<A, E>, | |
| scope: Scope.Scope | |
| ): Fiber.Fiber<A, E> => { | |
| if (self._exit) { | |
| return self | |
| } else if (scope.state._tag === "Closed") { | |
| self.interruptUnsafe(self.id) | |
| return self | |
| } | |
| const key = {} | |
| scopeAddFinalizerUnsafe(scope, key, () => fiberInterrupt(self)) | |
| self.addObserver(() => scopeRemoveFinalizerUnsafe(scope, key)) | |
| return self | |
| }) | |
| /** @internal */ | |
| export const runFork: <A, E>( | |
| effect: Effect.Effect<A, E, never>, | |
| options?: Effect.RunOptions | undefined | |
| ) => Fiber.Fiber<A, E> = runForkWith(Context.empty()) | |
| /** @internal */ | |
| export const runCallbackWith = <R>(context: Context.Context<R>) => { | |
| const runFork = runForkWith(context) | |
| return <A, E>( | |
| effect: Effect.Effect<A, E, R>, | |
| options?: | |
| | Effect.RunOptions & { | |
| readonly onExit: (exit: Exit.Exit<A, E>) => void | |
| } | |
| | undefined | |
| ): (interruptor?: number | undefined) => void => { | |
| const fiber = runFork(effect, options) | |
| if (options?.onExit) { | |
| fiber.addObserver(options.onExit) | |
| } | |
| return (interruptor) => { | |
| return fiber.interruptUnsafe(interruptor) | |
| } | |
| } | |
| } | |
| /** @internal */ | |
| export const runCallback = runCallbackWith(Context.empty()) | |
| /** @internal */ | |
| export const runPromiseExitWith = <R>(context: Context.Context<R>) => { | |
| const runFork = runForkWith(context) | |
| return <A, E>( | |
| effect: Effect.Effect<A, E, R>, | |
| options?: Effect.RunOptions | undefined | |
| ): Promise<Exit.Exit<A, E>> => { | |
| const fiber = runFork(effect, options) | |
| return new Promise((resolve) => { | |
| fiber.addObserver((exit) => resolve(exit)) | |
| }) | |
| } | |
| } | |
| /** @internal */ | |
| export const runPromiseExit = runPromiseExitWith(Context.empty()) | |
| /** @internal */ | |
| export const runPromiseWith = <R>(context: Context.Context<R>) => { | |
| const runPromiseExit = runPromiseExitWith(context) | |
| return <A, E>( | |
| effect: Effect.Effect<A, E, R>, | |
| options?: | |
| | Effect.RunOptions | |
| | undefined | |
| ): Promise<A> => | |
| runPromiseExit(effect, options).then((exit) => { | |
| if (exit._tag === "Failure") { | |
| throw causeSquash(exit.cause) | |
| } | |
| return exit.value | |
| }) | |
| } | |
| /** @internal */ | |
| export const runPromise: <A, E>( | |
| effect: Effect.Effect<A, E>, | |
| options?: | |
| | Effect.RunOptions | |
| | undefined | |
| ) => Promise<A> = runPromiseWith(Context.empty()) | |
| /** @internal */ | |
| export const runSyncExitWith = <R>(context: Context.Context<R>) => { | |
| const runFork = runForkWith(context) | |
| return <A, E>(effect: Effect.Effect<A, E, R>): Exit.Exit<A, E> => { | |
| if (effectIsExit(effect)) return effect | |
| const scheduler = new Scheduler.MixedScheduler("sync") | |
| const fiber = runFork(effect, { scheduler }) | |
| fiber.currentDispatcher?.flush() | |
| return (fiber as FiberImpl<A, E>)._exit ?? exitDie(new AsyncFiberError(fiber)) | |
| } | |
| } | |
| /** @internal */ | |
| export const runSyncExit: <A, E>(effect: Effect.Effect<A, E>) => Exit.Exit<A, E> = runSyncExitWith( | |
| Context.empty() | |
| ) | |
| /** @internal */ | |
| export const runSyncWith = <R>(context: Context.Context<R>) => { | |
| const runSyncExit = runSyncExitWith(context) | |
| return <A, E>(effect: Effect.Effect<A, E, R>): A => { | |
| const exit = runSyncExit(effect) | |
| if (exit._tag === "Failure") throw causeSquash(exit.cause) | |
| return exit.value | |
| } | |
| } | |
| /** @internal */ | |
| export const runSync: <A, E>(effect: Effect.Effect<A, E>) => A = runSyncWith(Context.empty()) | |
| const succeedTrue = succeed(true) | |
| const succeedFalse = succeed(false) | |
| class Latch implements _Latch.Latch { | |
| waiters: Array<(_: Effect.Effect<void>) => void> = [] | |
| scheduled = false | |
| private isOpen: boolean | |
| constructor(isOpen: boolean) { | |
| this.isOpen = isOpen | |
| } | |
| private scheduleUnsafe(fiber: Fiber.Fiber<unknown, unknown>) { | |
| if (this.scheduled || this.waiters.length === 0) { | |
| return succeedTrue | |
| } | |
| this.scheduled = true | |
| fiber.currentDispatcher.scheduleTask(this.flushWaiters, 0) | |
| return succeedTrue | |
| } | |
| private flushWaiters = () => { | |
| this.scheduled = false | |
| const waiters = this.waiters | |
| this.waiters = [] | |
| for (let i = 0; i < waiters.length; i++) { | |
| waiters[i](exitVoid) | |
| } | |
| } | |
| open = withFiber<boolean>((fiber) => { | |
| if (this.isOpen) return succeedFalse | |
| this.isOpen = true | |
| return this.scheduleUnsafe(fiber) | |
| }) | |
| release = withFiber<boolean>((fiber) => this.isOpen ? succeedFalse : this.scheduleUnsafe(fiber)) | |
| openUnsafe() { | |
| if (this.isOpen) return false | |
| this.isOpen = true | |
| this.flushWaiters() | |
| return true | |
| } | |
| await = callback<void>((resume) => { | |
| if (this.isOpen) { | |
| return resume(void_) | |
| } | |
| this.waiters.push(resume) | |
| return sync(() => { | |
| const index = this.waiters.indexOf(resume) | |
| if (index !== -1) { | |
| this.waiters.splice(index, 1) | |
| } | |
| }) | |
| }) | |
| closeUnsafe() { | |
| if (!this.isOpen) return false | |
| this.isOpen = false | |
| return true | |
| } | |
| close = sync(() => this.closeUnsafe()) | |
| whenOpen = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> => flatMap(this.await, () => self) | |
| } | |
| /** @internal */ | |
| export const makeLatchUnsafe = (open?: boolean | undefined): _Latch.Latch => new Latch(open ?? false) | |
| /** @internal */ | |
| export const makeLatch = (open?: boolean | undefined) => sync(() => makeLatchUnsafe(open)) | |
| // ---------------------------------------------------------------------------- | |
| // Tracer | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const tracer: Effect.Effect<Tracer.Tracer> = withFiber((fiber) => succeed(fiber.getRef(Tracer.Tracer))) | |
| /** @internal */ | |
| export const withTracer: { | |
| (tracer: Tracer.Tracer): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> | |
| <A, E, R>(effect: Effect.Effect<A, E, R>, tracer: Tracer.Tracer): Effect.Effect<A, E, R> | |
| } = dual( | |
| 2, | |
| <A, E, R>(effect: Effect.Effect<A, E, R>, tracer: Tracer.Tracer): Effect.Effect<A, E, R> => | |
| provideService(effect, Tracer.Tracer, tracer) | |
| ) | |
| /** @internal */ | |
| export const withTracerEnabled: { | |
| (enabled: boolean): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> | |
| <A, E, R>(effect: Effect.Effect<A, E, R>, enabled: boolean): Effect.Effect<A, E, R> | |
| } = provideService(TracerEnabled) | |
| /** @internal */ | |
| export const withTracerTiming: { | |
| (enabled: boolean): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> | |
| <A, E, R>(effect: Effect.Effect<A, E, R>, enabled: boolean): Effect.Effect<A, E, R> | |
| } = provideService(TracerTimingEnabled) | |
| const bigint0 = BigInt(0) | |
| const NoopSpanProto: Omit<Tracer.Span, "parent" | "name" | "annotations" | "level"> = { | |
| _tag: "Span", | |
| spanId: "noop", | |
| traceId: "noop", | |
| sampled: false, | |
| status: { | |
| _tag: "Ended", | |
| startTime: bigint0, | |
| endTime: bigint0, | |
| exit: exitVoid | |
| }, | |
| attributes: new Map(), | |
| links: [], | |
| kind: "internal", | |
| attribute() {}, | |
| event() {}, | |
| end() {}, | |
| addLinks() {} | |
| } | |
| /** @internal */ | |
| export const noopSpan = (options: { | |
| readonly name: string | |
| readonly parent: Option.Option<Tracer.AnySpan> | |
| readonly annotations: Context.Context<never> | |
| }): Tracer.Span => Object.assign(Object.create(NoopSpanProto), options) | |
| const filterDisablePropagation = (span: Tracer.AnySpan | undefined): Option.Option<Tracer.AnySpan> => { | |
| if (!span) return Option.none() | |
| return Context.get(span.annotations, Tracer.DisablePropagation) | |
| ? span._tag === "Span" ? filterDisablePropagation(Option.getOrUndefined(span.parent)) : Option.none() | |
| : Option.some(span) | |
| } | |
| /** @internal */ | |
| export const makeSpanUnsafe = <XA, XE>( | |
| fiber: Fiber.Fiber<XA, XE>, | |
| name: string, | |
| options: Tracer.SpanOptionsNoTrace | undefined | |
| ) => { | |
| const disablePropagation = !fiber.getRef(TracerEnabled) || | |
| (options?.annotations && Context.get(options.annotations, Tracer.DisablePropagation)) | |
| const parent = options?.parent !== undefined | |
| ? Option.some(options.parent) | |
| : options?.root | |
| ? Option.none<Tracer.AnySpan>() | |
| : filterDisablePropagation(fiber.currentSpan) | |
| let span: Tracer.Span | |
| if (disablePropagation) { | |
| span = noopSpan({ | |
| name, | |
| parent, | |
| annotations: Context.add( | |
| options?.annotations ?? Context.empty(), | |
| Tracer.DisablePropagation, | |
| true | |
| ) | |
| }) | |
| } else { | |
| const tracer = fiber.getRef(Tracer.Tracer) | |
| const clock = fiber.getRef(ClockRef) | |
| const timingEnabled = fiber.getRef(TracerTimingEnabled) | |
| const annotationsFromEnv = fiber.getRef(TracerSpanAnnotations) | |
| const linksFromEnv = fiber.getRef(TracerSpanLinks) | |
| const level = options?.level ?? fiber.getRef(Tracer.CurrentTraceLevel) | |
| const links = options?.links !== undefined ? | |
| [...linksFromEnv, ...options.links] : | |
| linksFromEnv.slice() | |
| span = tracer.span({ | |
| name, | |
| parent, | |
| annotations: options?.annotations ?? Context.empty(), | |
| links, | |
| startTime: timingEnabled ? clock.currentTimeNanosUnsafe() : BigInt(0), | |
| kind: options?.kind ?? "internal", | |
| root: options?.root ?? Option.isNone(parent), | |
| sampled: options?.sampled ?? | |
| (Option.isSome(parent) && parent.value.sampled === false | |
| ? false | |
| : !isLogLevelGreaterThan(fiber.getRef(Tracer.MinimumTraceLevel), level)) | |
| }) | |
| for (const [key, value] of Object.entries(annotationsFromEnv)) { | |
| span.attribute(key, value) | |
| } | |
| if (options?.attributes !== undefined) { | |
| for (const [key, value] of Object.entries(options.attributes)) { | |
| span.attribute(key, value) | |
| } | |
| } | |
| } | |
| return span | |
| } | |
| /** @internal */ | |
| export const makeSpan = ( | |
| name: string, | |
| options?: Tracer.SpanOptions | |
| ): Effect.Effect<Tracer.Span> => withFiber((fiber) => succeed(makeSpanUnsafe(fiber, name, options))) | |
| /** @internal */ | |
| export const makeSpanScoped = ( | |
| name: string, | |
| options?: Tracer.SpanOptionsNoTrace | undefined | |
| ): Effect.Effect<Tracer.Span, never, Scope.Scope> => | |
| uninterruptible( | |
| withFiber((fiber) => { | |
| const scope = Context.getUnsafe(fiber.context, scopeTag) | |
| const span = makeSpanUnsafe(fiber, name, options ?? {}) | |
| const clock = fiber.getRef(ClockRef) | |
| const timingEnabled = fiber.getRef(TracerTimingEnabled) | |
| return as( | |
| scopeAddFinalizerExit(scope, (exit) => endSpan(span, exit, clock, timingEnabled)), | |
| span | |
| ) | |
| }) | |
| ) | |
| /** @internal */ | |
| export const withSpanScoped: { | |
| ( | |
| name: string, | |
| options?: Tracer.SpanOptions | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan> | Scope.Scope> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| name: string, | |
| options?: Tracer.SpanOptions | |
| ): Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan> | Scope.Scope> | |
| } = function() { | |
| const dataFirst = typeof arguments[0] !== "string" | |
| const name = dataFirst ? arguments[1] : arguments[0] | |
| const options = addSpanStackTrace(dataFirst ? arguments[2] : arguments[1]) | |
| if (dataFirst) { | |
| const self = arguments[0] | |
| return flatMap( | |
| makeSpanScoped(name, options), | |
| (span) => withParentSpan(self, span, options) | |
| ) | |
| } | |
| return (self: Effect.Effect<any, any, any>) => | |
| flatMap( | |
| makeSpanScoped(name, options), | |
| (span) => withParentSpan(self, span, options) | |
| ) | |
| } as any | |
| const provideSpanStackFrame = (name: string, stack: (() => string | undefined) | undefined) => { | |
| stack = typeof stack === "function" ? stack : constUndefined | |
| return updateService(CurrentStackFrame, (parent) => ({ | |
| name, | |
| stack, | |
| parent | |
| })) | |
| } | |
| /** @internal */ | |
| export const spanAnnotations: Effect.Effect<Readonly<Record<string, unknown>>> = TracerSpanAnnotations | |
| /** @internal */ | |
| export const spanLinks: Effect.Effect<ReadonlyArray<Tracer.SpanLink>> = TracerSpanLinks | |
| /** @internal */ | |
| export const linkSpans: { | |
| ( | |
| span: Tracer.AnySpan | ReadonlyArray<Tracer.AnySpan>, | |
| attributes?: Record<string, unknown> | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| span: Tracer.AnySpan | ReadonlyArray<Tracer.AnySpan>, | |
| attributes?: Record<string, unknown> | |
| ): Effect.Effect<A, E, R> | |
| } = dual((args) => isEffect(args[0]), <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| span: Tracer.AnySpan | ReadonlyArray<Tracer.AnySpan>, | |
| attributes: Record<string, unknown> = {} | |
| ): Effect.Effect<A, E, R> => { | |
| const spans: Array<Tracer.AnySpan> = Array.isArray(span) ? span : [span] | |
| const links = spans.map((span): Tracer.SpanLink => ({ span, attributes })) | |
| return updateService(self, TracerSpanLinks, (current) => [...current, ...links]) | |
| }) | |
| /** @internal */ | |
| export const endSpan = <A, E>( | |
| span: Tracer.Span, | |
| exit: Exit.Exit<A, E>, | |
| clock: Clock.Clock, | |
| timingEnabled: boolean | |
| ) => | |
| sync(() => { | |
| if (span.status._tag === "Ended") return | |
| span.end(timingEnabled ? clock.currentTimeNanosUnsafe() : bigint0, exit) | |
| }) | |
| /** @internal */ | |
| export const useSpan: { | |
| <A, E, R>(name: string, evaluate: (span: Tracer.Span) => Effect.Effect<A, E, R>): Effect.Effect<A, E, R> | |
| <A, E, R>( | |
| name: string, | |
| options: Tracer.SpanOptionsNoTrace, | |
| evaluate: (span: Tracer.Span) => Effect.Effect<A, E, R> | |
| ): Effect.Effect<A, E, R> | |
| } = <A, E, R>( | |
| name: string, | |
| ...args: [evaluate: (span: Tracer.Span) => Effect.Effect<A, E, R>] | [ | |
| options: any, | |
| evaluate: (span: Tracer.Span) => Effect.Effect<A, E, R> | |
| ] | |
| ): Effect.Effect<A, E, R> => { | |
| const options = args.length === 1 ? undefined : args[0] | |
| const evaluate: (span: Tracer.Span) => Effect.Effect<A, E, R> = args[args.length - 1] | |
| return withFiber((fiber) => { | |
| const span = makeSpanUnsafe(fiber, name, options) | |
| const clock = fiber.getRef(ClockRef) | |
| return onExit(internalCall(() => evaluate(span)), (exit) => | |
| sync(() => { | |
| if (span.status._tag === "Ended") return | |
| span.end(clock.currentTimeNanosUnsafe(), exit) | |
| })) | |
| }) | |
| } | |
| const provideParentSpan = provideService(Tracer.ParentSpan) | |
| /** @internal */ | |
| export const withParentSpan: { | |
| ( | |
| value: Tracer.AnySpan, | |
| options?: Tracer.TraceOptions | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| value: Tracer.AnySpan, | |
| options?: Tracer.TraceOptions | |
| ): Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>> | |
| } = function() { | |
| const dataFirst = isEffect(arguments[0]) | |
| const span: Tracer.AnySpan = dataFirst ? arguments[1] : arguments[0] | |
| let options = dataFirst ? arguments[2] : arguments[1] | |
| let provideStackFrame: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> = identity | |
| if (span._tag === "Span") { | |
| options = addSpanStackTrace(options) | |
| provideStackFrame = provideSpanStackFrame(span.name, options?.captureStackTrace) | |
| } | |
| if (dataFirst) { | |
| return provideParentSpan(provideStackFrame(arguments[0]), span) | |
| } | |
| return (self: Effect.Effect<any, any, any>) => provideParentSpan(provideStackFrame(self), span) | |
| } as any | |
| /** @internal */ | |
| export const withSpan: { | |
| <Args extends ReadonlyArray<any>>( | |
| name: string, | |
| options?: Tracer.SpanOptionsNoTrace | ((...args: NoInfer<Args>) => Tracer.SpanOptionsNoTrace) | undefined, | |
| traceOptions?: Tracer.TraceOptions | undefined | |
| ): <A, E, R>(self: Effect.Effect<A, E, R>, ...args: Args) => Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>> | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| name: string, | |
| options?: Tracer.SpanOptions | undefined | |
| ): Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>> | |
| } = function() { | |
| const dataFirst = typeof arguments[0] !== "string" | |
| const name = dataFirst ? arguments[1] : arguments[0] | |
| const traceOptions = addSpanStackTrace(arguments[2]) | |
| if (dataFirst) { | |
| const self = arguments[0] | |
| return useSpan(name, arguments[2], (span) => withParentSpan(self, span, traceOptions)) | |
| } | |
| const fnArg = typeof arguments[1] === "function" ? arguments[1] : undefined | |
| const options = fnArg ? undefined : arguments[1] | |
| return (self: Effect.Effect<any, any, any>, ...args: any) => | |
| useSpan( | |
| name, | |
| fnArg ? fnArg(...args) : options, | |
| (span) => withParentSpan(self, span, traceOptions) | |
| ) | |
| } as any | |
| /** @internal */ | |
| export const annotateSpans: { | |
| (key: string, value: unknown): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> | |
| (values: Record<string, unknown>): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> | |
| <A, E, R>(effect: Effect.Effect<A, E, R>, key: string, value: unknown): Effect.Effect<A, E, R> | |
| <A, E, R>(effect: Effect.Effect<A, E, R>, values: Record<string, unknown>): Effect.Effect<A, E, R> | |
| } = dual( | |
| (args) => isEffect(args[0]), | |
| <A, E, R>( | |
| effect: Effect.Effect<A, E, R>, | |
| ...args: [Record<string, unknown>] | [key: string, value: unknown] | |
| ): Effect.Effect<A, E, R> => | |
| updateService(effect, TracerSpanAnnotations, (annotations) => { | |
| const newAnnotations = { ...annotations } | |
| if (args.length === 1) { | |
| Object.assign(newAnnotations, args[0]) | |
| } else { | |
| newAnnotations[args[0]] = args[1] | |
| } | |
| return newAnnotations | |
| }) | |
| ) | |
| /** @internal */ | |
| export const annotateCurrentSpan: { | |
| (key: string, value: unknown): Effect.Effect<void> | |
| (values: Record<string, unknown>): Effect.Effect<void> | |
| } = (...args: [Record<string, unknown>] | [key: string, value: unknown]) => | |
| withFiber((fiber) => { | |
| const span = fiber.currentSpanLocal | |
| if (span) { | |
| if (args.length === 1) { | |
| for (const [key, value] of Object.entries(args[0])) { | |
| span.attribute(key, value) | |
| } | |
| } else { | |
| span.attribute(args[0], args[1]) | |
| } | |
| } | |
| return void_ | |
| }) | |
| /** @internal */ | |
| export const currentSpan: Effect.Effect<Tracer.Span, Cause.NoSuchElementError> = withFiber((fiber) => { | |
| const span = fiber.currentSpanLocal | |
| return span ? succeed(span) : fail(new NoSuchElementError()) | |
| }) | |
| /** @internal */ | |
| export const currentParentSpan: Effect.Effect<Tracer.AnySpan, Cause.NoSuchElementError> = serviceOptional( | |
| Tracer.ParentSpan | |
| ) | |
| // ---------------------------------------------------------------------------- | |
| // Clock | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const ClockRef = Context.Reference<Clock.Clock>("effect/Clock", { | |
| defaultValue: (): Clock.Clock => new ClockImpl() | |
| }) | |
| const MAX_TIMER_MILLIS = 2 ** 31 - 1 | |
| class ClockImpl implements Clock.Clock { | |
| currentTimeMillisUnsafe(): number { | |
| return Date.now() | |
| } | |
| readonly currentTimeMillis: Effect.Effect<number> = sync(() => this.currentTimeMillisUnsafe()) | |
| currentTimeNanosUnsafe(): bigint { | |
| return processOrPerformanceNow() | |
| } | |
| readonly currentTimeNanos: Effect.Effect<bigint> = sync(() => this.currentTimeNanosUnsafe()) | |
| sleep(duration: Duration.Duration): Effect.Effect<void> { | |
| const millis = Duration.toMillis(duration) | |
| if (millis <= 0) return yieldNow | |
| return callback((resume) => { | |
| if (millis > MAX_TIMER_MILLIS) return | |
| const handle = setTimeout(() => resume(void_), millis) | |
| return sync(() => clearTimeout(handle)) | |
| }) | |
| } | |
| } | |
| const performanceNowNanos = (function() { | |
| const bigint1e6 = BigInt(1_000_000) | |
| if (typeof performance === "undefined" || typeof performance.now === "undefined") { | |
| return () => BigInt(Date.now()) * bigint1e6 | |
| } else if (typeof performance.timeOrigin === "number" && performance.timeOrigin === 0) { | |
| return () => BigInt(Math.round(performance.now() * 1_000_000)) | |
| } | |
| const origin = (BigInt(Date.now()) * bigint1e6) - BigInt(Math.round(performance.now() * 1_000_000)) | |
| return () => origin + BigInt(Math.round(performance.now() * 1_000_000)) | |
| })() | |
| const processOrPerformanceNow = (function() { | |
| const processHrtime = | |
| typeof process === "object" && "hrtime" in process && typeof process.hrtime.bigint === "function" ? | |
| process.hrtime : | |
| undefined | |
| if (!processHrtime) { | |
| return performanceNowNanos | |
| } | |
| const origin = performanceNowNanos() - processHrtime.bigint() | |
| return () => origin + processHrtime.bigint() | |
| })() | |
| /** @internal */ | |
| export const clockWith = <A, E, R>(f: (clock: Clock.Clock) => Effect.Effect<A, E, R>): Effect.Effect<A, E, R> => | |
| withFiber((fiber) => f(fiber.getRef(ClockRef))) | |
| /** @internal */ | |
| export const sleep = (duration: Duration.Input): Effect.Effect<void> => | |
| clockWith((clock) => clock.sleep(Duration.fromInputUnsafe(duration))) | |
| /** @internal */ | |
| export const currentTimeMillis: Effect.Effect<number> = clockWith((clock) => clock.currentTimeMillis) | |
| /** @internal */ | |
| export const currentTimeNanos: Effect.Effect<bigint> = clockWith((clock) => clock.currentTimeNanos) | |
| // ---------------------------------------------------------------------------- | |
| // Errors | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const TimeoutErrorTypeId = "~effect/Cause/TimeoutError" | |
| /** @internal */ | |
| export const isTimeoutError = (u: unknown): u is Cause.TimeoutError => hasProperty(u, TimeoutErrorTypeId) | |
| /** @internal */ | |
| export class TimeoutError extends TaggedError("TimeoutError") { | |
| readonly [TimeoutErrorTypeId] = TimeoutErrorTypeId | |
| constructor(message?: string) { | |
| super({ message } as any) | |
| } | |
| } | |
| /** @internal */ | |
| export const IllegalArgumentErrorTypeId = "~effect/Cause/IllegalArgumentError" | |
| /** @internal */ | |
| export const isIllegalArgumentError = ( | |
| u: unknown | |
| ): u is Cause.IllegalArgumentError => hasProperty(u, IllegalArgumentErrorTypeId) | |
| /** @internal */ | |
| export class IllegalArgumentError extends TaggedError("IllegalArgumentError") { | |
| readonly [IllegalArgumentErrorTypeId] = IllegalArgumentErrorTypeId | |
| constructor(message?: string) { | |
| super({ message } as any) | |
| } | |
| } | |
| /** @internal */ | |
| export const ExceededCapacityErrorTypeId = "~effect/Cause/ExceededCapacityError" | |
| /** @internal */ | |
| export const isExceededCapacityError = ( | |
| u: unknown | |
| ): u is Cause.ExceededCapacityError => hasProperty(u, ExceededCapacityErrorTypeId) | |
| /** @internal */ | |
| export class ExceededCapacityError extends TaggedError("ExceededCapacityError") { | |
| readonly [ExceededCapacityErrorTypeId] = ExceededCapacityErrorTypeId | |
| constructor(message?: string) { | |
| super({ message } as any) | |
| } | |
| } | |
| /** @internal */ | |
| export const AsyncFiberErrorTypeId = "~effect/Cause/AsyncFiberError" | |
| /** @internal */ | |
| export const isAsyncFiberError = ( | |
| u: unknown | |
| ): u is Cause.AsyncFiberError => hasProperty(u, AsyncFiberErrorTypeId) | |
| /** @internal */ | |
| export class AsyncFiberError extends TaggedError("AsyncFiberError")<{ | |
| fiber: Fiber.Fiber<unknown, unknown> | |
| message: string | |
| }> { | |
| readonly [AsyncFiberErrorTypeId] = AsyncFiberErrorTypeId | |
| constructor(fiber: Fiber.Fiber<unknown, unknown>) { | |
| super({ | |
| message: "An asynchronous Effect was executed with Effect.runSync", | |
| fiber | |
| }) | |
| } | |
| } | |
| /** @internal */ | |
| export const UnknownErrorTypeId = "~effect/Cause/UnknownError" | |
| /** @internal */ | |
| export const isUnknownError = ( | |
| u: unknown | |
| ): u is Cause.UnknownError => hasProperty(u, UnknownErrorTypeId) | |
| /** @internal */ | |
| export class UnknownError extends TaggedError("UnknownError")<{ | |
| cause: unknown | |
| message?: string | undefined | |
| }> { | |
| readonly [UnknownErrorTypeId] = UnknownErrorTypeId | |
| constructor(cause: unknown, message?: string) { | |
| super({ message, cause } as any) | |
| } | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // Console | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const ConsoleRef = Context.Reference<Console.Console>( | |
| "effect/Console/CurrentConsole", | |
| { defaultValue: (): Console.Console => globalThis.console } | |
| ) | |
| // ---------------------------------------------------------------------------- | |
| // LogLevel | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const logLevelToOrder = (level: LogLevel.LogLevel) => { | |
| switch (level) { | |
| case "All": | |
| return Number.MIN_SAFE_INTEGER | |
| case "Fatal": | |
| return 50_000 | |
| case "Error": | |
| return 40_000 | |
| case "Warn": | |
| return 30_000 | |
| case "Info": | |
| return 20_000 | |
| case "Debug": | |
| return 10_000 | |
| case "Trace": | |
| return 0 | |
| case "None": | |
| return Number.MAX_SAFE_INTEGER | |
| } | |
| } | |
| /** @internal */ | |
| export const LogLevelOrder = Order.mapInput(Order.Number, logLevelToOrder) | |
| /** @internal */ | |
| export const isLogLevelGreaterThan = Order.isGreaterThan(LogLevelOrder) | |
| // ---------------------------------------------------------------------------- | |
| // Logger | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const CurrentLoggers = Context.Reference< | |
| ReadonlySet<Logger.Logger<unknown, any>> | |
| >("effect/Loggers/CurrentLoggers", { | |
| defaultValue: () => new Set([defaultLogger, tracerLogger]) | |
| }) | |
| /** @internal */ | |
| export const LogToStderr = Context.Reference<boolean>("effect/Logger/LogToStderr", { | |
| defaultValue: constFalse | |
| }) | |
| /** @internal */ | |
| export const annotateLogsScoped: { | |
| (key: string, value: unknown): Effect.Effect<void, never, Scope.Scope> | |
| (values: Record<string, unknown>): Effect.Effect<void, never, Scope.Scope> | |
| } = function() { | |
| const entries = typeof arguments[0] === "string" ? | |
| [[arguments[0], arguments[1]]] : | |
| Object.entries(arguments[0]) | |
| return uninterruptible(withFiber((fiber) => { | |
| const prev = fiber.getRef(CurrentLogAnnotations) | |
| const next = { ...prev } | |
| for (let i = 0; i < entries.length; i++) { | |
| const [key, value] = entries[i] | |
| next[key] = value | |
| } | |
| fiber.setContext(Context.add(fiber.context, CurrentLogAnnotations, next)) | |
| return scopeAddFinalizerExit(Context.getUnsafe(fiber.context, scopeTag), (_) => { | |
| const current = fiber.getRef(CurrentLogAnnotations) | |
| const next = { ...current } | |
| for (let i = 0; i < entries.length; i++) { | |
| const [key, value] = entries[i] | |
| if (current[key] !== value) continue | |
| if (key in prev) { | |
| next[key] = prev[key] | |
| } else { | |
| delete next[key] | |
| } | |
| } | |
| fiber.setContext(Context.add(fiber.context, CurrentLogAnnotations, next)) | |
| return void_ | |
| }) | |
| })) | |
| } | |
| /** @internal */ | |
| export const LoggerTypeId = "~effect/Logger" | |
| const LoggerProto = { | |
| [LoggerTypeId]: { | |
| _Message: identity, | |
| _Output: identity | |
| }, | |
| pipe() { | |
| return pipeArguments(this, arguments) | |
| } | |
| } | |
| /** @internal */ | |
| export const loggerMake = <Message, Output>( | |
| log: (options: Logger.Options<Message>) => Output | |
| ): Logger.Logger<Message, Output> => { | |
| const self = Object.create(LoggerProto) | |
| self.log = log | |
| return self | |
| } | |
| /** | |
| * Sanitize a given string by replacing spaces, equal signs, and double quotes | |
| * with underscores. | |
| * | |
| * @internal | |
| */ | |
| export const formatLabel = (key: string) => key.replace(/[\s="]/g, "_") | |
| /** | |
| * Formats a log span into a `<label>=<value>ms` string. | |
| * | |
| * @internal | |
| */ | |
| export const formatLogSpan = (self: [label: string, timestamp: number], now: number): string => { | |
| const label = formatLabel(self[0]) | |
| return `${label}=${now - self[1]}ms` | |
| } | |
| /** @internal */ | |
| export const structuredMessage = (u: unknown): unknown => { | |
| switch (typeof u) { | |
| case "bigint": | |
| case "function": | |
| case "symbol": { | |
| return String(u) | |
| } | |
| default: { | |
| return toJson(u) | |
| } | |
| } | |
| } | |
| /** @internal */ | |
| export const logWithLevel = (level?: LogLevel.Severity) => | |
| ( | |
| ...message: ReadonlyArray<any> | |
| ): Effect.Effect<void> => { | |
| let cause: Cause.Cause<unknown> | undefined = undefined | |
| for (let i = 0, len = message.length; i < len; i++) { | |
| const msg = message[i] | |
| if (isCause(msg)) { | |
| if (cause) { | |
| ;(message as Array<any>).splice(i, 1) | |
| } else { | |
| message = message.slice(0, i).concat(message.slice(i + 1)) | |
| } | |
| cause = cause ? causeFromReasons(cause.reasons.concat(msg.reasons)) : msg | |
| i-- | |
| } | |
| } | |
| if (cause === undefined) { | |
| cause = causeEmpty | |
| } | |
| return withFiber((fiber) => { | |
| const logLevel = level ?? fiber.currentLogLevel | |
| if (isLogLevelGreaterThan(fiber.minimumLogLevel, logLevel)) { | |
| return void_ | |
| } | |
| const clock = fiber.getRef(ClockRef) | |
| const loggers = fiber.getRef(CurrentLoggers) | |
| if (loggers.size > 0) { | |
| const date = new Date(clock.currentTimeMillisUnsafe()) | |
| for (const logger of loggers) { | |
| logger.log({ | |
| cause, | |
| fiber, | |
| date, | |
| logLevel, | |
| message | |
| }) | |
| } | |
| } | |
| return void_ | |
| }) | |
| } | |
| const withColor = (text: string, ...colors: ReadonlyArray<string>) => { | |
| let out = "" | |
| for (let i = 0; i < colors.length; i++) { | |
| out += `\x1b[${colors[i]}m` | |
| } | |
| return out + text + "\x1b[0m" | |
| } | |
| const withColorNoop = (text: string, ..._colors: ReadonlyArray<string>) => text | |
| const colors = { | |
| bold: "1", | |
| red: "31", | |
| green: "32", | |
| yellow: "33", | |
| blue: "34", | |
| cyan: "36", | |
| white: "37", | |
| gray: "90", | |
| black: "30", | |
| bgBrightRed: "101" | |
| } as const | |
| const logLevelColors: Record<LogLevel.LogLevel, ReadonlyArray<string>> = { | |
| None: [], | |
| All: [], | |
| Trace: [colors.gray], | |
| Debug: [colors.blue], | |
| Info: [colors.green], | |
| Warn: [colors.yellow], | |
| Error: [colors.red], | |
| Fatal: [colors.bgBrightRed, colors.black] | |
| } | |
| const logLevelStyle: Record<LogLevel.LogLevel, string> = { | |
| None: "", | |
| All: "", | |
| Trace: "color:gray", | |
| Debug: "color:blue", | |
| Info: "color:green", | |
| Warn: "color:orange", | |
| Error: "color:red", | |
| Fatal: "background-color:red;color:white" | |
| } | |
| const defaultDateFormat = (date: Date): string => | |
| `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${ | |
| date.getSeconds().toString().padStart(2, "0") | |
| }.${date.getMilliseconds().toString().padStart(3, "0")}` | |
| /** @internal */ | |
| export const consolePretty = (options?: { | |
| readonly colors?: "auto" | boolean | undefined | |
| readonly formatDate?: ((date: Date) => string) | undefined | |
| readonly mode?: "browser" | "tty" | "auto" | undefined | |
| }) => { | |
| // evaluated lazily so the module-level bundle stays free of `process` | |
| // property accesses, which bundlers must retain as possible side effects | |
| const hasProcessStdout = typeof process === "object" && | |
| process !== null && | |
| typeof process.stdout === "object" && | |
| process.stdout !== null | |
| const processStdoutIsTTY = hasProcessStdout && | |
| process.stdout.isTTY === true | |
| const hasProcessStdoutOrDeno = hasProcessStdout || "Deno" in globalThis | |
| const mode_ = options?.mode ?? "auto" | |
| const mode = mode_ === "auto" ? (hasProcessStdoutOrDeno ? "tty" : "browser") : mode_ | |
| const isBrowser = mode === "browser" | |
| const showColors = typeof options?.colors === "boolean" ? options.colors : processStdoutIsTTY || isBrowser | |
| const formatDate = options?.formatDate ?? defaultDateFormat | |
| return isBrowser | |
| ? prettyLoggerBrowser({ colors: showColors, formatDate }) | |
| : prettyLoggerTty({ colors: showColors, formatDate }) | |
| } | |
| const prettyLoggerTty = (options: { | |
| readonly colors: boolean | |
| readonly formatDate: (date: Date) => string | |
| }) => { | |
| const processIsBun = typeof process === "object" && "isBun" in process && process.isBun === true | |
| const color = options.colors ? withColor : withColorNoop | |
| return loggerMake<unknown, void>( | |
| ({ cause, date, fiber, logLevel, message: message_ }) => { | |
| const console = fiber.getRef(ConsoleRef) | |
| // oxlint-disable-next-line no-console | |
| const log = fiber.getRef(LogToStderr) ? console.error : console.log | |
| const message = Array.isArray(message_) ? message_.slice() : [message_] | |
| let firstLine = color(`[${options.formatDate(date)}]`, colors.white) | |
| + ` ${color(logLevel.toUpperCase(), ...logLevelColors[logLevel])}` | |
| + ` (#${fiber.id})` | |
| const now = date.getTime() | |
| const spans = fiber.getRef(CurrentLogSpans) | |
| for (const span of spans) { | |
| firstLine += " " + formatLogSpan(span, now) | |
| } | |
| firstLine += ":" | |
| let messageIndex = 0 | |
| if (message.length > 0) { | |
| const firstMaybeString = structuredMessage(message[0]) | |
| if (typeof firstMaybeString === "string") { | |
| firstLine += " " + color(firstMaybeString, colors.bold, colors.cyan) | |
| messageIndex++ | |
| } | |
| } | |
| log(firstLine) | |
| // oxlint-disable-next-line no-console | |
| if (!processIsBun) console.group() | |
| if (cause.reasons.length > 0) { | |
| log(causePretty(cause)) | |
| } | |
| if (messageIndex < message.length) { | |
| for (; messageIndex < message.length; messageIndex++) { | |
| log(redact(message[messageIndex])) | |
| } | |
| } | |
| const annotations = fiber.getRef(CurrentLogAnnotations) | |
| for (const [key, value] of Object.entries(annotations)) { | |
| log(color(`${key}:`, colors.bold, colors.white), redact(value)) | |
| } | |
| // oxlint-disable-next-line no-console | |
| if (!processIsBun) console.groupEnd() | |
| } | |
| ) | |
| } | |
| const prettyLoggerBrowser = (options: { | |
| readonly colors: boolean | |
| readonly formatDate: (date: Date) => string | |
| }) => { | |
| const color = options.colors ? "%c" : "" | |
| return loggerMake<unknown, void>( | |
| ({ cause, date, fiber, logLevel, message: message_ }) => { | |
| const console = fiber.getRef(ConsoleRef) | |
| const message = Array.isArray(message_) ? message_.slice() : [message_] | |
| let firstLine = `${color}[${options.formatDate(date)}]` | |
| const firstParams = [] | |
| if (options.colors) { | |
| firstParams.push("color:gray") | |
| } | |
| firstLine += ` ${color}${logLevel.toUpperCase()}${color} (#${fiber.id})` | |
| if (options.colors) { | |
| firstParams.push(logLevelStyle[logLevel], "") | |
| } | |
| const now = date.getTime() | |
| const spans = fiber.getRef(CurrentLogSpans) | |
| for (const span of spans) { | |
| firstLine += " " + formatLogSpan(span, now) | |
| } | |
| firstLine += ":" | |
| let messageIndex = 0 | |
| if (message.length > 0) { | |
| const firstMaybeString = structuredMessage(message[0]) | |
| if (typeof firstMaybeString === "string") { | |
| firstLine += ` ${color}${firstMaybeString}` | |
| if (options.colors) { | |
| firstParams.push("color:deepskyblue") | |
| } | |
| messageIndex++ | |
| } | |
| } | |
| // oxlint-disable-next-line no-console | |
| console.groupCollapsed(firstLine, ...firstParams) | |
| if (cause.reasons.length > 0) { | |
| // oxlint-disable-next-line no-console | |
| console.error(causePretty(cause)) | |
| } | |
| if (messageIndex < message.length) { | |
| for (; messageIndex < message.length; messageIndex++) { | |
| // oxlint-disable-next-line no-console | |
| console.log(redact(message[messageIndex])) | |
| } | |
| } | |
| const annotations = fiber.getRef(CurrentLogAnnotations) | |
| for (const [key, value] of Object.entries(annotations)) { | |
| const redacted = redact(value) | |
| if (options.colors) { | |
| // oxlint-disable-next-line no-console | |
| console.log(`%c${key}:`, "color:gray", redacted) | |
| } else { | |
| // oxlint-disable-next-line no-console | |
| console.log(`${key}:`, redacted) | |
| } | |
| } | |
| // oxlint-disable-next-line no-console | |
| console.groupEnd() | |
| } | |
| ) | |
| } | |
| /** @internal */ | |
| export const defaultLogger = loggerMake<unknown, void>(({ cause, date, fiber, logLevel, message }) => { | |
| const message_ = Array.isArray(message) ? message.slice() : [message] | |
| if (cause.reasons.length > 0) { | |
| message_.push(causePretty(cause)) | |
| } | |
| const now = date.getTime() | |
| const spans = fiber.getRef(CurrentLogSpans) | |
| let spanString = "" | |
| for (const span of spans) { | |
| spanString += ` ${formatLogSpan(span, now)}` | |
| } | |
| const annotations = fiber.getRef(CurrentLogAnnotations) | |
| if (Object.keys(annotations).length > 0) { | |
| message_.push(annotations) | |
| } | |
| const console = fiber.getRef(ConsoleRef) | |
| // oxlint-disable-next-line no-console | |
| const log = fiber.getRef(LogToStderr) ? console.error : console.log | |
| log(`[${defaultDateFormat(date)}] ${logLevel.toUpperCase()} (#${fiber.id})${spanString}:`, ...message_) | |
| }) | |
| /** @internal */ | |
| export const tracerLogger = loggerMake<unknown, void>(({ cause, fiber, logLevel, message }) => { | |
| const clock = fiber.getRef(ClockRef) | |
| const annotations = fiber.getRef(CurrentLogAnnotations) | |
| const span = fiber.currentSpan | |
| if (span === undefined || span._tag === "ExternalSpan") return | |
| const attributes: Record<string, unknown> = {} | |
| for (const [key, value] of Object.entries(annotations)) { | |
| attributes[key] = value | |
| } | |
| attributes["effect.fiberId"] = fiber.id | |
| attributes["effect.logLevel"] = logLevel.toUpperCase() | |
| if (cause.reasons.length > 0) { | |
| attributes["effect.cause"] = causePretty(cause) | |
| } | |
| span.event( | |
| toStringUnknown(Array.isArray(message) && message.length === 1 ? message[0] : message), | |
| clock.currentTimeNanosUnsafe(), | |
| attributes | |
| ) | |
| }) | |
| /** @internal */ | |
| export function interruptChildrenPatch() { | |
| fiberMiddleware.interruptChildren ??= fiberInterruptChildren | |
| } | |
| /** @internal */ | |
| const undefined_ = succeed(undefined) | |
| /** @internal */ | |
| export { undefined_ as undefined } | |
| // ---------------------------------------------------------------------------- | |
| // ErrorReporter | |
| // ---------------------------------------------------------------------------- | |
| /** @internal */ | |
| export const withErrorReporting: < | |
| Arg extends Effect.Effect<any, any, any> | { | |
| readonly defectsOnly?: boolean | undefined | |
| } | undefined = { | |
| readonly defectsOnly?: boolean | undefined | |
| } | |
| >( | |
| effectOrOptions: Arg, | |
| options?: { | |
| readonly defectsOnly?: boolean | undefined | |
| } | undefined | |
| ) => [Arg] extends [Effect.Effect<infer _A, infer _E, infer _R>] ? Arg | |
| : <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> = dual( | |
| (args) => isEffect(args[0]), | |
| <A, E, R>( | |
| self: Effect.Effect<A, E, R>, | |
| options?: { | |
| readonly defectsOnly?: boolean | undefined | |
| } | undefined | |
| ): Effect.Effect<A, E, R> => | |
| onError(self, (cause) => | |
| withFiber((fiber) => { | |
| reportCauseUnsafe(fiber, cause, options?.defectsOnly) | |
| return void_ | |
| })) | |
| ) | |
| /** @internal */ | |
| export const reportCauseUnsafe = ( | |
| fiber: Fiber.Fiber<unknown, unknown>, | |
| cause: Cause.Cause<unknown>, | |
| defectsOnly?: boolean | |
| ) => { | |
| const reporters = fiber.getRef(CurrentErrorReporters) | |
| if (reporters.size === 0) return | |
| if (defectsOnly && !hasDies(cause)) return | |
| const opts = { cause, fiber, timestamp: fiber.getRef(ClockRef).currentTimeNanosUnsafe() } | |
| reporters.forEach((reporter) => reporter.report(opts)) | |
| } | |
Xet Storage Details
- Size:
- 203 kB
- Xet hash:
- 3184759115317e19aff4b156e3d162d3671fe2d282e1fb46419646976bdbd8df
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.