Files
nix-js/nix-js/runtime-ts/src/thunk.ts
2026-01-10 22:04:23 +08:00

75 lines
1.9 KiB
TypeScript

/**
* Lazy evaluation system for nix-js
* Implements thunks for lazy evaluation of Nix expressions
*/
import type { NixValue, NixThunkInterface, NixStrictValue } from "./types";
/**
* Symbol used to mark objects as thunks
* This is exported to Rust via Nix.IS_THUNK
*/
export const IS_THUNK = Symbol("is_thunk");
/**
* NixThunk class - represents a lazy, unevaluated expression
*
* A thunk wraps a function that produces a value when called.
* Once evaluated, the result is cached to avoid recomputation.
*/
export class NixThunk implements NixThunkInterface {
[key: symbol]: any;
readonly [IS_THUNK] = true as const;
func: (() => NixValue) | undefined;
result: NixStrictValue | undefined;
constructor(func: () => NixValue) {
this.func = func;
this.result = undefined;
}
}
/**
* Type guard to check if a value is a thunk
* @param value - Value to check
* @returns true if value is a NixThunk
*/
export const isThunk = (value: unknown): value is NixThunkInterface => {
return value !== null && typeof value === "object" && IS_THUNK in value && value[IS_THUNK] === true;
};
/**
* Force evaluation of a value
* If the value is a thunk, evaluate it and cache the result
* If already evaluated or not a thunk, return as-is
*
* @param value - Value to force (may be a thunk)
* @returns The forced/evaluated value
*/
export const force = (value: NixValue): NixStrictValue => {
if (!isThunk(value)) {
return value;
}
// Already evaluated - return cached result
if (value.func === undefined) {
return value.result!;
}
// Evaluate and cache
const result = force(value.func());
value.result = result;
value.func = undefined;
return result;
};
/**
* Create a new thunk from a function
* @param func - Function that produces a value when called
* @returns A new NixThunk wrapping the function
*/
export const createThunk = (func: () => NixValue): NixThunkInterface => {
return new NixThunk(func);
};