mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-05-24 19:23:46 +02:00
expose-rust-type
This commit is contained in:
parent
7d209454b1
commit
fdf83866cb
@ -302,6 +302,8 @@
|
|||||||
- [WebAssembly basics](webassembly.md)
|
- [WebAssembly basics](webassembly.md)
|
||||||
- [Load a WASM module](webassembly/load-wasm-module.md)
|
- [Load a WASM module](webassembly/load-wasm-module.md)
|
||||||
- [Expose a method](webassembly/expose-method.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
|
# Final Words
|
||||||
|
|
||||||
|
@ -5,25 +5,25 @@ use std::path::PathBuf;
|
|||||||
#[get("/")]
|
#[get("/")]
|
||||||
async fn index() -> Result<NamedFile> {
|
async fn index() -> Result<NamedFile> {
|
||||||
let path: PathBuf = "./files/index.html".parse()?;
|
let path: PathBuf = "./files/index.html".parse()?;
|
||||||
Ok(NamedFile::open(path)?)
|
Ok(NamedFile::open(path)?.use_last_modified(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/files/{name}")]
|
#[get("/files/{name}")]
|
||||||
async fn files(web::Path(name): web::Path<String>) -> Result<NamedFile> {
|
async fn files(web::Path(name): web::Path<String>) -> Result<NamedFile> {
|
||||||
let path: PathBuf = format!("./files/{}", name).parse()?;
|
let path: PathBuf = format!("./files/{}", name).parse()?;
|
||||||
Ok(NamedFile::open(path)?)
|
Ok(NamedFile::open(path)?.use_last_modified(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/font.otf")]
|
#[get("/font.otf")]
|
||||||
async fn font() -> Result<NamedFile> {
|
async fn font() -> Result<NamedFile> {
|
||||||
let path: PathBuf = "./files/source-code-regular.otf".parse()?;
|
let path: PathBuf = "./files/source-code-regular.otf".parse()?;
|
||||||
Ok(NamedFile::open(path)?)
|
Ok(NamedFile::open(path)?.use_last_modified(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/wasm/{name}")]
|
#[get("/wasm/{name}")]
|
||||||
async fn serve_wasm(web::Path(name): web::Path<String>) -> Result<NamedFile> {
|
async fn serve_wasm(web::Path(name): web::Path<String>) -> Result<NamedFile> {
|
||||||
let path: PathBuf = format!("./pkg/{}", name).parse()?;
|
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}")]
|
#[get("/wasm/snippets/{snippet_name}/{name}")]
|
||||||
@ -31,7 +31,7 @@ async fn serve_wasm_snippet(
|
|||||||
web::Path((snippet_name, name)): web::Path<(String, String)>,
|
web::Path((snippet_name, name)): web::Path<(String, String)>,
|
||||||
) -> Result<NamedFile> {
|
) -> Result<NamedFile> {
|
||||||
let path: PathBuf = format!("./pkg/snippets/{}/{}", snippet_name, name).parse()?;
|
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]
|
#[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
|
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