Skip to content

Commit 62200ff

Browse files
committed
More concise class
1 parent d7579d7 commit 62200ff

File tree

14 files changed

+148
-219
lines changed

14 files changed

+148
-219
lines changed

Diff for: src/SUMMARY.md

+7-2
Original file line numberDiff line numberDiff line change
@@ -299,18 +299,20 @@
299299
- [WebAssembly basics](webassembly.md)
300300
- [Load a Wasm module](webassembly/load-wasm-module.md)
301301
- [Expose a method](webassembly/expose-method.md)
302-
- [Error handling for exposed methods](webassembly/expose-method/error-handling.md)
303302
- [Import Method](webassembly/import-method.md)
304-
- [Error handling for imported methods](webassembly/import-method/error-handling.md)
305303
- [web-sys](webassembly/import-method/web-sys.md)
306304
- [Expose user-defined Rust types](webassembly/expose-rust-type.md)
307305
- [Import user-defined Javascript types](webassembly/import-js-type.md)
306+
- [Error handling](webassembly/error-handling.md)
307+
- [Error handling for imported methods](webassembly/error-handling/imported-methods.md)
308+
- [Error handling for exported methods](webassembly/error-handling/exported-methods.md)
308309
- [Limitations](webassembly/limitations.md)
309310
- [Borrow Checker](webassembly/limitations/borrow-checker.md)
310311
- [Closures](webassembly/limitations/closures.md)
311312
- [Async](webassembly/async.md)
312313
- [Exercises](exercises/webassembly/webassembly.md)
313314
- [Camera](exercises/webassembly/camera.md)
315+
- [Game Of Life](exercises/webassembly/game-of-life.md)
314316

315317
# Final Words
316318

@@ -335,3 +337,6 @@
335337
- [Bare Metal Rust Afternoon](exercises/bare-metal/solutions-afternoon.md)
336338
- [Concurrency Morning](exercises/concurrency/solutions-morning.md)
337339
- [Concurrency Afternoon](exercises/concurrency/solutions-afternoon.md)
340+
- [Webassembly](exercises/webassembly/webassembly.md)
341+
- [Camera](exercises/webassembly/solutions-camera.md)
342+
- [Game Of Life](exercises/webassembly/solutions-game-of-life.md)

Diff for: src/exercises/webassembly/webassembly.md

+12
Original file line numberDiff line numberDiff line change
@@ -1 +1,13 @@
11
# Exercises
2+
3+
There are two exercises for Webassembly, they both live in their own repository inside of
4+
[rust-wasm-template](../rust-wasm-template).
5+
6+
- [The Camera Exercise](camera.md) will give you access to the camera on your computer and offer you to
7+
apply transformations on the frames it captures.
8+
- [The Game Of Life Exercise](game-of-life.md) will have you implement _John Conway's Game Of Life_ using Webassembly.
9+
10+
You can find the solutions here:
11+
12+
- [Camera](solutions-camera.md)
13+
- [Game Of Life](solutions-game-of-life.md)

Diff for: src/rust-wasm-template/Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ tokio = { version = "1.29.1", features = ["sync"] }
2222
[dependencies.web-sys]
2323
version = "0.3.4"
2424
features = [
25+
'CanvasRenderingContext2d',
2526
'CssStyleDeclaration',
2627
'Document',
2728
'Element',
2829
'ImageData',
29-
'CanvasRenderingContext2d',
3030
'HtmlCanvasElement',
31-
'HtmlSelectElement',
3231
'HtmlElement',
32+
'HtmlSelectElement',
3333
'Node',
34+
'Response',
3435
'Window',
3536
]

Diff for: src/webassembly/async.md

+19-61
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,36 @@
11
# Async
22

3-
Rust methods in WebAssembly can be declared async. Once called, they will be scheduled on the browser's event loop.
4-
An event handler can for instance be implemented with a tokio channel.
5-
6-
Instead of `tokio::spawn`, `wasm_bindgen` provides `wasm_bindgen_futures::spawn_local`.
7-
8-
Let's create a class that waits for messages on a channel to rotate an HTML element:
3+
Rust methods in WebAssembly can be declared async.
94

105
```rust
116
use wasm_bindgen::prelude::*;
12-
use wasm_bindgen_futures::spawn_local;
13-
use tokio::sync::mpsc::{channel, Sender};
14-
15-
#[derive(Debug)]
16-
enum RotateSide {
17-
Left,
18-
Right,
19-
}
20-
21-
#[wasm_bindgen]
22-
pub struct Rotator {
23-
sender: Sender<RotateSide>,
24-
}
7+
use wasm_bindgen_futures::JsFuture;
8+
use web_sys::Response;
259

2610
#[wasm_bindgen]
27-
impl Rotator {
28-
#[wasm_bindgen(constructor)]
29-
pub fn new(element: web_sys::HtmlElement) -> Rotator {
30-
let (sender, mut receiver) = channel::<RotateSide>(1);
31-
spawn_local(async move {
32-
let mut rotation = 0;
33-
while let Some(rotate_side) = receiver.recv().await {
34-
match rotate_side {
35-
RotateSide::Left => rotation -= 45,
36-
RotateSide::Right => rotation += 45,
37-
}
38-
element.set_inner_html(&rotation.to_string());
39-
let style = element.style();
40-
style
41-
.set_property("transform", &format!("rotate({rotation}deg)"))
42-
.expect("Failed to rotate");
43-
}
44-
});
45-
Rotator { sender }
46-
}
47-
48-
#[wasm_bindgen]
49-
pub async fn rotate(&self, msg: String) -> Result<(), JsValue> {
50-
let rotate_side = match msg.as_str() {
51-
"ArrowLeft" => RotateSide::Left,
52-
"ArrowRight" => RotateSide::Right,
53-
_ => return Ok(()),
54-
};
55-
self.sender
56-
.send(rotate_side)
57-
.await
58-
.map_err(|e| JsValue::from_str(&format!("Receiver dropped {:?}", e)))
59-
}
11+
pub async fn get_current_page() -> Result<JsValue, JsValue> {
12+
let window = web_sys::window().unwrap();
13+
let resp_value = JsFuture::from(window.fetch_with_str("")).await?;
14+
let resp: Response = resp_value.dyn_into().unwrap();
15+
let text = JsFuture::from(resp.text()?).await?;
16+
Ok(text)
6017
}
6118
```
6219

