Con la arena por evento encendida (runNyxWasm(bytes, { arena: true })) todo lo que un handler aloca se descarta al terminar el evento. Un String o un Array armado en un evento y guardado en un global se leería en el evento siguiente como memoria reciclada, en silencio y sin ningún error. arena_persist(x) lo copia antes a la región persistente: lo que se guarda a propósito sobrevive y todo lo demás se sigue recuperando.
// 121 — wasm: guardar entre eventos un valor que nació en un evento // wasm: keep a value born in one event for the next ones // // Target wasm32-wasi (corre en el navegador, o bajo node con // examples/browser/run-node.mjs). Con la arena por evento encendida // (`runNyxWasm(bytes, { arena: true })`), todo lo que un handler aloca se // descarta al terminar el evento. Un String o un Array armado en un evento y // guardado en un global se leería en el evento siguiente como memoria // reciclada, en silencio. // // arena_persist(x) lo copia a la región persistente: // - acepta un String, o un Array de String/int/float/bool (y arrays de // esos: una línea de ticket con sus modificadores se copia entera); // - un struct, un Map, un Fn o un Array<Struct> es NYX1039 al compilar: no // llevan en tiempo de ejecución la descripción de lo que contienen. // Persiste sus campos uno por uno y reconstruye el valor donde se usa; // - es un builtin: no hace falta importar nada, y en nativo es la identidad // (no hay arena), así que la lógica que lo usa corre con `nyx test`. // // arena_stats() (import "std/wasm_mem", solo wasm) da los bytes persistentes // y los del turno, para vigilar que una página larga no crezca sin control. // // Construir: nyx build --target wasm32-wasi import "std/wasm_mem" var g_ultimo_codigo: String = "" var g_ticket: Array = [] // Cada escaneo arma un String y una línea de ticket DURANTE el evento. #[export_name = "al_escanear"] fn al_escanear(n: int) { let codigo: String = "SKU-" + int_to_string(n) g_ultimo_codigo = arena_persist(codigo) let modificadores: Array = ["sin hielo", "grande"] let linea: Array = [codigo, int_to_float(n) * 1.5, n % 2 == 0, modificadores] g_ticket = arena_persist(linea) } // Un evento posterior lee lo guardado: sigue intacto. #[export_name = "al_cobrar"] fn al_cobrar() -> int { let precio: float = g_ticket[1] let mods: Array = g_ticket[3] let primero: String = mods[0] print("cobrando " + g_ultimo_codigo + " a " + float_to_string(precio) + " (" + primero + ")") return g_ultimo_codigo.length() } // Diagnóstico: lo persistido solo crece con lo que se guarda a propósito. #[export_name = "memoria"] fn memoria() -> int { let st: ArenaStats = arena_stats() return st.persistent } fn main() { print("listo: la página llama a al_escanear y a al_cobrar") }
listo: la página llama a al_escanear y a al_cobrar cobrando SKU-7 a 10.5 (sin hielo)
Cómo funciona
Acepta un String o un Array de String, int, float y bool — incluso arrays de esos, así que una línea de ticket con sus modificadores se copia entera, como muestra g_ticket. Un struct, un Map, un Fn o un Array<Struct> es un error de compilación (NYX1039): en tiempo de ejecución no llevan la descripción de lo que contienen, así que se persisten sus campos uno por uno y el valor se reconstruye donde se usa.
arena_persist es un builtin, de modo que no se importa nada, y en nativo es la identidad (no hay arena). Eso permite que la lógica que lo rodea corra con nyx test. arena_stats(), de std/wasm_mem y solo para wasm, devuelve los bytes persistentes y los del turno, que es como una página de larga vida vigila que no crezca sin control. Esta es una receta de navegador — se construye con nyx build --target wasm32-wasi y la página llama a sus exports — así que la salida de arriba es ilustrativa.