// ets_tracing: off // option // cause import * as Cause from "../Cause/core.js" import type { Renderer } from "../Cause/Pretty/index.js" import { defaultRenderer, pretty } from "../Cause/Pretty/index.js" // exit import { HasClock, LiveClock } from "../Clock/index.js" import { flatten as exitFlatten } from "../Exit/core.js" import type { Exit } from "../Exit/exit.js" // fiber import { FiberContext } from "../Fiber/context.js" import { interruptible } from "../Fiber/core.js" import { newFiberId } from "../Fiber/id.js" import { Platform } from "../Fiber/platform.js" import type { Callback } from "../Fiber/state.js" import { constVoid, identity } from "../Function/index.js" import * as O from "../Option/index.js" import { none } from "../Option/index.js" import { defaultRandom, HasRandom } from "../Random/index.js" import * as Scope from "../Scope/index.js" // supervisor import * as Supervisor from "../Supervisor/index.js" import { isTracingEnabled } from "../Tracing/index.js" import * as core from "./core.js" import type { Effect, UIO } from "./effect.js" import type { FailureReporter } from "./primitives.js" import { instruction, IPlatform } from "./primitives.js" // empty function const empty = () => { // } export type DefaultEnv = HasClock & HasRandom export const defaultEnv: DefaultEnv = { [HasClock.key]: new LiveClock(), [HasRandom.key]: defaultRandom } as any /** * Effect Canceler */ export type AsyncCancel = UIO> export const prettyReporter: FailureReporter = (e) => { console.error(pretty(e, defaultRenderer)) } export const defaultPlatform = new Platform({ executionTraceLength: 25, stackTraceLength: 25, traceExecution: isTracingEnabled(), traceStack: isTracingEnabled(), traceEffects: isTracingEnabled(), initialTracingStatus: isTracingEnabled(), ancestorExecutionTraceLength: 25, ancestorStackTraceLength: 25, ancestryLength: 25, renderer: defaultRenderer, reportFailure: constVoid, maxOp: 2048, supervisor: Supervisor.trackMainFibers }) export class CustomRuntime { constructor(readonly env: R, readonly platform: Platform) { this.traceExecution = this.traceExecution.bind(this) this.executionTraceLength = this.executionTraceLength.bind(this) this.traceStack = this.traceStack.bind(this) this.stackTraceLength = this.stackTraceLength.bind(this) this.traceEffect = this.traceEffect.bind(this) this.initialTracingStatus = this.initialTracingStatus.bind(this) this.ancestorExecutionTraceLength = this.ancestorExecutionTraceLength.bind(this) this.ancestorStackTraceLength = this.ancestorStackTraceLength.bind(this) this.ancestryLength = this.ancestryLength.bind(this) this.fiberContext = this.fiberContext.bind(this) this.run = this.run.bind(this) this.runCancel = this.runCancel.bind(this) this.runPromise = this.runPromise.bind(this) this.runPromiseExit = this.runPromiseExit.bind(this) this.traceRenderer = this.traceRenderer.bind(this) this.runFiber = this.runFiber.bind(this) } private fiberContext(effect: Effect) { const initialIS = interruptible const fiberId = newFiberId() const scope = Scope.unsafeMakeScope>() const supervisor = Supervisor.none const context = new FiberContext( fiberId, this.env, initialIS, new Map(), supervisor, scope, this.platform.value.maxOp, this.platform.value.reportFailure, this.platform, none, this.platform.value.initialTracingStatus ) if (supervisor !== Supervisor.none) { supervisor.unsafeOnStart(this.env, effect, O.none, context) context.onDone((exit) => supervisor.unsafeOnEnd(exitFlatten(exit), context)) } context.evaluateLater(instruction(effect)) return context } supervised(supervisor: Supervisor.Supervisor): CustomRuntime { return new CustomRuntime( this.env, new Platform({ ...this.platform.value, supervisor }) ) } runFiber(self: Effect): FiberContext { const context = this.fiberContext(self) return context } /** * Runs effect until completion, calling cb with the eventual exit state */ run(self: Effect, cb?: Callback) { const context = this.fiberContext(self) context.runAsync(cb || empty) } /** * Runs effect until completion returing a cancel effecr that when executed * triggers cancellation of the process */ runCancel(self: Effect, cb?: Callback): AsyncCancel { const context = this.fiberContext(self) context.runAsync(cb || empty) return context.interruptAs(context.id) } /** * Run effect as a Promise, throwing a the first error or exception */ runPromise(self: Effect): Promise { const context = this.fiberContext(self) return new Promise((res, rej) => { context.runAsync((exit) => { switch (exit._tag) { case "Success": { res(exit.value) break } case "Failure": { rej(Cause.squash(identity)(exit.cause)) break } } }) }) } /** * Run effect as a Promise of the Exit state * in case of error. */ runPromiseExit(self: Effect): Promise> { const context = this.fiberContext(self) return new Promise((res) => { context.runAsync((exit) => { res(exit) }) }) } withEnvironment(f: (_: R) => R2) { return new CustomRuntime(f(this.env), this.platform) } traceRenderer(renderer: Renderer) { return new CustomRuntime( this.env, new Platform({ ...this.platform.value, renderer }) ) } traceExecution(b: boolean) { return new CustomRuntime( this.env, new Platform({ ...this.platform.value, traceExecution: b }) ) } executionTraceLength(n: number) { return new CustomRuntime( this.env, new Platform({ ...this.platform.value, executionTraceLength: n }) ) } traceStack(b: boolean) { return new CustomRuntime( this.env, new Platform({ ...this.platform.value, traceStack: b }) ) } stackTraceLength(n: number) { return new CustomRuntime( this.env, new Platform({ ...this.platform.value, stackTraceLength: n }) ) } traceEffect(b: boolean) { return new CustomRuntime( this.env, new Platform({ ...this.platform.value, traceEffects: b }) ) } initialTracingStatus(b: boolean) { return new CustomRuntime( this.env, new Platform({ ...this.platform.value, initialTracingStatus: b }) ) } ancestorExecutionTraceLength(n: number) { return new CustomRuntime( this.env, new Platform({ ...this.platform.value, ancestorExecutionTraceLength: n }) ) } ancestorStackTraceLength(n: number) { return new CustomRuntime( this.env, new Platform({ ...this.platform.value, ancestorStackTraceLength: n }) ) } ancestryLength(n: number) { return new CustomRuntime( this.env, new Platform({ ...this.platform.value, ancestryLength: n }) ) } reportFailure(reportFailure: (_: Cause.Cause) => void) { return new CustomRuntime( this.env, new Platform({ ...this.platform.value, reportFailure }) ) } maxOp(maxOp: number) { return new CustomRuntime(this.env, new Platform({ ...this.platform.value, maxOp })) } } /** * Construct custom runtime */ export function makeCustomRuntime(env: R, platform: Platform) { return new CustomRuntime(env, platform) } /** * Default runtime */ export const defaultRuntime = makeCustomRuntime(defaultEnv, defaultPlatform) /** * Exports of default runtime */ export const { run, runCancel, runFiber, runPromise, runPromiseExit } = defaultRuntime /** * Use current environment to build a runtime that is capable of * providing its content to other effects. * * NOTE: in should be used in a region where current environment * is valid (i.e. keep attention to closed resources) */ export function runtime() { return core.accessM( (r0: R0) => new IPlatform((platform) => core.succeedWith((): CustomRuntime => { return makeCustomRuntime(r0, platform) }) ) ) } export function withRuntimeM( f: (r: CustomRuntime) => Effect ) { return core.chain_(runtime(), f) } export function withRuntime(f: (r: CustomRuntime) => A) { return core.chain_(runtime(), (r) => core.succeed(f(r))) }