63-
Let's call it from Javascript
64-
6520
```javascript
66-
import init, {Rotator} from '/wasm/project.js';
21+
import init, { get_current_page} from '/wasm/project.js';
6722

6823
(async () => {
69-
// Run the init method to initiate the WebAssembly module.
7024
await init();
71-
const wasmoutput = document.querySelector('#wasmoutput');
72-
const rotator = new Rotator(wasmoutput);
73-
document.body.addEventListener('keydown', async (e) => {
74-
await rotator.rotate(e.key);
75-
});
25+
console.log(await get_current_page());
7626
})();
7727

7828
```
29+
30+
<details>
31+
32+
- Async methods are scheduled on the Javascript event loop.
33+
- Instead of `tokio::spawn`, `wasm_bindgen` provides `wasm_bindgen_futures::spawn_local`.
34+
- We use `JsFuture::from` to convert Javascript futures to Rust futures that we can `.await`.
35+
36+
</details>

Diff for: src/webassembly/error-handling.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Error handling
2+
3+
In this chapter we cover error handling both on the Rust side for imported Javascript methods
4+
and on the Javascript side for imported Rust methods.
5+
6+
- [Error handling for imported methods](error-handling/imported-methods.md)
7+
- [Error handling for exported methods](error-handling/exported-methods.md)

Diff for: src/webassembly/expose-method/error-handling.md renamed to src/webassembly/error-handling/exported-methods.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,12 @@ pub fn str_to_int(s: &str) -> Option<i32> {
2424
Javascript, click on the wasm output box to parse the string:
2525

2626
```javascript
27-
import init, {set_panic_hook, str_to_int} from '/wasm/project.js';
27+
import init, {str_to_int} from '/wasm/project.js';
2828

2929

3030
(async () => {
3131
// Run the init method to initiate the WebAssembly module.
3232
await init();
33-
set_panic_hook();
3433
const wasmoutput = document.querySelector('#wasmoutput');
3534
const input = document.createElement('input');
3635
input.type = 'text';
@@ -51,4 +50,4 @@ import init, {set_panic_hook, str_to_int} from '/wasm/project.js';
5150
* Click on the wasm output box to see the output
5251
* `?` and other error handling tools are also supported
5352

54-
</details>
53+
</details>

Diff for: src/webassembly/expose-method.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ pub fn add(a: i32, b: i32) -> i32 {
2424

2525
<details>
2626

27-
* `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
27+
* `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 tends to bloat the bundle size.
2828

29-
</details>
29+
</details>

Diff for: src/webassembly/expose-rust-type.md

+6-25
Original file line numberDiff line numberDiff line change
@@ -2,64 +2,45 @@
22

33
Similarily to methods, types can be exposed from Rust to Javascript with the `#[wasm_bindgen]` macro.
44

5-
Members that implement `Copy` can be public and directly accessed from Javascript.
6-
75
```rust
86
use wasm_bindgen::prelude::*;
9-
107
#[wasm_bindgen]
118
pub struct Counter {
129
name: String,
1310
pub count: u8,
1411
}
15-
```
16-
17-
Methods can also be exported
18-
19-
```rust
2012
#[wasm_bindgen]
2113
impl Counter {
22-
// Constructor will be called in JS when using `new Counter(name, count)`
2314
#[wasm_bindgen(constructor)]
2415
pub fn new(name: String, count: u8) -> Counter {
2516
Counter { name, count }
2617
}
27-
2818
pub fn increment(&mut self) {
2919
self.count += 1;
3020
}
31-
32-
// Getter for the name
3321
#[wasm_bindgen(getter)]
3422
pub fn name(&self) -> String {
3523
self.name.clone()
3624
}
37-
38-
// Setter for the name
3925
#[wasm_bindgen(setter)]
4026
pub fn set_name(&mut self, name: String) {
4127
self.name = name;
4228
}
4329
}
4430
```
4531

46-
Add this button to the HTML file
47-
48-
```html
49-
<button id="button">Increment</button>
50-
```
51-
52-
Javascript to use the `Counter`
32+
Javascript to use the `Counter`.
5333

5434
```javascript
55-
import init, { set_panic_hook, Counter } from "/wasm/project.js";
35+
import init, { Counter } from "/wasm/project.js";
5636

5737
(async () => {
5838
// Run the init method to initiate the WebAssembly module.
5939
await init();
60-
set_panic_hook();
6140
const wasmOutput = document.querySelector("#wasmoutput");
62-
const button = document.querySelector("#button");
41+
const button = document.createElement("button");
42+
button.textContent = "increment";
43+
document.body.appendChild(button);
6344
const counter = new Counter("ButtonCounter", 42);
6445
wasmOutput.textContent = counter.count;
6546
button.addEventListener("click", () => {
@@ -75,5 +56,5 @@ import init, { set_panic_hook, Counter } from "/wasm/project.js";
7556

7657
- `pub` members must implement copy
7758
- Type parameters and lifetime annotations are not supported yet
78-
59+
- Members that implement `Copy` can be public and directly accessed from Javascript.
7960
</details>

0 commit comments

Comments
 (0)