/** * Internal and advanced utilities used by Effect's generator-based syntax and * higher-kinded type support. This is not a general-purpose utility module for * application code. * * `SingleShotGen` makes an Effect-style value work with `yield*` inside * generator helpers. `Variance` and `Gen` provide the type-level signatures * used by modules such as `Effect`, `Option`, and `Result` to type their * `gen` APIs. * * @stability stable * @since 2.0.0 */ import type { Kind, TypeLambda } from "./HKT.ts" import { getStackTraceLimit, setStackTraceLimit } from "./internal/stackTraceLimit.ts" import type * as Types from "./Types.ts" /** * Yields its wrapped value exactly once, then completes with the value sent * back in. * * **When to use** * * Use to implement `[Symbol.iterator]()` on Effect-like types so they can be * `yield*`-ed inside generator functions, such as `Effect.gen` and * `Option.gen`. * * **Details** * * The first call to `next()` returns a fresh `{ value: self, done: false }`. * Every subsequent call returns `{ value: a, done: true }` where `a` is the * argument passed to `next()`. To keep `yield*` cheap, the completion result * is the iterator itself rather than a new object, so only the iterator and * the single yielded result are allocated per `yield*`. * * **Example** (Yielding a wrapped value in a generator) * * ```ts import.meta.vitest * import { Utils } from "effect" * * const gen = new Utils.SingleShotGen("hello") * * gen.next(0).value // => "hello" * * gen.next(42).value // => 42 * ``` * * @see {@link Gen} for the type-level signature that relies on `SingleShotGen` * @stability stable * @category constructors * @since 2.0.0 */ export class SingleShotGen implements Iterator { declare private value: T | A declare private done: boolean constructor(self: T) { this.value = self this.done = false } /** * Yields the stored value once, then completes with the value sent back in. * * **When to use** * * Use to advance a `SingleShotGen` through its single yield and completion * step. * * @since 2.0.0 */ next(a: A): IteratorResult { if (this.done) { this.value = a return this as unknown as IteratorReturnResult } this.done = true return { value: this.value as T, done: false } } } /** * Type-level marker encoding the variance of a `TypeLambda`'s type * parameters. * * **When to use** * * Use to define variance constraints for a higher-kinded type so that * {@link Gen} can correctly infer `R`, `O`, and `E` from yielded values. * * **Details** * * `F` is invariant and must match exactly. `R` is contravariant in the input * or environment position. `O` and `E` are covariant in the output and error * positions. This is a pure type-level construct with no runtime * representation. * * **Example** (Declaring variance for a TypeLambda) * * ```ts import.meta.vitest * import type { Option, Utils } from "effect" * * const variance: Utils.Variance< * Option.OptionTypeLambda, * unknown, * string, * string * > = { * _F: (value) => value, * _R: () => {}, * _O: () => "output", * _E: () => "error" * } * Array.of(variance._O(undefined as never), variance._E(undefined as never)) // => ["output", "error"] * ``` * * @see {@link Gen} for the type-level signature that uses `Variance` * @stability stable * @category models * @since 2.0.0 */ export interface Variance { readonly _F: Types.Invariant readonly _R: Types.Contravariant readonly _O: Types.Covariant readonly _E: Types.Covariant } /** * Type-level signature for generator-based monadic composition over any * `TypeLambda`. * * **When to use** * * Use to type the `gen` function of a module that supports generator syntax, * such as `Option.gen`, `Result.gen`, and `Effect.gen`. * * **Details** * * This is a pure type alias with no runtime behavior. It infers `R`, `O`, and * `E` from the yielded values via {@link Variance} or `Kind` constraints. The * generator's return type `A` becomes the output's `A` parameter. * * **Example** (Typing a gen function for Option) * * ```ts import.meta.vitest * import { Option } from "effect" * import type { Utils } from "effect" * * const gen: Utils.Gen = Option.gen * const result = gen(function*() { * return yield* Option.some(1) * }) * result // => Option.some(1) * ``` * * @see {@link Variance} for encoding the variance used for inference * @see {@link SingleShotGen} for the iterator protocol that makes yielding work * @stability stable * @category models * @since 2.0.0 */ export type Gen = < Self, K extends Variance | Kind, A >( ...args: | [ self: Self, body: (this: Self) => Generator ] | [ body: () => Generator ] ) => Kind< F, [K] extends [Variance] ? R : [K] extends [Kind] ? R : never, [K] extends [Variance] ? O : [K] extends [Kind] ? O : never, [K] extends [Variance] ? E : [K] extends [Kind] ? E : never, A > // the probe is wrapped in a single function call (rather than module-level // statements) so the whole selection is pure-annotated by the build and // tree-shakable when `internalCall` is unused. const pickInternalCall = (): (body: () => A) => A => { const InternalTypeId = "~effect/Utils/internal" const standard = { [InternalTypeId]: (body: () => A) => { return body() } } const forced = { [InternalTypeId]: (body: () => A) => { try { return body() } finally { // } } } const limit = getStackTraceLimit() if (limit === 0) return forced[InternalTypeId] // Only the callback and internal call frames are needed for detection. setStackTraceLimit(2) const error = standard[InternalTypeId](() => new Error()) setStackTraceLimit(limit) return error.stack?.includes(InternalTypeId) === true ? standard[InternalTypeId] : forced[InternalTypeId] } /** @internal */ export const internalCall = pickInternalCall()