| 1 | /** |
| 2 | * Internal and advanced utilities used by Effect's generator-based syntax and |
| 3 | * higher-kinded type support. This is not a general-purpose utility module for |
| 4 | * application code. |
| 5 | * |
| 6 | * `SingleShotGen` makes an Effect-style value work with `yield*` inside |
| 7 | * generator helpers. `Variance` and `Gen` provide the type-level signatures |
| 8 | * used by modules such as `Effect`, `Option`, and `Result` to type their |
| 9 | * `gen` APIs. |
| 10 | * |
| 11 | * @since 2.0.0 |
| 12 | */ |
| 13 | import type { Kind, TypeLambda } from "./HKT.ts" |
| 14 | import { getStackTraceLimit } from "./internal/stackTraceLimit.ts" |
| 15 | import type * as Types from "./Types.ts" |
| 16 | |
| 17 | /** |
| 18 | * Yields its wrapped value exactly once, then completes with the value sent |
| 19 | * back in. |
| 20 | * |
| 21 | * **When to use** |
| 22 | * |
| 23 | * Use to implement `[Symbol.iterator]()` on Effect-like types so they can be |
| 24 | * `yield*`-ed inside generator functions, such as `Effect.gen` and |
| 25 | * `Option.gen`. |
| 26 | * |
| 27 | * **Details** |
| 28 | * |
| 29 | * The first call to `next()` returns a fresh `{ value: self, done: false }`. |
| 30 | * Every subsequent call returns `{ value: a, done: true }` where `a` is the |
| 31 | * argument passed to `next()`. To keep `yield*` cheap, the completion result |
| 32 | * is the iterator itself rather than a new object, so only the iterator and |
| 33 | * the single yielded result are allocated per `yield*`. |
| 34 | * |
| 35 | * **Example** (Yielding a wrapped value in a generator) |
| 36 | * |
| 37 | * ```ts import.meta.vitest |
| 38 | * import { Utils } from "effect" |
| 39 | * |
| 40 | * const gen = new Utils.SingleShotGen<string, number>("hello") |
| 41 | * |
| 42 | * gen.next(0).value // => "hello" |
| 43 | * |
| 44 | * gen.next(42).value // => 42 |
| 45 | * ``` |
| 46 | * |
| 47 | * @see {@link Gen} for the type-level signature that relies on `SingleShotGen` |
| 48 | * @category constructors |
| 49 | * @since 2.0.0 |
| 50 | */ |
| 51 | export class SingleShotGen<T, A> implements Iterator<T, A> { |
| 52 | declare private value: T | A |
| 53 | declare private done: boolean |
| 54 | |
| 55 | constructor(self: T) { |
| 56 | this.value = self |
| 57 | this.done = false |
| 58 | } |
| 59 | |
| 60 | /** |
| 61 | * Yields the stored value once, then completes with the value sent back in. |
| 62 | * |
| 63 | * **When to use** |
| 64 | * |
| 65 | * Use to advance a `SingleShotGen` through its single yield and completion |
| 66 | * step. |
| 67 | * |
| 68 | * @since 2.0.0 |
| 69 | */ |
| 70 | next(a: A): IteratorResult<T, A> { |
| 71 | if (this.done) { |
| 72 | this.value = a |
| 73 | return this as unknown as IteratorReturnResult<A> |
| 74 | } |
| 75 | this.done = true |
| 76 | return { value: this.value as T, done: false } |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | /** |
| 81 | * Type-level marker encoding the variance of a `TypeLambda`'s type |
| 82 | * parameters. |
| 83 | * |
| 84 | * **When to use** |
| 85 | * |
| 86 | * Use to define variance constraints for a higher-kinded type so that |
| 87 | * {@link Gen} can correctly infer `R`, `O`, and `E` from yielded values. |
| 88 | * |
| 89 | * **Details** |
| 90 | * |
| 91 | * `F` is invariant and must match exactly. `R` is contravariant in the input |
| 92 | * or environment position. `O` and `E` are covariant in the output and error |
| 93 | * positions. This is a pure type-level construct with no runtime |
| 94 | * representation. |
| 95 | * |
| 96 | * **Example** (Declaring variance for a TypeLambda) |
| 97 | * |
| 98 | * ```ts import.meta.vitest |
| 99 | * import type { Option, Utils } from "effect" |
| 100 | * |
| 101 | * const variance: Utils.Variance< |
| 102 | * Option.OptionTypeLambda, |
| 103 | * unknown, |
| 104 | * string, |
| 105 | * string |
| 106 | * > = { |
| 107 | * _F: (value) => value, |
| 108 | * _R: () => {}, |
| 109 | * _O: () => "output", |
| 110 | * _E: () => "error" |
| 111 | * } |
| 112 | * Array.of(variance._O(undefined as never), variance._E(undefined as never)) // => ["output", "error"] |
| 113 | * ``` |
| 114 | * |
| 115 | * @see {@link Gen} for the type-level signature that uses `Variance` |
| 116 | * @category models |
| 117 | * @since 2.0.0 |
| 118 | */ |
| 119 | export interface Variance<in out F extends TypeLambda, in R, out O, out E> { |
| 120 | readonly _F: Types.Invariant<F> |
| 121 | readonly _R: Types.Contravariant<R> |
| 122 | readonly _O: Types.Covariant<O> |
| 123 | readonly _E: Types.Covariant<E> |
| 124 | } |
| 125 | |
| 126 | /** |
| 127 | * Type-level signature for generator-based monadic composition over any |
| 128 | * `TypeLambda`. |
| 129 | * |
| 130 | * **When to use** |
| 131 | * |
| 132 | * Use to type the `gen` function of a module that supports generator syntax, |
| 133 | * such as `Option.gen`, `Result.gen`, and `Effect.gen`. |
| 134 | * |
| 135 | * **Details** |
| 136 | * |
| 137 | * This is a pure type alias with no runtime behavior. It infers `R`, `O`, and |
| 138 | * `E` from the yielded values via {@link Variance} or `Kind` constraints. The |
| 139 | * generator's return type `A` becomes the output's `A` parameter. |
| 140 | * |
| 141 | * **Example** (Typing a gen function for Option) |
| 142 | * |
| 143 | * ```ts import.meta.vitest |
| 144 | * import { Option } from "effect" |
| 145 | * import type { Utils } from "effect" |
| 146 | * |
| 147 | * const gen: Utils.Gen<Option.OptionTypeLambda> = Option.gen |
| 148 | * const result = gen(function*() { |
| 149 | * return yield* Option.some(1) |
| 150 | * }) |
| 151 | * result // => Option.some(1) |
| 152 | * ``` |
| 153 | * |
| 154 | * @see {@link Variance} for encoding the variance used for inference |
| 155 | * @see {@link SingleShotGen} for the iterator protocol that makes yielding work |
| 156 | * @category models |
| 157 | * @since 2.0.0 |
| 158 | */ |
| 159 | export type Gen<F extends TypeLambda> = < |
| 160 | Self, |
| 161 | K extends Variance<F, any, any, any> | Kind<F, any, any, any, any>, |
| 162 | A |
| 163 | >( |
| 164 | ...args: |
| 165 | | [ |
| 166 | self: Self, |
| 167 | body: (this: Self) => Generator<K, A, never> |
| 168 | ] |
| 169 | | [ |
| 170 | body: () => Generator<K, A, never> |
| 171 | ] |
| 172 | ) => Kind< |
| 173 | F, |
| 174 | [K] extends [Variance<F, infer R, any, any>] ? R |
| 175 | : [K] extends [Kind<F, infer R, any, any, any>] ? R |
| 176 | : never, |
| 177 | [K] extends [Variance<F, any, infer O, any>] ? O |
| 178 | : [K] extends [Kind<F, any, infer O, any, any>] ? O |
| 179 | : never, |
| 180 | [K] extends [Variance<F, any, any, infer E>] ? E |
| 181 | : [K] extends [Kind<F, any, any, infer E, any>] ? E |
| 182 | : never, |
| 183 | A |
| 184 | > |
| 185 | |
| 186 | // the probe is wrapped in a single function call (rather than module-level |
| 187 | // statements) so the whole selection is pure-annotated by the build and |
| 188 | // tree-shakable when `internalCall` is unused. |
| 189 | const pickInternalCall = (): <A>(body: () => A) => A => { |
| 190 | const InternalTypeId = "~effect/Utils/internal" |
| 191 | |
| 192 | const standard = { |
| 193 | [InternalTypeId]: <A>(body: () => A) => { |
| 194 | return body() |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | const forced = { |
| 199 | [InternalTypeId]: <A>(body: () => A) => { |
| 200 | try { |
| 201 | return body() |
| 202 | } finally { |
| 203 | // |
| 204 | } |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | const isNotOptimizedAway = getStackTraceLimit() !== 0 && |
| 209 | standard[InternalTypeId](() => new Error().stack)?.includes(InternalTypeId) === true |
| 210 | |
| 211 | return isNotOptimizedAway ? standard[InternalTypeId] : forced[InternalTypeId] |
| 212 | } |
| 213 | |
| 214 | /** @internal */ |
| 215 | export const internalCall = pickInternalCall() |