/** * Plain, structured-clone-friendly mirror of the numbl values the lab uses. * Tensors keep numbl's column-major layout: element (i, j) of an [m, n] array is * data[i + j*m], and (i, j, k) of an [m, n, p] array is data[i + j*m + k*m*n]. */ export interface PlainTensor { kind: "tensor"; shape: number[]; data: Float64Array; imag?: Float64Array; } export interface PlainStruct { kind: "struct"; fields: Record; } export interface PlainCell { kind: "cell"; shape: number[]; items: PlainValue[]; } export interface PlainUnsupported { kind: "unsupported"; description: string; } export type PlainValue = number | boolean | string | PlainTensor | PlainStruct | PlainCell | PlainUnsupported; export function isPlainTensor(v: PlainValue | undefined): v is PlainTensor { return typeof v === "object" && v !== null && v.kind === "tensor"; } export function isPlainStruct(v: PlainValue | undefined): v is PlainStruct { return typeof v === "object" && v !== null && v.kind === "struct"; } export function isPlainCell(v: PlainValue | undefined): v is PlainCell { return typeof v === "object" && v !== null && v.kind === "cell"; } /** All ArrayBuffers inside a value, for zero-copy transfer out of a worker. */ export function collectBuffers(v: PlainValue, out: ArrayBuffer[] = []): ArrayBuffer[] { if (isPlainTensor(v)) { out.push(v.data.buffer as ArrayBuffer); if (v.imag) out.push(v.imag.buffer as ArrayBuffer); } else if (isPlainStruct(v)) { for (const f of Object.values(v.fields)) collectBuffers(f, out); } else if (isPlainCell(v)) { for (const item of v.items) collectBuffers(item, out); } return out; }