diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000000..1caf9d09b51 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,13 @@ +{ + "image": "mcr.microsoft.com/devcontainers/rust:0-1-bullseye", + // Configure tool-specific properties. + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + "settings": {}, + "extensions": [ + "streetsidesoftware.code-spell-checker" + ] + } + } +} diff --git a/Cargo.lock b/Cargo.lock index 8b65dd36403..c901b83df55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "0.7.20" @@ -103,6 +118,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.1" @@ -277,6 +307,16 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -702,6 +742,12 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + [[package]] name = "gitignore" version = "1.0.7" @@ -1050,9 +1096,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "link-cplusplus" @@ -1187,6 +1233,15 @@ dependencies = [ "unicase", ] +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.6" @@ -1286,6 +1341,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.17.1" @@ -1586,6 +1650,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "project" +version = "0.1.0" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "tokio", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "pulldown-cmark" version = "0.9.2" @@ -1771,6 +1847,12 @@ dependencies = [ "winreg", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc_version" version = "0.4.0" @@ -2184,11 +2266,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.1" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -2495,6 +2578,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", + "serde", + "serde_json", "wasm-bindgen-macro", ] diff --git a/Cargo.toml b/Cargo.toml index 7f1b06da21c..57ba757817b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,5 @@ members = [ "src/bare-metal/useful-crates/allocator-example", "src/bare-metal/useful-crates/zerocopy-example", "src/exercises/concurrency/chat-async", + "src/rust-wasm-template", ] diff --git a/src/SUMMARY.md b/src/SUMMARY.md index ddcd83b6151..71b08b6c529 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -1,6 +1,7 @@ # Summary [Welcome to Comprehensive Rust 🦀](welcome.md) + - [Running the Course](running-the-course.md) - [Course Structure](running-the-course/course-structure.md) - [Keyboard Shortcuts](running-the-course/keyboard-shortcuts.md) @@ -10,10 +11,9 @@ - [Code Samples](cargo/code-samples.md) - [Running Cargo Locally](cargo/running-locally.md) - # Day 1: Morning ----- +--- - [Welcome](welcome-day-1.md) - [What is Rust?](welcome-day-1/what-is-rust.md) @@ -67,10 +67,9 @@ - [Storing Books](exercises/day-1/book-library.md) - [Iterators and Ownership](exercises/day-1/iterators-and-ownership.md) - # Day 2: Morning ----- +--- - [Welcome](welcome-day-2.md) - [Structs](structs.md) @@ -120,10 +119,9 @@ - [Luhn Algorithm](exercises/day-2/luhn.md) - [Strings and Iterators](exercises/day-2/strings-iterators.md) - # Day 3: Morning ----- +--- - [Welcome](welcome-day-3.md) - [Generics](generics.md) @@ -177,10 +175,9 @@ - [Exercises](exercises/day-3/afternoon.md) - [Safe FFI Wrapper](exercises/day-3/safe-ffi-wrapper.md) - # Android ----- +--- - [Welcome](android.md) - [Setup](android/setup.md) @@ -203,10 +200,9 @@ - [With Java](android/interoperability/java.md) - [Exercises](exercises/android/morning.md) - # Bare Metal: Morning ----- +--- - [Welcome](bare-metal.md) - [no_std](bare-metal/no_std.md) @@ -253,10 +249,9 @@ - [Exercises](exercises/bare-metal/afternoon.md) - [RTC Driver](exercises/bare-metal/rtc.md) - # Concurrency: Morning ----- +--- - [Welcome](concurrency.md) - [Threads](concurrency/threads.md) @@ -297,19 +292,39 @@ - [Dining Philosophers](exercises/concurrency/dining-philosophers-async.md) - [Broadcast Chat Application](exercises/concurrency/chat-app.md) +# WebAssembly + +--- + +- [WebAssembly basics](webassembly.md) +- [Load a Wasm module](webassembly/load-wasm-module.md) +- [Expose a method](webassembly/expose-method.md) +- [Import Method](webassembly/import-method.md) + - [web-sys](webassembly/import-method/web-sys.md) +- [Expose user-defined Rust types](webassembly/expose-rust-type.md) +- [Import user-defined Javascript types](webassembly/import-js-type.md) +- [Error handling](webassembly/error-handling.md) + - [Error handling for imported methods](webassembly/error-handling/imported-methods.md) + - [Error handling for exported methods](webassembly/error-handling/exported-methods.md) +- [Limitations](webassembly/limitations.md) + - [Borrow Checker](webassembly/limitations/borrow-checker.md) + - [Closures](webassembly/limitations/closures.md) +- [Async](webassembly/async.md) +- [Exercises](exercises/webassembly/webassembly.md) + - [Camera](exercises/webassembly/camera.md) + - [Game Of Life](exercises/webassembly/game-of-life.md) # Final Words ----- +--- - [Thanks!](thanks.md) - [Other Resources](other-resources.md) - [Credits](credits.md) - # Solutions ----- +--- - [Solutions](exercises/solutions.md) - [Day 1 Morning](exercises/day-1/solutions-morning.md) @@ -322,3 +337,6 @@ - [Bare Metal Rust Afternoon](exercises/bare-metal/solutions-afternoon.md) - [Concurrency Morning](exercises/concurrency/solutions-morning.md) - [Concurrency Afternoon](exercises/concurrency/solutions-afternoon.md) + - [Webassembly](exercises/webassembly/webassembly.md) + - [Camera](exercises/webassembly/solutions-camera.md) + - [Game Of Life](exercises/webassembly/solutions-game-of-life.md) \ No newline at end of file diff --git a/src/exercises/webassembly/camera.md b/src/exercises/webassembly/camera.md new file mode 100644 index 00000000000..a926a5d7d0e --- /dev/null +++ b/src/exercises/webassembly/camera.md @@ -0,0 +1,50 @@ +# Camera + +In this exercise we will play with the camera in real time. + +Serve the web server and navigate to [http://localhost:8000/exercises/camera/](http://localhost:8000/exercises/camera/). + +You will edit [lib.rs](../../rust-wasm-template/lib.rs) as usual. + +Here is the basic code you will need: + +```rust +extern crate console_error_panic_hook; + +use js_sys::Uint8ClampedArray; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +extern "C" { + fn alert(s: &str); + + #[wasm_bindgen(js_namespace = console)] + pub fn log(s: &str); +} + +#[wasm_bindgen] +pub fn setup() { + console_error_panic_hook::set_once(); +} + +#[wasm_bindgen] +pub fn edit_bitmap(image_data: &Uint8ClampedArray, width: u32, height: u32) { +} + +``` + +We want to edit the function `edit_bitmap`. `image_data` is a reference to the [Uint8ClampedArray](https://rustwasm.github.io/wasm-bindgen/api/js_sys/struct.Uint8ClampedArray.html) being rendered on your screen. `Uint8ClampedArray` is a flat array of unsigned int of `8` bits. +It represents _srgb_ image, which means that each pixel is represented as a vector of 4 elements [red, green, blue, illumination]. +The image can be thought of as a matrix of dimension `(width, height, 4)`, it is row-major. + +We will reuse our different implementations. So do not erase them when going from one exercise to the next. + +First off let's implement some methods that modify the video live: + +1. Paint the top half the image to black. +2. Paint the left half of the image to white. +3. Create an X-ray effect. This is done by mapping colors to their opposite, for instance `0<->255`, `100<->155`. Beware of illumination. +4. _Bonus question:_ Now feel free to implement other transformations such as _greyscale_ or adding _random noise_. +5. Let's now add functionalities to our page. In the _setup_ function create a dropdown (``) that will change which transformation to apply to the image. +```rust +static METHODS: [&str; 3] = ["xray", "top-black", "left-white"]; + +#[wasm_bindgen] +pub fn setup() -> Result<(), JsValue> { + console_error_panic_hook::set_once(); + let window = web_sys::window().expect("no global `window` exists"); + let document = window.document().expect("should have a document on window"); + let body = document.body().expect("document should have a body"); + + let select = document.create_element("select")?; + for option_value in METHODS { + let option = document.create_element("option")?; + option.set_inner_html(option_value); + option.set_attribute("value", option_value)?; + select.append_child(&option)?; + } + body.append_child(&select)?; + Ok(()) +} + +#[wasm_bindgen] +pub fn edit_bitmap( + image_data: &Uint8ClampedArray, + width: u32, + height: u32, +) -> Result<(), JsValue> { + let window = web_sys::window().expect("no global `window` exists"); + let document = window.document().expect("should have a document on window"); + let select = document + .query_selector("select")? + .expect("No select") + .dyn_into::() + .expect("Failed to cast