1/**
2 * One-time coordination cells for Effect programs. A `Deferred<A, E>` starts
3 * empty, can be completed exactly once with a success, failure, defect, or
4 * interruption, and lets any number of fibers wait for that result. Awaiting a
5 * `Deferred` suspends the fiber instead of blocking an operating-system thread,
6 * and every waiter observes the same completion.
7 *
8 * @since 2.0.0
9 */
10import type * as Cause from "./Cause.ts"
11import type { Effect } from "./Effect.ts"
12import type * as Exit from "./Exit.ts"
13import { dual, identity, type LazyArg } from "./Function.ts"
14import * as core from "./internal/core.ts"
15import * as internalEffect from "./internal/effect.ts"
16import * as Option from "./Option.ts"
17import type { Pipeable } from "./Pipeable.ts"
18import { pipeArguments } from "./Pipeable.ts"
19import { hasProperty } from "./Predicate.ts"
20import type * as Types from "./Types.ts"
21
22const TypeId = "~effect/Deferred"
23
24/**
25 * A `Deferred` represents an asynchronous variable that can be set exactly
26 * once, with the ability for an arbitrary number of fibers to suspend (by
27 * calling `Deferred.await`) and automatically resume when the variable is set.
28 *
29 * **When to use**
30 *
31 * Use to coordinate multiple fibers around a value or failure that will be
32 * supplied exactly once.
33 *
34 * **Example** (Creating a Deferred for inter-fiber communication)
35 *
36 * ```ts import.meta.vitest
37 * import { Deferred, Effect, Fiber } from "effect"
38 *
39 * const program = Effect.gen(function*() {
40 * const deferred: Deferred.Deferred<string> = yield* Deferred.make<string>()
41 * const producer = yield* Effect.forkChild(
42 * Effect.gen(function*() {
43 * yield* Deferred.succeed(deferred, "Hello, World!")
44 * })
45 * )
46 *
47 * const consumer = yield* Effect.forkChild(Deferred.await(deferred))
48 * yield* Fiber.join(producer)
49 * return yield* Fiber.join(consumer)
50 * })
51 *
52 * await Effect.runPromise(program) // => "Hello, World!"
53 * ```
54 *
55 * @category models
56 * @since 2.0.0
57 */
58export interface Deferred<in out A, in out E = never> extends Deferred.Variance<A, E>, Pipeable {
59 effect?: Effect<A, E>
60 resumes?: Array<(effect: Effect<A, E>) => void> | undefined
61}
62
63/**
64 * Checks whether a value is a `Deferred`.
65 *
66 * **When to use**
67 *
68 * Use to validate unknown values at runtime boundaries before treating them as
69 * `Deferred` values.
70 *
71 * @category guards
72 * @since 4.0.0
73 */
74export const isDeferred = <A, E>(u: unknown): u is Deferred<A, E> => hasProperty(u, TypeId)
75
76/**
77 * Companion namespace containing type-level metadata for `Deferred`.
78 *
79 * **When to use**
80 *
81 * Use to reference type-level metadata associated with `Deferred`.
82 *
83 * @since 2.0.0
84 */
85export declare namespace Deferred {
86 /**
87 * Type-level variance marker for the value and error channels of `Deferred`.
88 *
89 * **When to use**
90 *
91 * Use to carry the value and error type parameters for `Deferred` in Effect's
92 * type machinery.
93 *
94 * **Details**
95 *
96 * This interface is part of the public type structure and is not intended to
97 * be constructed directly.
98 *
99 * @category models
100 * @since 2.0.0
101 */
102 export interface Variance<in out A, in out E> {
103 readonly [TypeId]: {
104 readonly _A: Types.Invariant<A>
105 readonly _E: Types.Invariant<E>
106 }
107 }
108}
109
110const DeferredProto = {
111 [TypeId]: {
112 _A: identity,
113 _E: identity
114 },
115 pipe() {
116 return pipeArguments(this, arguments)
117 }
118}
119
120const DeferredImpl = function(this: any) {
121 this.resumes = undefined
122 this.effect = undefined
123} as unknown as { new<A, E>(): Deferred<A, E>; prototype: any }
124DeferredImpl.prototype = DeferredProto
125
126/**
127 * Creates an empty `Deferred` synchronously outside the `Effect` runtime.
128 *
129 * **When to use**
130 *
131 * Use to allocate a `Deferred` synchronously when direct allocation outside
132 * `Effect` is required.
133 *
134 * **Example** (Creating a Deferred unsafely)
135 *
136 * ```ts import.meta.vitest
137 * import { Deferred } from "effect"
138 *
139 * const deferred = Deferred.makeUnsafe<number>()
140 * Deferred.isDoneUnsafe(deferred) // => false
141 * ```
142 *
143 * @category unsafe
144 * @since 4.0.0
145 */
146export const makeUnsafe = <A, E = never>(): Deferred<A, E> => new DeferredImpl<A, E>()
147
148/**
149 * Creates a new `Deferred`.
150 *
151 * **When to use**
152 *
153 * Use to allocate an empty `Deferred` inside an `Effect` workflow.
154 *
155 * **Example** (Creating a Deferred)
156 *
157 * ```ts import.meta.vitest
158 * import { Deferred, Effect } from "effect"
159 *
160 * const program = Effect.gen(function*() {
161 * const deferred = yield* Deferred.make<number>()
162 * yield* Deferred.succeed(deferred, 42)
163 * return yield* Deferred.await(deferred)
164 * })
165 *
166 * await Effect.runPromise(program) // => 42
167 * ```
168 *
169 * @category constructors
170 * @since 2.0.0
171 */
172export const make = <A, E = never>(): Effect<Deferred<A, E>> => internalEffect.sync(() => makeUnsafe())
173
174const _await = <A, E>(self: Deferred<A, E>): Effect<A, E> =>
175 internalEffect.callback<A, E>((resume) => {
176 if (self.effect) return resume(self.effect)
177 self.resumes ??= []
178 self.resumes.push(resume)
179 return internalEffect.sync(() => {
180 // Completion resumes all waiters and clears `resumes`, so a cleanup
181 // running after completion has nothing to unregister.
182 const resumes = self.resumes
183 if (resumes === undefined) return
184 const index = resumes.indexOf(resume)
185 if (index >= 0) resumes.splice(index, 1)
186 })
187 })
188
189export {
190 /**
191 * Retrieves the value of the `Deferred`, suspending the fiber running the
192 * workflow until the result is available.
193 *
194 * **When to use**
195 *
196 * Use to wait for a `Deferred` to be completed and resume with its success,
197 * failure, defect, or interruption.
198 *
199 * **Details**
200 *
201 * Awaiters observe the completion effect stored in the `Deferred`.
202 *
203 * **Example** (Awaiting a Deferred value)
204 *
205 * ```ts import.meta.vitest
206 * import { Deferred, Effect } from "effect"
207 *
208 * const program = Effect.gen(function*() {
209 * const deferred = yield* Deferred.make<number>()
210 * yield* Deferred.succeed(deferred, 42)
211 *
212 * return yield* Deferred.await(deferred)
213 * })
214 *
215 * await Effect.runPromise(program) // => 42
216 * ```
217 *
218 * @see {@link complete} for completing from an effect and memoizing its result
219 * @see {@link completeWith} for completing with an effect directly
220 *
221 * @category getters
222 * @since 2.0.0
223 */
224 _await as await
225}
226
227/**
228 * Runs the supplied `Effect` and attempts to complete the `Deferred` with its
229 * memoized result.
230 *
231 * **When to use**
232 *
233 * Use when completing a `Deferred` should run an effect once and share its
234 * result with all awaiters.
235 *
236 * **Details**
237 *
238 * The returned effect succeeds with `true` when this call completed the
239 * `Deferred`, or `false` if it was already completed.
240 *
241 * **Example** (Completing a Deferred from an effect)
242 *
243 * ```ts import.meta.vitest
244 * import { Deferred, Effect } from "effect"
245 *
246 * const program = Effect.gen(function*() {
247 * const deferred = yield* Deferred.make<number>()
248 * const completed = yield* Deferred.complete(deferred, Effect.succeed(42))
249 * const value = yield* Deferred.await(deferred)
250 * return [completed, value]
251 * })
252 *
253 * await Effect.runPromise(program) // => [true, 42]
254 * ```
255 *
256 * @see {@link completeWith} for storing an effect directly without memoizing its result
257 *
258 * @category completion
259 * @since 2.0.0
260 */
261export const complete: {
262 <A, E, R>(effect: Effect<A, E, R>): (self: Deferred<A, E>) => Effect<boolean, never, R>
263 <A, E, R>(self: Deferred<A, E>, effect: Effect<A, E, R>): Effect<boolean, never, R>
264} = dual(
265 2,
266 <A, E, R>(self: Deferred<A, E>, effect: Effect<A, E, R>): Effect<boolean, never, R> =>
267 internalEffect.suspend(() => self.effect ? internalEffect.succeed(false) : into(effect, self))
268)
269
270/**
271 * Attempts to complete the `Deferred` with the specified effect directly.
272 *
273 * **When to use**
274 *
275 * Use to store an already environment-free effect as the completion without
276 * running it during completion.
277 *
278 * **Details**
279 *
280 * The returned effect succeeds with `true` when this call completed the
281 * `Deferred`, or `false` if it was already completed.
282 *
283 * **Gotchas**
284 *
285 * The supplied effect is not memoized by `completeWith`; each awaiter may run
286 * the stored effect independently.
287 *
288 * **Example** (Completing a Deferred with an effect)
289 *
290 * ```ts import.meta.vitest
291 * import { Deferred, Effect } from "effect"
292 *
293 * const program = Effect.gen(function*() {
294 * const deferred = yield* Deferred.make<number>()
295 * const completed = yield* Deferred.completeWith(deferred, Effect.succeed(42))
296 * const value = yield* Deferred.await(deferred)
297 * return [completed, value]
298 * })
299 *
300 * await Effect.runPromise(program) // => [true, 42]
301 * ```
302 *
303 * @see {@link complete} for running an effect once and sharing its result
304 * @see {@link done} for completing from an already computed `Exit`
305 *
306 * @category completion
307 * @since 2.0.0
308 */
309export const completeWith: {
310 <A, E>(effect: Effect<A, E>): (self: Deferred<A, E>) => Effect<boolean>
311 <A, E>(self: Deferred<A, E>, effect: Effect<A, E>): Effect<boolean>
312} = dual(
313 2,
314 <A, E>(self: Deferred<A, E>, effect: Effect<A, E>): Effect<boolean> =>
315 internalEffect.sync(() => doneUnsafe(self, effect))
316)
317
318/**
319 * Completes the `Deferred` with the specified `Exit` value, which will be
320 * propagated to all fibers waiting on the value of the `Deferred`.
321 *
322 * **When to use**
323 *
324 * Use to complete a `Deferred` from an already computed `Exit`.
325 *
326 * **Details**
327 *
328 * The returned effect succeeds with `true` when this call completed the
329 * `Deferred`, or `false` if it was already completed.
330 *
331 * **Example** (Completing a Deferred with an Exit)
332 *
333 * ```ts import.meta.vitest
334 * import { Deferred, Effect, Exit } from "effect"
335 *
336 * const program = Effect.gen(function*() {
337 * const deferred = yield* Deferred.make<number>()
338 * yield* Deferred.done(deferred, Exit.succeed(42))
339 * return yield* Effect.exit(Deferred.await(deferred))
340 * })
341 *
342 * await Effect.runPromise(program) // => Exit.succeed(42)
343 * ```
344 *
345 * @see {@link complete} for completing from an effect and memoizing its result
346 * @see {@link completeWith} for storing an effect directly
347 * @see {@link succeed} for completing with a success value
348 * @see {@link failCause} for completing with a failure cause
349 *
350 * @category completion
351 * @since 2.0.0
352 */
353export const done: {
354 <A, E>(exit: Exit.Exit<A, E>): (self: Deferred<A, E>) => Effect<boolean>
355 <A, E>(self: Deferred<A, E>, exit: Exit.Exit<A, E>): Effect<boolean>
356} = completeWith as any
357
358/**
359 * Attempts to complete the `Deferred` with the specified error.
360 *
361 * **When to use**
362 *
363 * Use to complete a `Deferred` with a typed failure value.
364 *
365 * **Details**
366 *
367 * Fibers waiting on the `Deferred` fail with that error only if this call
368 * completes it. The returned effect succeeds with `true` when this call
369 * completed the `Deferred`, or `false` if it was already completed.
370 *
371 * **Example** (Failing a Deferred with an error)
372 *
373 * ```ts import.meta.vitest
374 * import { Deferred, Effect, Exit } from "effect"
375 *
376 * const program = Effect.gen(function*() {
377 * const deferred = yield* Deferred.make<number, string>()
378 * const success = yield* Deferred.fail(deferred, "Operation failed")
379 * const exit = yield* Effect.exit(Deferred.await(deferred))
380 * return [success, exit]
381 * })
382 *
383 * await Effect.runPromise(program) // => [true, Exit.fail("Operation failed")]
384 * ```
385 *
386 * @category completion
387 * @since 2.0.0
388 */
389export const fail: {
390 <E>(error: E): <A>(self: Deferred<A, E>) => Effect<boolean>
391 <A, E>(self: Deferred<A, E>, error: E): Effect<boolean>
392} = dual(2, <A, E>(self: Deferred<A, E>, error: E): Effect<boolean> => done(self, core.exitFail(error)))
393
394/**
395 * Computes an error when the returned effect is run, then attempts to complete
396 * the `Deferred` with that error.
397 *
398 * **When to use**
399 *
400 * Use to lazily compute a typed failure value when the `Deferred` completion
401 * effect runs.
402 *
403 * **Details**
404 *
405 * Fibers waiting on the `Deferred` fail with the computed error only if this
406 * call completes it. The returned effect succeeds with `true` when this call
407 * completed the `Deferred`, or `false` if it was already completed.
408 *
409 * **Example** (Failing a Deferred with a lazy error)
410 *
411 * ```ts import.meta.vitest
412 * import { Deferred, Effect, Exit } from "effect"
413 *
414 * const program = Effect.gen(function*() {
415 * const deferred = yield* Deferred.make<number, string>()
416 * const success = yield* Deferred.failSync(deferred, () => "Lazy error")
417 * const exit = yield* Effect.exit(Deferred.await(deferred))
418 * return [success, exit]
419 * })
420 *
421 * await Effect.runPromise(program) // => [true, Exit.fail("Lazy error")]
422 * ```
423 *
424 * @category completion
425 * @since 2.0.0
426 */
427export const failSync: {
428 <E>(evaluate: LazyArg<E>): <A>(self: Deferred<A, E>) => Effect<boolean>
429 <A, E>(self: Deferred<A, E>, evaluate: LazyArg<E>): Effect<boolean>
430} = dual(
431 2,
432 <A, E>(self: Deferred<A, E>, evaluate: LazyArg<E>): Effect<boolean> =>
433 internalEffect.suspend(() => fail(self, evaluate()))
434)
435
436/**
437 * Attempts to complete the `Deferred` with the specified `Cause`.
438 *
439 * **When to use**
440 *
441 * Use to complete a `Deferred` with a full failure cause.
442 *
443 * **Details**
444 *
445 * Fibers waiting on the `Deferred` observe that cause only if this call
446 * completes it. The returned effect succeeds with `true` when this call
447 * completed the `Deferred`, or `false` if it was already completed.
448 *
449 * **Example** (Failing a Deferred with a Cause)
450 *
451 * ```ts import.meta.vitest
452 * import { Cause, Deferred, Effect, Exit } from "effect"
453 *
454 * const program = Effect.gen(function*() {
455 * const deferred = yield* Deferred.make<number, string>()
456 * const success = yield* Deferred.failCause(deferred, Cause.fail("Operation failed"))
457 * const exit = yield* Effect.exit(Deferred.await(deferred))
458 * return [success, exit]
459 * })
460 *
461 * await Effect.runPromise(program) // => [true, Exit.failCause(Cause.fail("Operation failed"))]
462 * ```
463 *
464 * @category completion
465 * @since 2.0.0
466 */
467export const failCause: {
468 <E>(cause: Cause.Cause<E>): <A>(self: Deferred<A, E>) => Effect<boolean>
469 <A, E>(self: Deferred<A, E>, cause: Cause.Cause<E>): Effect<boolean>
470} = dual(
471 2,
472 <A, E>(self: Deferred<A, E>, cause: Cause.Cause<E>): Effect<boolean> => done(self, core.exitFailCause(cause))
473)
474
475/**
476 * Computes a `Cause` when the returned effect is run, then attempts to
477 * complete the `Deferred` with that cause.
478 *
479 * **When to use**
480 *
481 * Use to lazily compute a full failure cause when the `Deferred` completion
482 * effect runs.
483 *
484 * **Details**
485 *
486 * Fibers waiting on the `Deferred` observe the computed cause only if this
487 * call completes it. The returned effect succeeds with `true` when this call
488 * completed the `Deferred`, or `false` if it was already completed.
489 *
490 * **Example** (Failing a Deferred with a lazy Cause)
491 *
492 * ```ts import.meta.vitest
493 * import { Cause, Deferred, Effect, Exit } from "effect"
494 *
495 * const program = Effect.gen(function*() {
496 * const deferred = yield* Deferred.make<number, string>()
497 * const success = yield* Deferred.failCauseSync(deferred, () => Cause.fail("Lazy error"))
498 * const exit = yield* Effect.exit(Deferred.await(deferred))
499 * return [success, exit]
500 * })
501 *
502 * await Effect.runPromise(program) // => [true, Exit.failCause(Cause.fail("Lazy error"))]
503 * ```
504 *
505 * @category completion
506 * @since 2.0.0
507 */
508export const failCauseSync: {
509 <E>(evaluate: LazyArg<Cause.Cause<E>>): <A>(self: Deferred<A, E>) => Effect<boolean>
510 <A, E>(self: Deferred<A, E>, evaluate: LazyArg<Cause.Cause<E>>): Effect<boolean>
511} = dual(
512 2,
513 <A, E>(self: Deferred<A, E>, evaluate: LazyArg<Cause.Cause<E>>): Effect<boolean> =>
514 internalEffect.suspend(() => failCause(self, evaluate()))
515)
516
517/**
518 * Attempts to complete the `Deferred` with a defect.
519 *
520 * **When to use**
521 *
522 * Use to complete a `Deferred` with an unexpected defect.
523 *
524 * **Details**
525 *
526 * Fibers waiting on the `Deferred` die with that defect only if this call
527 * completes it. The returned effect succeeds with `true` when this call
528 * completed the `Deferred`, or `false` if it was already completed.
529 *
530 * **Example** (Killing a Deferred with a defect)
531 *
532 * ```ts import.meta.vitest
533 * import { Deferred, Effect, Exit } from "effect"
534 *
535 * const defect = new Error("Something went wrong")
536 * const program = Effect.gen(function*() {
537 * const deferred = yield* Deferred.make<number>()
538 * const success = yield* Deferred.die(deferred, defect)
539 * const exit = yield* Effect.exit(Deferred.await(deferred))
540 * return [success, exit]
541 * })
542 *
543 * await Effect.runPromise(program) // => [true, Exit.die(defect)]
544 * ```
545 *
546 * @category completion
547 * @since 2.0.0
548 */
549export const die: {
550 (defect: unknown): <A, E>(self: Deferred<A, E>) => Effect<boolean>
551 <A, E>(self: Deferred<A, E>, defect: unknown): Effect<boolean>
552} = dual(2, <A, E>(self: Deferred<A, E>, defect: unknown): Effect<boolean> => done(self, core.exitDie(defect)))
553
554/**
555 * Computes a defect when the returned effect is run, then attempts to complete
556 * the `Deferred` with that defect.
557 *
558 * **When to use**
559 *
560 * Use to lazily compute an unexpected defect when the completion effect runs.
561 *
562 * **Details**
563 *
564 * Fibers waiting on the `Deferred` die with the computed defect only if this
565 * call completes it. The returned effect succeeds with `true` when this call
566 * completed the `Deferred`, or `false` if it was already completed.
567 *
568 * **Example** (Killing a Deferred with a lazy defect)
569 *
570 * ```ts import.meta.vitest
571 * import { Deferred, Effect, Exit } from "effect"
572 *
573 * const defect = new Error("Lazy error")
574 * const program = Effect.gen(function*() {
575 * const deferred = yield* Deferred.make<number>()
576 * const success = yield* Deferred.dieSync(deferred, () => defect)
577 * const exit = yield* Effect.exit(Deferred.await(deferred))
578 * return [success, exit]
579 * })
580 *
581 * await Effect.runPromise(program) // => [true, Exit.die(defect)]
582 * ```
583 *
584 * @category completion
585 * @since 2.0.0
586 */
587export const dieSync: {
588 (evaluate: LazyArg<unknown>): <A, E>(self: Deferred<A, E>) => Effect<boolean>
589 <A, E>(self: Deferred<A, E>, evaluate: LazyArg<unknown>): Effect<boolean>
590} = dual(
591 2,
592 <A, E>(self: Deferred<A, E>, evaluate: LazyArg<unknown>): Effect<boolean> =>
593 internalEffect.suspend(() => die(self, evaluate()))
594)
595
596/**
597 * Attempts to complete the `Deferred` with interruption by the current fiber.
598 *
599 * **When to use**
600 *
601 * Use to complete a `Deferred` as interrupted by the current fiber.
602 *
603 * **Details**
604 *
605 * Fibers waiting on the `Deferred` are interrupted with the current fiber id
606 * only if this call completes it. The returned effect succeeds with `true`
607 * when this call completed the `Deferred`, or `false` if it was already
608 * completed.
609 *
610 * **Example** (Interrupting a Deferred)
611 *
612 * ```ts import.meta.vitest
613 * import { Deferred, Effect, Exit } from "effect"
614 *
615 * const program = Effect.gen(function*() {
616 * const deferred = yield* Deferred.make<number>()
617 * const success = yield* Deferred.interrupt(deferred)
618 * const exit = yield* Effect.exit(Deferred.await(deferred))
619 * return [success, exit] as const
620 * })
621 *
622 * const [success, exit] = await Effect.runPromise(program)
623 * success // => true
624 * Exit.hasInterrupts(exit) // => true
625 * ```
626 *
627 * @category completion
628 * @since 2.0.0
629 */
630export const interrupt = <A, E>(self: Deferred<A, E>): Effect<boolean> =>
631 core.withFiber((fiber) => interruptWith(self, fiber.id))
632
633/**
634 * Attempts to complete the `Deferred` with interruption by the specified
635 * `FiberId`.
636 *
637 * **When to use**
638 *
639 * Use to complete a `Deferred` as interrupted by a specific fiber id.
640 *
641 * **Details**
642 *
643 * Fibers waiting on the `Deferred` are interrupted with that fiber id only if
644 * this call completes it. The returned effect succeeds with `true` when this
645 * call completed the `Deferred`, or `false` if it was already completed.
646 *
647 * **Example** (Interrupting a Deferred with a fiber id)
648 *
649 * ```ts import.meta.vitest
650 * import { Deferred, Effect, Exit } from "effect"
651 *
652 * const program = Effect.gen(function*() {
653 * const deferred = yield* Deferred.make<number>()
654 * const success = yield* Deferred.interruptWith(deferred, 42)
655 * const exit = yield* Effect.exit(Deferred.await(deferred))
656 * return [success, exit]
657 * })
658 *
659 * await Effect.runPromise(program) // => [true, Exit.interrupt(42)]
660 * ```
661 *
662 * @category completion
663 * @since 2.0.0
664 */
665export const interruptWith: {
666 (fiberId: number): <A, E>(self: Deferred<A, E>) => Effect<boolean>
667 <A, E>(self: Deferred<A, E>, fiberId: number): Effect<boolean>
668} = dual(
669 2,
670 <A, E>(self: Deferred<A, E>, fiberId: number): Effect<boolean> =>
671 failCause(self, internalEffect.causeInterrupt(fiberId))
672)
673
674/**
675 * Returns `true` if this `Deferred` has already been completed with a value or
676 * an error, `false` otherwise.
677 *
678 * **When to use**
679 *
680 * Use to check completion status inside an `Effect` workflow.
681 *
682 * **Example** (Checking Deferred completion)
683 *
684 * ```ts import.meta.vitest
685 * import { Deferred, Effect } from "effect"
686 *
687 * const program = Effect.gen(function*() {
688 * const deferred = yield* Deferred.make<number>()
689 * const beforeCompletion = yield* Deferred.isDone(deferred)
690 * yield* Deferred.succeed(deferred, 42)
691 * const afterCompletion = yield* Deferred.isDone(deferred)
692 * return [beforeCompletion, afterCompletion]
693 * })
694 *
695 * await Effect.runPromise(program) // => [false, true]
696 * ```
697 *
698 * @category predicates
699 * @since 2.0.0
700 */
701export const isDone = <A, E>(self: Deferred<A, E>): Effect<boolean> => internalEffect.sync(() => isDoneUnsafe(self))
702
703/**
704 * Returns whether this `Deferred` has already been completed synchronously.
705 *
706 * **When to use**
707 *
708 * Use to check `Deferred` completion synchronously in code that cannot return
709 * an `Effect`, such as low-level integration code.
710 *
711 * @see {@link isDone} for checking completion inside `Effect`
712 * @see {@link poll} for reading the completed effect when available
713 *
714 * @category predicates
715 * @since 4.0.0
716 */
717export const isDoneUnsafe = <A, E>(self: Deferred<A, E>): boolean => self.effect !== undefined
718
719/**
720 * Returns the current completion effect as an `Option`. This returns
721 * `Option.some(effect)` when the `Deferred` is completed, `Option.none()`
722 * otherwise.
723 *
724 * **When to use**
725 *
726 * Use to inspect whether a `Deferred` is already completed and retrieve its
727 * stored completion effect when available.
728 *
729 * **Example** (Polling Deferred completion)
730 *
731 * ```ts import.meta.vitest
732 * import { Deferred, Effect, Option } from "effect"
733 *
734 * const program = Effect.gen(function*() {
735 * const deferred = yield* Deferred.make<number>()
736 * const beforeCompletion = yield* Deferred.poll(deferred)
737 * yield* Deferred.succeed(deferred, 42)
738 * const afterCompletion = yield* Deferred.poll(deferred)
739 * const afterValue = yield* Effect.transposeOption(afterCompletion)
740 * return [beforeCompletion, afterValue]
741 * })
742 *
743 * await Effect.runPromise(program) // => [Option.none(), Option.some(42)]
744 * ```
745 *
746 * @category getters
747 * @since 2.0.0
748 */
749export function poll<A, E>(self: Deferred<A, E>): Effect<Option.Option<Effect<A, E>>> {
750 return internalEffect.sync(() => Option.fromUndefinedOr(self.effect))
751}
752
753/**
754 * Attempts to complete the `Deferred` with the specified value.
755 *
756 * **When to use**
757 *
758 * Use to complete a `Deferred` with a successful value.
759 *
760 * **Details**
761 *
762 * Fibers waiting on the `Deferred` receive the value only if this call
763 * completes it. The returned effect succeeds with `true` when this call
764 * completed the `Deferred`, or `false` if it was already completed.
765 *
766 * **Example** (Completing a Deferred with a value)
767 *
768 * ```ts import.meta.vitest
769 * import { Deferred, Effect } from "effect"
770 *
771 * const program = Effect.gen(function*() {
772 * const deferred = yield* Deferred.make<number>()
773 * yield* Deferred.succeed(deferred, 42)
774 *
775 * return yield* Deferred.await(deferred)
776 * })
777 *
778 * await Effect.runPromise(program) // => 42
779 * ```
780 *
781 * @category completion
782 * @since 2.0.0
783 */
784export const succeed: {
785 <A>(value: A): <E>(self: Deferred<A, E>) => Effect<boolean>
786 <A, E>(self: Deferred<A, E>, value: A): Effect<boolean>
787} = dual(2, <A, E>(self: Deferred<A, E>, value: A): Effect<boolean> => done(self, core.exitSucceed(value)))
788
789/**
790 * Computes a value when the returned effect is run, then attempts to complete
791 * the `Deferred` with that value.
792 *
793 * **When to use**
794 *
795 * Use to lazily compute a successful value when the `Deferred` completion
796 * effect runs.
797 *
798 * **Details**
799 *
800 * Fibers waiting on the `Deferred` receive the computed value only if this call
801 * completes it. The returned effect succeeds with `true` when this call
802 * completed the `Deferred`, or `false` if it was already completed.
803 *
804 * **Example** (Completing a Deferred with a lazy value)
805 *
806 * ```ts import.meta.vitest
807 * import { Deferred, Effect } from "effect"
808 *
809 * const program = Effect.gen(function*() {
810 * const deferred = yield* Deferred.make<number>()
811 * yield* Deferred.sync(deferred, () => 42)
812 * return yield* Deferred.await(deferred)
813 * })
814 *
815 * await Effect.runPromise(program) // => 42
816 * ```
817 *
818 * @category completion
819 * @since 2.0.0
820 */
821export const sync: {
822 <A>(evaluate: LazyArg<A>): <E>(self: Deferred<A, E>) => Effect<boolean>
823 <A, E>(self: Deferred<A, E>, evaluate: LazyArg<A>): Effect<boolean>
824} = dual(
825 2,
826 <A, E>(self: Deferred<A, E>, evaluate: LazyArg<A>): Effect<boolean> =>
827 internalEffect.suspend(() => succeed(self, evaluate()))
828)
829
830/**
831 * Attempts to complete the `Deferred` synchronously with the specified
832 * completion effect.
833 *
834 * **When to use**
835 *
836 * Use to complete a `Deferred` synchronously in low-level code that already has
837 * the completion effect.
838 *
839 * **Details**
840 *
841 * This mutates the `Deferred` directly and should be reserved for low-level
842 * code; prefer the effectful completion APIs when possible. Returns `true` if
843 * this call completed the `Deferred`, or `false` if it was already completed.
844 *
845 * **Example** (Completing a Deferred unsafely)
846 *
847 * ```ts import.meta.vitest
848 * import { Deferred, Effect } from "effect"
849 *
850 * const deferred = Deferred.makeUnsafe<number>()
851 * Deferred.doneUnsafe(deferred, Effect.succeed(42)) // => true
852 * ```
853 *
854 * @category unsafe
855 * @since 4.0.0
856 */
857export const doneUnsafe = <A, E>(self: Deferred<A, E>, effect: Effect<A, E>): boolean => {
858 if (self.effect) return false
859 self.effect = effect
860 if (self.resumes) {
861 // Clear `resumes` before resuming: a waiter resumed with an interrupt
862 // cause dies synchronously inside `resume`, and its await cleanup would
863 // otherwise splice this array mid-iteration and skip the next waiter.
864 const resumes = self.resumes
865 self.resumes = undefined
866 for (let i = 0; i < resumes.length; i++) {
867 resumes[i](effect)
868 }
869 }
870 return true
871}
872
873/**
874 * Runs an `Effect` and attempts to complete a `Deferred` with the effect's
875 * result.
876 *
877 * **When to use**
878 *
879 * Use to pipe an effect result into a `Deferred` while preserving success,
880 * failure, defects, and interruption.
881 *
882 * **Details**
883 *
884 * If the effect succeeds, fails, dies, or is interrupted, that result is used
885 * as the attempted completion. The returned effect cannot fail; it succeeds
886 * with `true` if it completed the `Deferred`, or `false` if the `Deferred` was
887 * already completed.
888 *
889 * **Example** (Completing a Deferred from an effect result)
890 *
891 * ```ts import.meta.vitest
892 * import { Deferred, Effect } from "effect"
893 *
894 * const successEffect = Effect.succeed(42)
895 *
896 * const program = Effect.gen(function*() {
897 * const deferred = yield* Deferred.make<number, string>()
898 * const isCompleted = yield* Deferred.into(successEffect, deferred)
899 * const value = yield* Deferred.await(deferred)
900 * return [isCompleted, value]
901 * })
902 *
903 * await Effect.runPromise(program) // => [true, 42]
904 * ```
905 *
906 * @category completion
907 * @since 4.0.0
908 */
909export const into: {
910 <A, E>(deferred: Deferred<A, E>): <R>(self: Effect<A, E, R>) => Effect<boolean, never, R>
911 <A, E, R>(self: Effect<A, E, R>, deferred: Deferred<A, E>): Effect<boolean, never, R>
912} = dual(
913 2,
914 <A, E, R>(self: Effect<A, E, R>, deferred: Deferred<A, E>): Effect<boolean, never, R> =>
915 internalEffect.uninterruptibleMask((restore) =>
916 internalEffect.flatMap(
917 internalEffect.exit(restore(self)),
918 (exit) => done(deferred, exit)
919 )
920 )
921)