include_bytes("path") reads a file AT COMPILE TIME and puts its bytes into the binary, so the resource cannot get lost along the way — the real case: a UI that silently degrades to another typeface because someone copied only the executable, not the assets folder. The path is a literal, resolved from the project root and never from the file that uses it: with a variable the compiler rejects it with NYX1033.
// Nyx by Example: un recurso binario que viaja DENTRO del ejecutable. // // El caso real, en chico: un ERP que promete instalarse copiando un solo // ejecutable servía sus tipografías desde disco. Si alguien copiaba únicamente // el binario, la interfaz se degradaba a otra tipografía SIN AVISAR — el // servidor respondía 200 con un cuerpo vacío. `include_bytes` lee el archivo AL // COMPILAR y mete sus bytes en el binario, así que el recurso no se puede // perder por el camino. // // Lo que esta receta muestra: // 1. que los bytes llegan intactos (NUL incluidos — un .woff2 está lleno); // 2. que el valor sirve TAL CUAL como cuerpo de una respuesta HTTP; // 3. que dos llamadas a la misma ruta comparten un solo global. // // No abre un puerto a propósito: arma la respuesta en memoria y la describe, // así la receta corre sola bajo `make test-examples`. import "std/web" // La ruta es un LITERAL y se resuelve desde la raíz del proyecto, nunca desde // este archivo. Con una variable el compilador la rechaza con NYX1033: la ruta // tiene que conocerse al compilar. fn tipografia() -> String { return include_bytes("examples/by-example/assets/tipografia.woff2") } fn servir_tipografia() -> Response { let cuerpo: String = tipografia() var r: Response = response_new(200, cuerpo) // headers_flat es intercalado [nombre, valor, nombre, valor, ...]. r.headers_flat.push("Content-Type") r.headers_flat.push("font/woff2") // Un recurso empotrado es inmutable por definición: cambia solo si se // recompila, así que puede cachearse para siempre. r.headers_flat.push("Cache-Control") r.headers_flat.push("public, max-age=31536000, immutable") return r } fn main() { let datos: String = tipografia() // str_byte_length y NO length(): length() cuenta codepoints UTF-8, y esto // son bytes arbitrarios. Es el gotcha `strings-are-bytes` del repo. println("bytes: " + int_to_string(str_byte_length(datos))) // La firma del formato sobrevive, y el byte 8 es un NUL: si algo tratara // el recurso como cadena de C, el cuerpo se cortaría justo acá. println("firma: " + datos.substring(0, 4)) println("byte 8 (NUL): " + int_to_string(datos.charAt(8))) // La identidad byte a byte, medida: este sha256 es el del archivo en disco // (sha256sum examples/by-example/assets/tipografia.woff2). println("sha256: " + sha256(datos)) // La respuesta HTTP lleva el recurso entero, sin leer nada del disco. let resp: Response = servir_tipografia() println("respuesta: " + int_to_string(resp.status) + " con " + int_to_string(str_byte_length(resp.body)) + " bytes") // Dos llamadas a la MISMA ruta comparten un solo global: el recurso ocupa // sus bytes una vez, no una por uso. let otra: String = tipografia() if str_byte_length(otra) == str_byte_length(datos) { println("segunda llamada: el mismo recurso") } // Para leer un archivo AL EJECUTAR —algo que el usuario elige en tiempo de // corrida— lo que corresponde es read_file/try_read_file. include_bytes no // existe en el intérprete ni en el REPL: ahí responde NYX3007. }
bytes: 776 firma: wOF2 byte 8 (NUL): 0 sha256: 0d4f9fe0394d9008f67caddb00171ffe7a3a63aaac4ec225d66f5fadcc79c1d2 respuesta: 200 con 776 bytes segunda llamada: el mismo recurso
How it works
The bytes arrive intact, NULs included: a real .woff2 is full of them, which is why the recipe measures with str_byte_length and not length() — length() counts UTF-8 codepoints, these are arbitrary bytes (the repo's strings-are-bytes gotcha). Byte 8 of the file is a real NUL, and it is still a NUL once embedded.
The value works AS IS as an HTTP response body: servir_tipografia assigns it straight to Response.body, reading nothing from disk at runtime. Since the resource is immutable by definition — it only changes if the program is recompiled — the response can be cached forever (Cache-Control: public, max-age=31536000, immutable).
Two calls to the same path share a single global: the resource occupies its bytes ONCE in the binary, not once per use. For a file the user picks at runtime, the right tool is read_file/try_read_file, not include_bytes — which also does not exist in the interpreter or the REPL, where it answers NYX3007.