import { FiberRuntime } from "@effect/core/io/Fiber/_internal/runtime" import { StagedScheduler } from "@effect/core/support/Scheduler" import { constVoid } from "@tsplus/stdlib/data/Function" export class AsyncFiber { readonly _tag = "AsyncFiber" constructor(readonly fiber: FiberRuntime) {} } export class Runtime { constructor( readonly environment: Env, readonly runtimeFlags: RuntimeFlags, readonly fiberRefs: FiberRefs ) {} unsafeFork = (effect: Effect) => { const fiberId = FiberId.unsafeMake() const fiberRefs = this.fiberRefs .updateAs( fiberId, FiberRef.currentEnvironment, this.environment as Env ) const context = new FiberRuntime( fiberId, fiberRefs, this.runtimeFlags ) const supervisor = context.getSupervisor if (supervisor != Supervisor.none) { supervisor.onStart(this.environment, effect, Maybe.none, context) context.addObserver(exit => supervisor.onEnd(exit, context)) } context.start(effect) FiberScope.global.add(this.runtimeFlags, context) return context } unsafeRunWith = ( effect: Effect, k: (exit: Exit) => void ): ((fiberId: FiberId) => (_: (exit: Exit) => void) => void) => { const fiberId = FiberId.unsafeMake() const fiberRefs = this.fiberRefs .updateAs( fiberId, FiberRef.currentEnvironment, this.environment as Env ) const context = new FiberRuntime( fiberId, fiberRefs, this.runtimeFlags ) const supervisor = context.getSupervisor if (supervisor != Supervisor.none) { supervisor.onStart(this.environment, effect, Maybe.none, context) context.addObserver(exit => supervisor.onEnd(exit, context)) } context.start(effect) FiberScope.global.add(this.runtimeFlags, context) context.addObserver((exit) => { k(exit) }) return (id) => (k) => this.unsafeRunAsyncWith(context.interruptAs(id), (exit) => k(exit.flatten)) } unsafeRunSync = ( effect: Effect ): A => { const exit = this.unsafeRunSyncExit(effect) if (exit._tag === "Failure") { throw exit.cause.squashWith(identity) } return exit.value } unsafeRunSyncExit = ( effect: Effect ): Exit => { const fiberId = FiberId.unsafeMake() const scheduler = new StagedScheduler() const fiberRefs = this.fiberRefs .updateAs( fiberId, FiberRef.currentEnvironment, this.environment as Env ) .updateAs( fiberId, FiberRef.currentScheduler, scheduler ) const context = new FiberRuntime( fiberId, fiberRefs, this.runtimeFlags ) const supervisor = context.getSupervisor if (supervisor != Supervisor.none) { supervisor.onStart(this.environment, effect, Maybe.none, context) context.addObserver(exit => supervisor.onEnd(exit, context)) } context.start(effect) FiberScope.global.add(this.runtimeFlags, context) scheduler.flush() const result = context.unsafePoll if (result) { return result } return Exit.die(new AsyncFiber(context)) } /** * Executes the effect asynchronously, discarding the result of execution. * * This method is effectful and should only be invoked at the edges of your * program. */ unsafeRunAsync = (effect: Effect): void => { return this.unsafeRunAsyncWith(effect, constVoid) } /** * Executes the effect asynchronously, eventually passing the exit value to * the specified callback. * * This method is effectful and should only be invoked at the edges of your * program. */ unsafeRunAsyncWith = ( effect: Effect, k: (exit: Exit) => void ): void => { this.unsafeRunWith(effect, k) } /** * Runs the `Effect`, returning a JavaScript `Promise` that will be resolved * with the value of the effect once the effect has been executed, or will be * rejected with the first error or exception throw by the effect. * * This method is effectful and should only be used at the edges of your * program. */ unsafeRunPromise = ( effect: Effect ): Promise => { return new Promise((resolve, reject) => { this.unsafeRunAsyncWith(effect, (exit) => { switch (exit._tag) { case "Success": { resolve(exit.value) break } case "Failure": { reject(exit.cause.squashWith(identity)) break } } }) }) } /** * Runs the `Effect`, returning a JavaScript `Promise` that will be resolved * with the `Exit` state of the effect once the effect has been executed. * * This method is effectful and should only be used at the edges of your * program. */ unsafeRunPromiseExit = ( effect: Effect ): Promise> => { return new Promise((resolve) => { this.unsafeRunAsyncWith(effect, (exit) => { resolve(exit) }) }) } }