/** * This module provides utilities for working with `Deferred`, a powerful concurrency * primitive that represents an asynchronous variable that can be set exactly once. * Multiple fibers can await the same `Deferred` and will all be notified when it * completes. * * A `Deferred` can be: * - **Completed successfully** with a value of type `A` * - **Failed** with an error of type `E` * - **Interrupted** if the fiber setting it is interrupted * * Key characteristics: * - **Single assignment**: Can only be completed once * - **Multiple waiters**: Many fibers can await the same `Deferred` * - **Fiber-safe**: Thread-safe operations across concurrent fibers * - **Composable**: Works seamlessly with other Effect operations * * @example * ```ts * import { Deferred, Effect, Fiber } from "effect" * * // Basic usage: coordinate between fibers * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * * // Fiber 1: waits for the value * const waiter = yield* Effect.forkChild( * Effect.gen(function*() { * const value = yield* Deferred.await(deferred) * console.log("Received:", value) * return value * }) * ) * * // Fiber 2: sets the value after a delay * const setter = yield* Effect.forkChild( * Effect.gen(function*() { * yield* Effect.sleep("1 second") * yield* Deferred.succeed(deferred, "Hello from setter!") * }) * ) * * // Wait for both fibers * yield* Fiber.join(waiter) * yield* Fiber.join(setter) * }) * * // Producer-consumer pattern * const producerConsumer = Effect.gen(function*() { * const buffer = yield* Deferred.make, never>() * * const producer = Effect.gen(function*() { * const data = [1, 2, 3, 4, 5] * yield* Deferred.succeed(buffer, data) * }) * * const consumer = Effect.gen(function*() { * const data = yield* Deferred.await(buffer) * return data.reduce((sum, n) => sum + n, 0) * }) * * const [, result] = yield* Effect.all([producer, consumer]) * return result // 15 * }) * ``` * * @since 2.0.0 */ import type * as Cause from "./Cause.ts" import type { Effect } from "./Effect.ts" import type * as Exit from "./Exit.ts" import { dual, identity, type LazyArg } from "./Function.ts" import * as core from "./internal/core.ts" import * as internalEffect from "./internal/effect.ts" import * as Option from "./Option.ts" import type { Pipeable } from "./Pipeable.ts" import { pipeArguments } from "./Pipeable.ts" import { hasProperty } from "./Predicate.ts" import type * as Types from "./Types.ts" const TypeId = "~effect/Deferred" /** * A `Deferred` represents an asynchronous variable that can be set exactly * once, with the ability for an arbitrary number of fibers to suspend (by * calling `Deferred.await`) and automatically resume when the variable is set. * * `Deferred` can be used for building primitive actions whose completions * require the coordinated action of multiple fibers, and for building * higher-level concurrent or asynchronous structures. * * @example * ```ts * import { Deferred, Effect, Fiber } from "effect" * * // Create and use a Deferred for inter-fiber communication * const program = Effect.gen(function*() { * // Create a Deferred that will hold a string value * const deferred: Deferred.Deferred = yield* Deferred.make() * * // Fork a fiber that will set the deferred value * const producer = yield* Effect.forkChild( * Effect.gen(function*() { * yield* Effect.sleep("100 millis") * yield* Deferred.succeed(deferred, "Hello, World!") * }) * ) * * // Fork a fiber that will await the deferred value * const consumer = yield* Effect.forkChild( * Effect.gen(function*() { * const value = yield* Deferred.await(deferred) * console.log("Received:", value) * return value * }) * ) * * // Wait for both fibers to complete * yield* Fiber.join(producer) * const result = yield* Fiber.join(consumer) * return result * }) * ``` * * @since 2.0.0 * @category models */ export interface Deferred extends Deferred.Variance, Pipeable { effect?: Effect resumes?: Array<(effect: Effect) => void> | undefined } /** * @since 2.0.0 * @category Guards */ export const isDeferred = (u: unknown): u is Deferred => hasProperty(u, TypeId) /** * @since 2.0.0 * @category models */ export declare namespace Deferred { /** * @since 2.0.0 * @category models */ export interface Variance { readonly [TypeId]: { readonly _A: Types.Invariant readonly _E: Types.Invariant } } } const DeferredProto = { [TypeId]: { _A: identity, _E: identity }, pipe() { return pipeArguments(this, arguments) } } /** * Unsafely creates a new `Deferred` * * @example * ```ts * import { Deferred } from "effect" * * const deferred = Deferred.makeUnsafe() * console.log(deferred) * ``` * * @since 2.0.0 * @category unsafe */ export const makeUnsafe = (): Deferred => { const self = Object.create(DeferredProto) self.resumes = undefined self.effect = undefined return self } /** * Creates a new `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * yield* Deferred.succeed(deferred, 42) * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category constructors */ export const make = (): Effect> => internalEffect.sync(() => makeUnsafe()) const _await = (self: Deferred): Effect => internalEffect.callback((resume) => { if (self.effect) return resume(self.effect) self.resumes ??= [] self.resumes.push(resume) return internalEffect.sync(() => { const index = self.resumes!.indexOf(resume) self.resumes!.splice(index, 1) }) }) export { /** * Retrieves the value of the `Deferred`, suspending the fiber running the * workflow until the result is available. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * yield* Deferred.succeed(deferred, 42) * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category getters */ _await as await } /** * Completes the deferred with the result of the specified effect. If the * deferred has already been completed, the method will produce false. * * Note that `Deferred.completeWith` will be much faster, so consider using * that if you do not need to memoize the result of the specified effect. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const completed = yield* Deferred.complete(deferred, Effect.succeed(42)) * console.log(completed) // true * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ export const complete: { /** * Completes the deferred with the result of the specified effect. If the * deferred has already been completed, the method will produce false. * * Note that `Deferred.completeWith` will be much faster, so consider using * that if you do not need to memoize the result of the specified effect. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const completed = yield* Deferred.complete(deferred, Effect.succeed(42)) * console.log(completed) // true * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ (effect: Effect): (self: Deferred) => Effect /** * Completes the deferred with the result of the specified effect. If the * deferred has already been completed, the method will produce false. * * Note that `Deferred.completeWith` will be much faster, so consider using * that if you do not need to memoize the result of the specified effect. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const completed = yield* Deferred.complete(deferred, Effect.succeed(42)) * console.log(completed) // true * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ (self: Deferred, effect: Effect): Effect } = dual( 2, (self: Deferred, effect: Effect): Effect => internalEffect.suspend(() => self.effect ? internalEffect.succeed(false) : into(effect, self)) ) /** * Completes the deferred with the result of the specified effect. If the * deferred has already been completed, the method will produce false. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const completed = yield* Deferred.completeWith(deferred, Effect.succeed(42)) * console.log(completed) // true * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ export const completeWith: { /** * Completes the deferred with the result of the specified effect. If the * deferred has already been completed, the method will produce false. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const completed = yield* Deferred.completeWith(deferred, Effect.succeed(42)) * console.log(completed) // true * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ (effect: Effect): (self: Deferred) => Effect /** * Completes the deferred with the result of the specified effect. If the * deferred has already been completed, the method will produce false. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const completed = yield* Deferred.completeWith(deferred, Effect.succeed(42)) * console.log(completed) // true * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ (self: Deferred, effect: Effect): Effect } = dual( 2, (self: Deferred, effect: Effect): Effect => internalEffect.sync(() => doneUnsafe(self, effect)) ) /** * Exits the `Deferred` with the specified `Exit` value, which will be * propagated to all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect, Exit } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * yield* Deferred.done(deferred, Exit.succeed(42)) * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ export const done: { /** * Exits the `Deferred` with the specified `Exit` value, which will be * propagated to all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect, Exit } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * yield* Deferred.done(deferred, Exit.succeed(42)) * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ (exit: Exit.Exit): (self: Deferred) => Effect /** * Exits the `Deferred` with the specified `Exit` value, which will be * propagated to all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect, Exit } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * yield* Deferred.done(deferred, Exit.succeed(42)) * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ (self: Deferred, exit: Exit.Exit): Effect } = completeWith as any /** * Fails the `Deferred` with the specified error, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.fail(deferred, "Operation failed") * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ export const fail: { /** * Fails the `Deferred` with the specified error, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.fail(deferred, "Operation failed") * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (error: E): (self: Deferred) => Effect /** * Fails the `Deferred` with the specified error, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.fail(deferred, "Operation failed") * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (self: Deferred, error: E): Effect } = dual(2, (self: Deferred, error: E): Effect => done(self, core.exitFail(error))) /** * Fails the `Deferred` with the specified error, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.failSync(deferred, () => "Lazy error") * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ export const failSync: { /** * Fails the `Deferred` with the specified error, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.failSync(deferred, () => "Lazy error") * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (evaluate: LazyArg): (self: Deferred) => Effect /** * Fails the `Deferred` with the specified error, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.failSync(deferred, () => "Lazy error") * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (self: Deferred, evaluate: LazyArg): Effect } = dual( 2, (self: Deferred, evaluate: LazyArg): Effect => internalEffect.suspend(() => fail(self, evaluate())) ) /** * Fails the `Deferred` with the specified `Cause`, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Cause, Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.failCause( * deferred, * Cause.fail("Operation failed") * ) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ export const failCause: { /** * Fails the `Deferred` with the specified `Cause`, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Cause, Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.failCause( * deferred, * Cause.fail("Operation failed") * ) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (cause: Cause.Cause): (self: Deferred) => Effect /** * Fails the `Deferred` with the specified `Cause`, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Cause, Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.failCause( * deferred, * Cause.fail("Operation failed") * ) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (self: Deferred, cause: Cause.Cause): Effect } = dual( 2, (self: Deferred, cause: Cause.Cause): Effect => done(self, core.exitFailCause(cause)) ) /** * Fails the `Deferred` with the specified `Cause`, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Cause, Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.failCauseSync( * deferred, * () => Cause.fail("Lazy error") * ) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ export const failCauseSync: { /** * Fails the `Deferred` with the specified `Cause`, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Cause, Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.failCauseSync( * deferred, * () => Cause.fail("Lazy error") * ) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (evaluate: LazyArg>): (self: Deferred) => Effect /** * Fails the `Deferred` with the specified `Cause`, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Cause, Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.failCauseSync( * deferred, * () => Cause.fail("Lazy error") * ) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (self: Deferred, evaluate: LazyArg>): Effect } = dual( 2, (self: Deferred, evaluate: LazyArg>): Effect => internalEffect.suspend(() => failCause(self, evaluate())) ) /** * Kills the `Deferred` with the specified defect, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.die( * deferred, * new Error("Something went wrong") * ) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ export const die: { /** * Kills the `Deferred` with the specified defect, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.die( * deferred, * new Error("Something went wrong") * ) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (defect: unknown): (self: Deferred) => Effect /** * Kills the `Deferred` with the specified defect, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.die( * deferred, * new Error("Something went wrong") * ) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (self: Deferred, defect: unknown): Effect } = dual(2, (self: Deferred, defect: unknown): Effect => done(self, core.exitDie(defect))) /** * Kills the `Deferred` with the specified defect, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.dieSync( * deferred, * () => new Error("Lazy error") * ) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ export const dieSync: { /** * Kills the `Deferred` with the specified defect, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.dieSync( * deferred, * () => new Error("Lazy error") * ) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (evaluate: LazyArg): (self: Deferred) => Effect /** * Kills the `Deferred` with the specified defect, which will be propagated to * all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.dieSync( * deferred, * () => new Error("Lazy error") * ) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (self: Deferred, evaluate: LazyArg): Effect } = dual( 2, (self: Deferred, evaluate: LazyArg): Effect => internalEffect.suspend(() => die(self, evaluate())) ) /** * Completes the `Deferred` with interruption. This will interrupt all fibers * waiting on the value of the `Deferred` with the `FiberId` of the fiber * calling this method. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.interrupt(deferred) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ export const interrupt = (self: Deferred): Effect => core.withFiber((fiber) => interruptWith(self, fiber.id)) /** * Completes the `Deferred` with interruption. This will interrupt all fibers * waiting on the value of the `Deferred` with the specified `FiberId`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.interruptWith(deferred, 42) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ export const interruptWith: { /** * Completes the `Deferred` with interruption. This will interrupt all fibers * waiting on the value of the `Deferred` with the specified `FiberId`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.interruptWith(deferred, 42) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (fiberId: number): (self: Deferred) => Effect /** * Completes the `Deferred` with interruption. This will interrupt all fibers * waiting on the value of the `Deferred` with the specified `FiberId`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const success = yield* Deferred.interruptWith(deferred, 42) * console.log(success) // true * }) * ``` * * @since 2.0.0 * @category utils */ (self: Deferred, fiberId: number): Effect } = dual( 2, (self: Deferred, fiberId: number): Effect => failCause(self, internalEffect.causeInterrupt(fiberId)) ) /** * Returns `true` if this `Deferred` has already been completed with a value or * an error, `false` otherwise. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const beforeCompletion = yield* Deferred.isDone(deferred) * console.log(beforeCompletion) // false * * yield* Deferred.succeed(deferred, 42) * const afterCompletion = yield* Deferred.isDone(deferred) * console.log(afterCompletion) // true * }) * ``` * * @since 2.0.0 * @category getters */ export const isDone = (self: Deferred): Effect => internalEffect.sync(() => isDoneUnsafe(self)) /** * Returns `true` if this `Deferred` has already been completed with a value or * an error, `false` otherwise. * * @since 2.0.0 * @category getters */ export const isDoneUnsafe = (self: Deferred): boolean => self.effect !== undefined /** * Returns the current completion effect as an `Option`. This returns * `Option.some(effect)` when the `Deferred` is completed, `Option.none()` * otherwise. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * const beforeCompletion = yield* Deferred.poll(deferred) * console.log(beforeCompletion._tag === "None") // true * * yield* Deferred.succeed(deferred, 42) * const afterCompletion = yield* Deferred.poll(deferred) * console.log(afterCompletion._tag === "Some") // true * }) * ``` * * @since 2.0.0 * @category getters */ export function poll(self: Deferred): Effect>> { return internalEffect.sync(() => Option.fromUndefinedOr(self.effect)) } /** * Completes the `Deferred` with the specified value. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * yield* Deferred.succeed(deferred, 42) * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ export const succeed: { /** * Completes the `Deferred` with the specified value. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * yield* Deferred.succeed(deferred, 42) * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ (value: A): (self: Deferred) => Effect /** * Completes the `Deferred` with the specified value. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * yield* Deferred.succeed(deferred, 42) * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ (self: Deferred, value: A): Effect } = dual(2, (self: Deferred, value: A): Effect => done(self, core.exitSucceed(value))) /** * Completes the `Deferred` with the specified lazily evaluated value. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * yield* Deferred.sync(deferred, () => 42) * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ export const sync: { /** * Completes the `Deferred` with the specified lazily evaluated value. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * yield* Deferred.sync(deferred, () => 42) * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ (evaluate: LazyArg): (self: Deferred) => Effect /** * Completes the `Deferred` with the specified lazily evaluated value. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const program = Effect.gen(function*() { * const deferred = yield* Deferred.make() * yield* Deferred.sync(deferred, () => 42) * * const value = yield* Deferred.await(deferred) * console.log(value) // 42 * }) * ``` * * @since 2.0.0 * @category utils */ (self: Deferred, evaluate: LazyArg): Effect } = dual( 2, (self: Deferred, evaluate: LazyArg): Effect => internalEffect.suspend(() => succeed(self, evaluate())) ) /** * Unsafely exits the `Deferred` with the specified `Exit` value, which will be * propagated to all fibers waiting on the value of the `Deferred`. * * @example * ```ts * import { Deferred, Effect } from "effect" * * const deferred = Deferred.makeUnsafe() * const success = Deferred.doneUnsafe(deferred, Effect.succeed(42)) * console.log(success) // true * ``` * * @since 2.0.0 * @category unsafe */ export const doneUnsafe = (self: Deferred, effect: Effect): boolean => { if (self.effect) return false self.effect = effect if (self.resumes) { for (let i = 0; i < self.resumes.length; i++) { self.resumes[i](effect) } self.resumes = undefined } return true } /** * Converts an `Effect` into an operation that completes a `Deferred` with its result. * * **Details** * * The `into` function takes an effect and a `Deferred` and ensures that the `Deferred` * is completed based on the outcome of the effect. If the effect succeeds, the `Deferred` is * completed with the success value. If the effect fails, the `Deferred` is completed with the * failure. Additionally, if the effect is interrupted, the `Deferred` will also be interrupted. * * @example * ```ts * import { Deferred, Effect } from "effect" * * // Define an effect that succeeds * const successEffect = Effect.succeed(42) * * const program = Effect.gen(function*() { * // Create a deferred * const deferred = yield* Deferred.make() * * // Complete the deferred using the successEffect * const isCompleted = yield* Deferred.into(successEffect, deferred) * * // Access the value of the deferred * const value = yield* Deferred.await(deferred) * console.log(value) * * return isCompleted * }) * * Effect.runPromise(program).then(console.log) * // Output: * // 42 * // true * ``` * * @since 2.0.0 * @category Synchronization Utilities */ export const into: { /** * Converts an `Effect` into an operation that completes a `Deferred` with its result. * * **Details** * * The `into` function takes an effect and a `Deferred` and ensures that the `Deferred` * is completed based on the outcome of the effect. If the effect succeeds, the `Deferred` is * completed with the success value. If the effect fails, the `Deferred` is completed with the * failure. Additionally, if the effect is interrupted, the `Deferred` will also be interrupted. * * @example * ```ts * import { Deferred, Effect } from "effect" * * // Define an effect that succeeds * const successEffect = Effect.succeed(42) * * const program = Effect.gen(function*() { * // Create a deferred * const deferred = yield* Deferred.make() * * // Complete the deferred using the successEffect * const isCompleted = yield* Deferred.into(successEffect, deferred) * * // Access the value of the deferred * const value = yield* Deferred.await(deferred) * console.log(value) * * return isCompleted * }) * * Effect.runPromise(program).then(console.log) * // Output: * // 42 * // true * ``` * * @since 2.0.0 * @category Synchronization Utilities */ (deferred: Deferred): (self: Effect) => Effect /** * Converts an `Effect` into an operation that completes a `Deferred` with its result. * * **Details** * * The `into` function takes an effect and a `Deferred` and ensures that the `Deferred` * is completed based on the outcome of the effect. If the effect succeeds, the `Deferred` is * completed with the success value. If the effect fails, the `Deferred` is completed with the * failure. Additionally, if the effect is interrupted, the `Deferred` will also be interrupted. * * @example * ```ts * import { Deferred, Effect } from "effect" * * // Define an effect that succeeds * const successEffect = Effect.succeed(42) * * const program = Effect.gen(function*() { * // Create a deferred * const deferred = yield* Deferred.make() * * // Complete the deferred using the successEffect * const isCompleted = yield* Deferred.into(successEffect, deferred) * * // Access the value of the deferred * const value = yield* Deferred.await(deferred) * console.log(value) * * return isCompleted * }) * * Effect.runPromise(program).then(console.log) * // Output: * // 42 * // true * ``` * * @since 2.0.0 * @category Synchronization Utilities */ (self: Effect, deferred: Deferred): Effect } = dual( 2, (self: Effect, deferred: Deferred): Effect => internalEffect.uninterruptibleMask((restore) => internalEffect.flatMap( internalEffect.exit(restore(self)), (exit) => done(deferred, exit) ) ) )