Rust
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Ownership and Borrowing
-
Section 4: Structuring Data
-
Section 5: Collections and Error Handling
-
Section 6: Traits and Generics
-
Section 7: Concurrency
-
Section 8: Building for the Web
-
Section 9: Memory and Performance
-
Section 10: More Standard Library and Ecosystem
-
Section 11: Advanced Rust
-
Section 12: Rust for Systems and WebAssembly
-
Section 13: Tooling and Best Practices
-
Section 14: Data Structures and Algorithms in Rust
-
Section 15: Practical Projects
-
Section 16: Interview Practice
-
Section 17: std::collections In Depth
-
Section 18: std::io and std::fs In Depth
-
Section 19: std::net
-
Section 20: std::option and std::result In Depth
-
Section 21: std::iter In Depth
-
Section 22: std::sync In Depth
-
Section 23: std::string and std::str
-
Section 24: Cargo and Crates.io Ecosystem
-
Section 25: Popular Crates Ecosystem
-
Section 26: Rust Memory Model Deep Dive
-
Section 27: More Practice Exercises
-
Section 28: More Interview Practice
-
Section 29: Async Rust Deep Dive
-
Section 30: Tokio Ecosystem In Depth
-
Section 31: Error Handling Ecosystem Deep Dive
-
Section 32: Serde In Depth
-
Section 33: Web Development with Rust Deep Dive
-
Section 34: Database Access Ecosystem
-
Section 35: Rust for Embedded Systems Deep Dive
-
Section 36: Rust Macros In Depth
-
Section 37: Advanced Trait System
-
Section 38: Unsafe Rust In Depth
-
Section 39: Rust CLI Development
-
Section 40: Testing Ecosystem Deep Dive
-
Section 41: WebAssembly Deep Dive
-
Section 42: Rust Design Patterns
-
Section 43: More Data Structures in Rust
-
Section 44: Final Practice Projects
-
Section 45: Rust Performance Optimization
-
Section 46: Rust Ecosystem Tooling
-
Section 47: More Interview and Review
212: wasm-bindgen for JS Interop
By now, you know that WebAssembly is great for performance, but it's essentially a sandbox. It doesn't "know" about the DOM, the window, or your JavaScript variables. That's where wasm-bindgen comes in. It's the glue that lets you pass strings, objects, and functions back and forth between the two worlds.
How do I actually make a Rust function callable from JavaScript?
The short answer is the #[wasm_bindgen] attribute. When you tag a public function with this, the tool generates a JavaScript wrapper that handles all the messy memory management for you. Instead of dealing with raw pointers and linear memory, you just call a regular JS function.
Let's say we're building a game and we want Rust to handle the "Combat Math" because it's computationally heavy. Here is how you'd expose a function to calculate damage:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn calculate_damage(base_attack: f64, defense: f64, crit_multiplier: f64) -> f64 {
let damage = base_attack - defense;
if damage < 0.0 {
return 0.0;
}
// Imagine more complex math here
damage * crit_multiplier
}
Once you compile this with wasm-pack, you can just import it in your JS file like any other module: import { calculate_damage } from './pkg/my_game_engine';. I've found that keeping your "business logic" in Rust and your "UI logic" in JS is the sweet spot for most Wasm projects.
Can Rust call JavaScript functions, or is it a one-way street?
It's definitely a two-way street. You can "import" JavaScript functions into Rust. You do this by using an extern "C" block decorated with #[wasm_bindgen]. This tells Rust: "Trust me, this function will exist in the JS environment when the code actually runs."
A common use case is logging or triggering a UI alert. If you want to call a custom JS function called showNotification from your Rust logic, it looks like this:
#[wasm_bindgen]
extern "C" {
// This tells Rust that JS has a function with this signature
fn showNotification(message: &str);
}
#[wasm_bindgen]
pub fn level_up(current_level: i32) {
let new_level = current_level + 1;
// Now we call the JS function directly!
showNotification(&format!("Congratulations! You reached level {}", new_level));
}
One thing to watch out for: if you call a function in the extern block that doesn't actually exist in your JS environment, the app will crash at runtime. There's no compile-time check for JS functions because Rust has no way of knowing what your JS file looks like.
How do I move complex data, like structs, between the two?
Passing a single number is easy, but passing a full object is where people usually get stuck. You can't just send a Rust struct to JS because the memory layouts are completely different. However, wasm-bindgen allows you to export structs as JS classes.
Check out this example of a Player profile. By marking the struct and its impl block with #[wasm_bindgen], Rust creates a JS class that wraps the Wasm memory pointer.
#[wasm_bindgen]
pub struct Player {
name: String,
health: i32,
}
#[wasm_bindgen]
impl Player {
#[wasm_bindgen(constructor)]
pub fn new(name: String, health: i32) -> Player {
Player { name, health }
}
pub fn take_damage(&mut self, amount: i32) {
self.health -= amount;
}
pub fn get_health(&self) -> i32 {
self.health
}
}
In JavaScript, this looks incredibly natural: const hero = new Player("Aragorn", 100); hero.take_damage(20); console.log(hero.get_health());. Just keep in mind that the Player object in JS is actually a pointer to memory inside the Wasm linear heap. If you're doing this with thousands of objects, be mindful of memory leaks—you'll need to call hero.free() in JS if you want to manually drop the Rust object before the JS garbage collector gets around to it.
📋 Practical Task
Exercise: Build a Rust-powered Password Strength Validator
Your goal is to create a small interop bridge that validates password strength in Rust and reports the result back to JavaScript.
- The Rust Side: Create a function
check_password_strengththat takes aString. It should return an integer:0for "Weak" (less than 8 characters),1for "Medium" (8+ characters but no numbers), and2for "Strong" (8+ characters including at least one digit). - The JS Side: Create a JavaScript function that calls your Rust validator. Based on the returned number (0, 1, or 2), it should call a JS
alert()saying "Weak", "Medium", or "Strong". - The Glue: Ensure you use the
#[wasm_bindgen]attribute on the Rust function so it is exported correctly.
There are no comments for now.