Rust compila a WebAssembly con rendimiento cercano al nativo. wasm-pack automatiza el proceso de compilación y empaquetado; wasm-bindgen genera los bindings entre Rust y JavaScript. El resultado es un módulo que puedes importar desde cualquier bundler moderno o directamente desde el navegador.
Configuración inicial
// Instalar las herramientas:
// cargo install wasm-pack
// cargo install wasm-bindgen-cli (opcional, wasm-pack lo gestiona)
// Cargo.toml
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
// Para acceder a APIs del navegador:
// [dependencies]
// web-sys = { version = "0.3", features = ["Window", "Document", "Element"] }
// js-sys = "0.3"
Exportar funciones a JavaScript
use wasm_bindgen::prelude::*;
// #[wasm_bindgen] hace la función visible desde JS
#[wasm_bindgen]
pub fn saludar(nombre: &str) -> String {
format!("Hola, {nombre}! Desde Rust/WebAssembly")
}
#[wasm_bindgen]
pub fn suma(a: f64, b: f64) -> f64 {
a + b
}
// Structs exportadas se convierten en clases JS
#[wasm_bindgen]
pub struct Punto {
x: f64,
y: f64,
}
#[wasm_bindgen]
impl Punto {
#[wasm_bindgen(constructor)]
pub fn new(x: f64, y: f64) -> Punto { Punto { x, y } }
pub fn distancia(&self, otro: &Punto) -> f64 {
let dx = self.x - otro.x;
let dy = self.y - otro.y;
(dx * dx + dy * dy).sqrt()
}
pub fn x(&self) -> f64 { self.x }
pub fn y(&self) -> f64 { self.y }
}
Compilar y usar desde JavaScript
// Compilar:
// wasm-pack build --target web
// El resultado en pkg/:
// mi_crate.js ? módulo JS con los bindings
// mi_crate_bg.wasm ? el binario WebAssembly
// mi_crate.d.ts ? tipos TypeScript generados automáticamente
// index.html / index.js:
// import init, { saludar, suma, Punto } from './pkg/mi_crate.js';
//
// async function main() {
// await init(); // carga el .wasm
//
// console.log(saludar("mundo")); // "Hola, mundo! Desde Rust/WebAssembly"
// console.log(suma(3.14, 2.86)); // 6
//
// const p1 = new Punto(0, 0);
// const p2 = new Punto(3, 4);
// console.log(p1.distancia(p2)); // 5
// }
// main();
Llamar a APIs del navegador con web-sys
use wasm_bindgen::prelude::*;
use web_sys::{window, HtmlElement};
#[wasm_bindgen]
pub fn cambiar_titulo(nuevo_titulo: &str) {
let win = window().unwrap();
let doc = win.document().unwrap();
doc.set_title(nuevo_titulo);
if let Some(h1) = doc.get_element_by_id("titulo") {
let el: HtmlElement = h1.dyn_into().unwrap();
el.set_inner_text(nuevo_titulo);
}
}
#[wasm_bindgen]
pub fn log(msg: &str) {
web_sys::console::log_1(&JsValue::from_str(msg));
}
Cálculo pesado: CRC32
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn crc32(data: &[u8]) -> u32 {
let mut crc: u32 = 0xFFFF_FFFF;
for &byte in data {
crc ^= byte as u32;
for _ in 0..8 {
if crc & 1 == 1 {
crc = (crc >> 1) ^ 0xEDB8_8320;
} else {
crc >>= 1;
}
}
}
!crc
}
// Desde JS:
// const encoder = new TextEncoder();
// const bytes = encoder.encode("hello world");
// console.log(crc32(bytes).toString(16)); // 0d4a1185
Pasar arrays JS nativos
use wasm_bindgen::prelude::*;
use js_sys::Float64Array;
#[wasm_bindgen]
pub fn estadisticas(datos: &[f64]) -> Float64Array {
let n = datos.len() as f64;
let media = datos.iter().sum::<f64>() / n;
let varianza = datos.iter()
.map(|x| (x - media).powi(2))
.sum::<f64>() / n;
let desviacion = varianza.sqrt();
let min = datos.iter().cloned().fold(f64::INFINITY, f64::min);
let max = datos.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
Float64Array::from(&[media, varianza, desviacion, min, max][..])
}
// Desde JS:
// const stats = estadisticas(new Float64Array([1,2,3,4,5]));
// console.log('Media:', stats[0], 'Desv:', stats[2]);
Resumen
wasm-pack build --target webcompila y genera los bindings JS listos para importar.#[wasm_bindgen]en funciones y structs las expone a JavaScript con tipos automáticamente convertidos.web-sysda acceso a todas las Web APIs del navegador; activa solo los features que necesitas.js-sysprovee tipos JS nativos comoFloat64Array,PromiseoObject.- wasm-bindgen genera tipos TypeScript (
.d.ts) sin ninguna configuración adicional. - El punto fuerte de Rust/WASM: cálculo intensivo (criptografía, compresión, procesamiento de imágenes) sin tocar el main thread de JavaScript.
