Trabalhando com WebAssembly e Rust: métodos avançados de integração na web

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que Rust e WebAssembly em nível avançado

\n

WebAssembly (Wasm) e Rust são uma combinação que permite transferir tarefas computacionalmente pesadas do JavaScript para código nativo de alto desempenho executado no navegador. No nível básico, você já pode ter se familiarizado com a compilação de funções simples. No entanto, para criar produtos reais — motores de jogos, processadores de imagens, parsers ou bibliotecas criptográficas — é necessário um profundo entendimento do gerenciamento de memória, transmissão de estruturas de dados complexas e interação com o ambiente externo.

\n

Neste artigo, abordaremos técnicas avançadas de trabalho com WebAssembly em Rust: desde o gerenciamento manual de memória até a criação de aplicações híbridas, onde Rust e JavaScript funcionam como um todo. O material é voltado para desenvolvedores que já conhecem os fundamentos de Rust e Wasm.

\n\n

1. Gerenciamento de memória: memória linear e alocadores

\n

Ao contrário do JavaScript, o WebAssembly usa memória linear — um array plano de bytes. O código Rust compilado para Wasm trabalha diretamente com essa memória. Para um trabalho eficiente, é necessário entender como alocar e liberar memória manualmente.

\n\n

1.1. Alocação manual de memória com wasm_bindgen

\n

A biblioteca wasm-bindgen fornece abstrações convenientes, mas em nível avançado, muitas vezes é necessário acesso direto à memória. Vejamos um exemplo:

\n
use wasm_bindgen::prelude::*;\nuse std::mem;\nuse std::slice;\n\n#[wasm_bindgen]\npub fn allocate_buffer(size: usize) -> *mut u8 {\n    let mut buf = Vec::with_capacity(size);\n    let ptr = buf.as_mut_ptr();\n    mem::forget(buf); // impede a remoção do vetor\n    ptr\n}\n\n#[wasm_bindgen]\npub fn deallocate_buffer(ptr: *mut u8, size: usize) {\n    unsafe {\n        let _ = Vec::from_raw_parts(ptr, 0, size);\n    }\n}\n\n#[wasm_bindgen]\npub fn fill_buffer(ptr: *mut u8, value: u8, len: usize) {\n    let slice = unsafe { slice::from_raw_parts_mut(ptr, len) };\n    for byte in slice.iter_mut() {\n        *byte = value;\n    }\n}
\n

Aqui alocamos memória através de Vec, "esquecemos" dele (para que o Rust não remova o buffer) e passamos o ponteiro para o JavaScript. A função deallocate_buffer restaura o vetor e libera a memória corretamente.

\n\n

1.2. Uso de um alocador personalizado

\n

Para projetos complexos, vale a pena substituir o alocador padrão por um mais previsível. Por exemplo, wee_alloc é um alocador pequeno, otimizado para Wasm:

\n
// em Cargo.toml\n// [dependencies]\n// wee_alloc = "0.4"\n\n#[global_allocator]\nstatic ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
\n

Isso reduzirá o tamanho do arquivo .wasm final e acelerará a alocação de memória no navegador.

\n\n

2. Transmissão de estruturas de dados complexas entre Rust e JavaScript

\n

Em nível avançado, você não se limita a números e strings. É necessário transmitir arrays, estruturas e até closures.

\n\n

2.1. Estruturas com #[wasm_bindgen]

\n

Você pode exportar estruturas Rust inteiras como classes JavaScript:

\n
#[wasm_bindgen]\npub struct Matrix {\n    rows: usize,\n    cols: usize,\n    data: Vec<f64>,\n}\n\n#[wasm_bindgen]\nimpl Matrix {\n    #[wasm_bindgen(constructor)]\n    pub fn new(rows: usize, cols: usize) -> Matrix {\n        Matrix {\n            rows,\n            cols,\n            data: vec![0.0; rows * cols],\n        }\n    }\n\n    pub fn get(&self, row: usize, col: usize) -> f64 {\n        self.data[row * self.cols + col]\n    }\n\n    pub fn set(&mut self, row: usize, col: usize, val: f64) {\n        self.data[row * self.cols + col] = val;\n    }\n\n    pub fn multiply(&self, other: &Matrix) -> Result<Matrix, String> {\n        if self.cols != other.rows {\n            return Err("Dimensões incompatíveis".to_string());\n        }\n        // ... implementação da multiplicação de matrizes\n        let result = Matrix::new(self.rows, other.cols);\n        Ok(result)\n                

Blogs

Book Recommendations