import { Effect } from "@effect/core/io/Effect/definition" import type { Exit } from "@effect/core/io/Exit/definition" import type { FiberRuntime } from "@effect/core/io/Fiber/_internal/runtime" import type { Patch as P } from "@effect/core/io/Supervisor/patch" import type { SortedSet } from "@tsplus/stdlib/collections/SortedSet" import type { Maybe } from "@tsplus/stdlib/data/Maybe" import type { Env } from "@tsplus/stdlib/service/Env" export const SupervisorURI = Symbol.for("@effect/core/io/Supervisor") export type SupervisorURI = typeof SupervisorURI export namespace Supervisor { export type Patch = P } /** * A `Supervisor` is allowed to supervise the launching and termination of * fibers, producing some visible value of type `A` from the supervision. * * @tsplus type effect/core/io/Supervisor * @tsplus companion effect/core/io/Supervisor.Ops */ export abstract class Supervisor { readonly [SupervisorURI]!: { _T: (_: never) => T } /** * Returns an effect that succeeds with the value produced by this supervisor. * This value may change over time, reflecting what the supervisor produces as * it supervises fibers. */ abstract get value(): Effect abstract onStart( environment: Env, effect: Effect, parent: Maybe>, fiber: FiberRuntime ): void abstract onEnd( value: Exit, fiber: FiberRuntime ): void abstract onEffect( fiber: FiberRuntime, effect: Effect ): void abstract onSuspend( fiber: FiberRuntime ): void abstract onResume( fiber: FiberRuntime ): void /** * Maps this supervisor to another one, which has the same effect, but whose * value has been transformed by the specified function. */ map(f: (a: T) => B): Supervisor { return new ProxySupervisor(this, () => this.value.map(f)) } /** * Returns a new supervisor that performs the function of this supervisor, and * the function of the specified supervisor, producing a tuple of the outputs * produced by both supervisors. */ zip(right: Supervisor): Supervisor { return new Zip(this, right) } } export class ProxySupervisor extends Supervisor { constructor( readonly underlying: Supervisor, readonly value0: () => Effect ) { super() } get value(): Effect { return this.value0() } onStart( environment: Env, effect: Effect, parent: Maybe>, fiber: FiberRuntime ): void { this.underlying.onStart(environment, effect, parent, fiber) } onEnd(value: Exit, fiber: FiberRuntime): void { this.underlying.onEnd(value, fiber) } onEffect(fiber: FiberRuntime, effect: Effect): void { this.underlying.onEffect(fiber, effect) } onSuspend(fiber: FiberRuntime): void { this.underlying.onSuspend(fiber) } onResume(fiber: FiberRuntime): void { this.underlying.onResume(fiber) } } export class Zip extends Supervisor { constructor( readonly left: Supervisor, readonly right: Supervisor ) { super() } get value(): Effect { return this.left.value.zip(this.right.value) } onStart( environment: Env, effect: Effect, parent: Maybe>, fiber: FiberRuntime ): void { this.left.onStart(environment, effect, parent, fiber) this.right.onStart(environment, effect, parent, fiber) } onEnd(value: Exit, fiber: FiberRuntime): void { this.left.onEnd(value, fiber) this.right.onEnd(value, fiber) } onEffect(fiber: FiberRuntime, effect: Effect): void { this.left.onEffect(fiber, effect) this.right.onEffect(fiber, effect) } onSuspend(fiber: FiberRuntime): void { this.left.onSuspend(fiber) this.right.onSuspend(fiber) } onResume(fiber: FiberRuntime): void { this.left.onResume(fiber) this.right.onResume(fiber) } } export class Track extends Supervisor>> { readonly fibers: Set> = new Set() get value(): Effect>> { return Effect.sync(Chunk.from(this.fibers)) } onStart( _environment: Env, _effect: Effect, _parent: Maybe>, fiber: FiberRuntime ): void { this.fibers.add(fiber) } onEnd(_value: Exit, fiber: FiberRuntime): void { this.fibers.delete(fiber) } onEffect(_fiber: FiberRuntime, _effect: Effect): void { // } onSuspend(_fiber: FiberRuntime): void { // } onResume(_fiber: FiberRuntime): void { // } } export class Const extends Supervisor { constructor(readonly effect: Effect) { super() } get value(): Effect { return this.effect } onStart( _environment: Env, _effect: Effect, _parent: Maybe>, _fiber: FiberRuntime ): void { // } onEnd(_value: Exit, _fiber: FiberRuntime): void { // } onEffect(_fiber: FiberRuntime, _effect: Effect): void { // } onSuspend(_fiber: FiberRuntime): void { // } onResume(_fiber: FiberRuntime): void { // } } /** * Creates a new supervisor that tracks children in a set. * * @tsplus static effect/core/io/Supervisor.Ops unsafeTrack */ export function unsafeTrack(): Supervisor>> { return new Track() } /** * Creates a new supervisor that tracks children in a set. * * @tsplus static effect/core/io/Supervisor.Ops track */ export const track = Effect.sync(unsafeTrack) /** * Creates a new supervisor that constantly yields effect when polled * * @tsplus static effect/core/io/Supervisor.Ops fromEffect */ export function fromEffect( effect: Effect ): Supervisor { return new Const(effect) } /** * A supervisor that doesn't do anything in response to supervision events. * * @tsplus static effect/core/io/Supervisor.Ops none */ export const none = fromEffect(Effect.unit) class FibersIn extends Supervisor>> { constructor(readonly ref: AtomicReference>>) { super() } get value(): Effect>> { return Effect.sync(this.ref.get) } onStart( _environment: Env, _effect: Effect, _parent: Maybe>, fiber: FiberRuntime ): void { this.ref.set(this.ref.get.add(fiber)) } onEnd(_value: Exit, fiber: FiberRuntime): void { this.ref.set(this.ref.get.remove(fiber)) } onEffect(_fiber: FiberRuntime, _effect: Effect): void { // } onSuspend(_fiber: FiberRuntime): void { // } onResume(_fiber: FiberRuntime): void { // } } /** * Creates a new supervisor that tracks children in a set. * * @tsplus static effect/core/io/Supervisor.Ops fibersIn */ export function fibersIn( ref: AtomicReference>> ): Effect>>> { return Effect.sync(new FibersIn(ref)) }