1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2025-05-23 19:00:13 +02:00

expose-rust-type

This commit is contained in:
sakex 2023-07-21 18:11:48 +02:00
parent 7d209454b1
commit fdf83866cb
5 changed files with 153 additions and 5 deletions

View File

@ -302,6 +302,8 @@
- [WebAssembly basics](webassembly.md)
- [Load a WASM module](webassembly/load-wasm-module.md)
- [Expose a method](webassembly/expose-method.md)
- [Expose user-defined Rust types](webassembly/expose-rust-type.md)
- [Borrow Checker](webassembly/borrow-checker.md)
# Final Words

View File

@ -5,25 +5,25 @@ use std::path::PathBuf;
#[get("/")]
async fn index() -> Result<NamedFile> {
let path: PathBuf = "./files/index.html".parse()?;
Ok(NamedFile::open(path)?)
Ok(NamedFile::open(path)?.use_last_modified(true))
}
#[get("/files/{name}")]
async fn files(web::Path(name): web::Path<String>) -> Result<NamedFile> {
let path: PathBuf = format!("./files/{}", name).parse()?;
Ok(NamedFile::open(path)?)
Ok(NamedFile::open(path)?.use_last_modified(true))
}
#[get("/font.otf")]
async fn font() -> Result<NamedFile> {
let path: PathBuf = "./files/source-code-regular.otf".parse()?;
Ok(NamedFile::open(path)?)
Ok(NamedFile::open(path)?.use_last_modified(true))
}
#[get("/wasm/{name}")]
async fn serve_wasm(web::Path(name): web::Path<String>) -> Result<NamedFile> {
let path: PathBuf = format!("./pkg/{}", name).parse()?;
Ok(NamedFile::open(path)?)
Ok(NamedFile::open(path)?.use_last_modified(true))
}
#[get("/wasm/snippets/{snippet_name}/{name}")]
@ -31,7 +31,7 @@ async fn serve_wasm_snippet(
web::Path((snippet_name, name)): web::Path<(String, String)>,
) -> Result<NamedFile> {
let path: PathBuf = format!("./pkg/snippets/{}/{}", snippet_name, name).parse()?;
Ok(NamedFile::open(path)?)
Ok(NamedFile::open(path)?.use_last_modified(true))
}
#[actix_web::main]

View File

@ -0,0 +1,61 @@
# Borrow Checker
Types annotated with `wasm_bindgen` can reference each other.
```rust
#[wasm_bindgen]
pub struct MultiCounter {
// We use the counter from the previous slide
counters: Vec<Counter>,
}
#[wasm_bindgen]
impl MultiCounter {
#[wasm_bindgen(constructor)]
pub fn new() -> MultiCounter {
MultiCounter { counters: Vec::new() }
}
pub fn increment(&mut self) {
for counter in &mut self.counters {
counter.increment();
}
}
pub fn add_counter(&mut self, counter: Counter) {
self.counter.push(counter);
}
}
```
But what happens when you call `add_counter` from Javascript ?
```javascript
import init, {set_panic_hook, Counter, MultiCounter} from '/wasm/project.js';
(async () => {
// Run the init method to initiate the WebAssembly module.
await init();
set_panic_hook();
const wasmOutput = document.querySelector("#wasmoutput");
const button = document.querySelector("#button");
const counter = new Counter("ButtonCounter", 42);
counter.increment();
// Works fine
wasmOutput.textContent = counter.count;
const multiCounter = new MultiCounter();
// Move counter into the MultiCounter
multiCounter.add_counter(counter);
// Error: Open console
counter.increment();
})();
```
<details>
* `counter` is moved before the second call, so the code panics
* Ownership rules must be respected
</details>

View File

@ -21,3 +21,9 @@ pub fn add(a: i32, b: i32) -> i32 {
a + b
}
```
<details>
* `set_panic_hook` is a convenient setup method that adds debug information to stack traces when a WASM module panics. Don't use it in prod builds because it is rather
</details>

View File

@ -0,0 +1,79 @@
# Expose user-defined Rust types
Similarily to methods, types can be exposed from Rust to Javascript with the `#[wasm_bindgen]` macro.
Members that implement `Copy` can be public and directly accessed from Javascript.
```rust
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct Counter {
name: String,
pub count: u8,
}
```
Methods can also be exported
```rust
#[wasm_bindgen]
impl Counter {
// Constructor will be called in JS when using `new Counter(name, count)`
#[wasm_bindgen(constructor)]
pub fn new(name: String, count: u8) -> Counter {
Counter { name, count }
}
pub fn increment(&mut self) {
self.count += 1;
}
// Getter for the name
#[wasm_bindgen(getter)]
pub fn name(&self) -> String {
self.name.clone()
}
// Setter for the name
#[wasm_bindgen(setter)]
pub fn set_name(&mut self, name: String) {
self.name = name;
}
}
```
Add this button to the HTML file
```html
<button id="button">Increment</button>
```
Javascript to use the `Counter`
```javascript
import init, { set_panic_hook, Counter } from "/wasm/project.js";
(async () => {
// Run the init method to initiate the WebAssembly module.
await init();
set_panic_hook();
const wasmOutput = document.querySelector("#wasmoutput");
const button = document.querySelector("#button");
const counter = new Counter("ButtonCounter", 42);
wasmOutput.textContent = counter.count;
button.addEventListener("click", () => {
// Calls the getter
console.log("Button clicked!", counter.name);
counter.increment();
wasmOutput.textContent = counter.count;
});
})();
```
<details>
- `pub` members must implement copy
- Type parameters and lifetime annotations are not supported yet
</details>