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:
parent
7d209454b1
commit
fdf83866cb
@ -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
|
||||
|
||||
|
@ -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]
|
||||
|
61
src/webassembly/borrow-checker.md
Normal file
61
src/webassembly/borrow-checker.md
Normal 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>
|
@ -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>
|
79
src/webassembly/expose-rust-type.md
Normal file
79
src/webassembly/expose-rust-type.md
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user