├── .envrc ├── .gitignore ├── .gitlab-ci.yml ├── .projectile ├── .rsync-ignore ├── README.org ├── ci ├── Dockerfile ├── export-course.el ├── run-in-ci.el └── setup.el ├── courses ├── 01-advanced-async │ ├── 000-what-is-async.org │ ├── 010-async-in-core-std.org │ ├── 011-future-anatomy.org │ ├── 012-exercise-basic.org │ ├── 020-signals.org │ ├── 022-excercise-real-wake.org │ ├── 025-runtimes.org │ ├── 030-shutdown-select.org │ ├── 031-wakenotify.org │ ├── 032-actor-programming.org │ ├── 033-channels.org │ ├── 033-pin-project.org │ ├── 040-async-hacking.org │ ├── README.org │ ├── exercises │ │ ├── 01-future-anatomy │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── always.rs │ │ │ │ ├── bin │ │ │ │ ├── 01_never.rs │ │ │ │ ├── 02_twice.rs │ │ │ │ ├── 03_twice.rs │ │ │ │ └── 10_timer.rs │ │ │ │ ├── good_twice.rs │ │ │ │ ├── lib.rs │ │ │ │ ├── never.rs │ │ │ │ └── twice.rs │ │ ├── 02-async-patterns │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── bin │ │ │ │ ├── 01_channels.rs │ │ │ │ ├── 02_backpressure_bounded.rs │ │ │ │ ├── 02_backpressure_unbounded.rs │ │ │ │ ├── 03_cancel_future.rs │ │ │ │ └── 04_select_tokio.rs │ │ ├── 03-runtimes │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── bin │ │ │ │ ├── async-std.rs │ │ │ │ ├── async-task.rs │ │ │ │ └── tokio.rs │ │ │ │ └── lib.rs │ │ ├── 04-wake-notify │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── lib.rs │ │ │ │ └── main.rs │ │ ├── 05-actors │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── bin │ │ │ │ ├── actix.rs │ │ │ │ └── ockam.rs │ │ └── 06-async-chat │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ ├── bin │ │ │ ├── client.rs │ │ │ └── server.rs │ │ │ ├── lib.rs │ │ │ └── message.rs │ └── imgs │ │ ├── actor.svg │ │ ├── actor0.png │ │ ├── actor1.png │ │ ├── actor2.png │ │ ├── actor3.png │ │ ├── async-essay.png │ │ ├── backpressure.svg │ │ ├── bp0.png │ │ ├── bp1.png │ │ ├── bp10.png │ │ ├── bp2.png │ │ ├── bp3.png │ │ ├── bp4.png │ │ ├── bp5.png │ │ ├── bp6.png │ │ ├── bp7.png │ │ ├── bp8.png │ │ ├── bp9.png │ │ ├── calypso.png │ │ ├── concurrency0.png │ │ ├── concurrency1.png │ │ ├── concurrency2.png │ │ ├── external-signal.svg │ │ ├── external-wake.png │ │ ├── gen │ │ ├── future-lifecycle.png │ │ ├── future-lifecycle2.png │ │ └── future-lifecycle3.png │ │ ├── parallelism1.png │ │ ├── pin0.png │ │ ├── pin10.png │ │ ├── pin11.png │ │ ├── pin12.png │ │ ├── rust.gif │ │ ├── rustlatam2019.png │ │ ├── task-notify.png │ │ ├── tokio-notify.png │ │ └── type-separation.png └── 02-ownership │ ├── 10-memory-management.org │ ├── 20-why-ownership.org │ ├── 21-thought-on-raii.org │ ├── 25-ownership-quiz.org │ ├── 30-borrowing.org │ ├── 35-borrowing-exercises.org │ ├── 40-lifetimes.org │ ├── 45-borrowing-exercises.org │ ├── 50-threading.org │ ├── 51-race-conditians.org │ ├── 55-thread-exercises.org │ ├── 60-patterns-arc-mutex.org │ ├── 65-patterns-channels.org │ ├── 70-message-cache.org │ ├── README.org │ ├── exercises │ ├── 00_playground │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── 01_seizing_ownership │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── README.org │ │ └── src │ │ │ ├── bin │ │ │ ├── 01_scopes.rs │ │ │ ├── 02_drop.rs │ │ │ └── 03_move.rs │ │ │ └── lib.rs │ ├── 02_mailbox │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── 03_network_mailbox │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── consumer.rs │ │ │ ├── main.rs │ │ │ └── pool.rs │ └── README.org │ └── imgs │ ├── arc0.png │ ├── arc1.png │ ├── arc2.png │ ├── arc3.png │ ├── arc4.png │ ├── channel0.png │ ├── channel1.png │ ├── channel2.png │ ├── channel3.png │ ├── channel4.png │ ├── cpu.svg │ ├── cpu0.png │ ├── cpu1.png │ ├── cpu2.png │ ├── gc0.png │ ├── gc1.png │ ├── gc2.png │ ├── gc3.png │ ├── gc4.png │ ├── gc5.png │ ├── gc6.png │ ├── gen │ ├── .keep │ ├── borrow1.png │ ├── borrow2.png │ ├── clone-move.png │ ├── mailbox-simple.png │ ├── move-owner.png │ └── raii.png │ ├── ned_flanders.jpg │ ├── numref0.png │ ├── numref1.png │ ├── numref2.png │ ├── numref3.png │ ├── peertube.png │ ├── races │ ├── cpu0.png │ ├── cpu1.png │ ├── cpu2.png │ ├── cpu3.png │ ├── cpu4.png │ ├── race_condition1.png │ ├── race_condition2.png │ ├── race_condition3.png │ └── race_condition4.png │ ├── rust.gif │ ├── uaf0.png │ ├── uaf1.png │ └── uaf2.png ├── html.setup ├── into.org ├── overview.css ├── reveal.setup └── shell.nix /.envrc: -------------------------------------------------------------------------------- 1 | eval "$(lorri direnv)" 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.html 2 | dd-ownership/imgs/gen/* 3 | **/target -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: ubuntu:latest 2 | 3 | before_script: 4 | - apt-get update && apt-get upgrade -y 5 | - apt-get install -y emacs tree 6 | - emacs --batch -l ci/setup.el 7 | 8 | deep-dive-async: 9 | stage: build 10 | script: 11 | - cd dd-async/ 12 | - emacs --batch -l ../ci/export-course.el -------------------------------------------------------------------------------- /.projectile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/.projectile -------------------------------------------------------------------------------- /.rsync-ignore: -------------------------------------------------------------------------------- 1 | **/target -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | #+Title: Rust workshop material 2 | #+Author: Katharina Fey 3 | #+SETUPFILE: html.setup 4 | 5 | Welcome to the Rust teaching material repository. This material was 6 | created by [[file:into.org][Katharina Fey]] with the purpose of having a set of slides, 7 | code examples, example projects, and advanced visualisations to 8 | teach the Rust programming language to developers of varying 9 | backgrounds. 10 | 11 | Is your company looking for teaching? [[mailto:kookie@spacekookie.de][Contact me]] for details and 12 | booking! 13 | 14 | * Outline 15 | 16 | This repository is structured as a set of course trees. Each tree 17 | focuses primarily on conveying a single aspect of the Rust 18 | programming langueg. Following is an overview of available 19 | courses. 20 | 21 | - [[./dd-ownership][deep-dive-ownership]] :: An intensive deep-dive course into the 22 | Rust ownership model and it's impact on concurrent programming 23 | - [[./dd-async/README.org][deep-dive-async]] :: A deep-dive course into async development, 24 | async compiler internals, and runtime development in Rust 25 | 26 | * Hosted slides 27 | 28 | https://learn.spacekookie.de/rust/ 29 | 30 | * Build these slides 31 | 32 | It's generally recommended to use the hosted version for these 33 | slides, but if you must build them yourself, you need to have Emacs 34 | (v26+) and org-mode installed! 35 | 36 | The following function will export the full course into an HTML 37 | slide tree. 38 | 39 | #+INCLUDE: "ci/export-course.el" src emacs-lisp 40 | 41 | * Sponsors 42 | 43 | This course has been sponsored by various companies that have paid 44 | for trainings and the creation of new material in the past. 45 | 46 | -------------------------------------------------------------------------------- /ci/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | RUN apt-get update && apt-get upgrade -y 4 | RUN apt-get install -y emacs curl 5 | 6 | RUN mkdir /ci 7 | COPY setup.el /ci/ 8 | COPY export-course.el /ci/ 9 | 10 | RUN yes | emacs --batch -l /ci/setup.el 11 | -------------------------------------------------------------------------------- /ci/export-course.el: -------------------------------------------------------------------------------- 1 | ;; TODO: swap the theme to be more easily readable on white background 2 | (defun export-course () 3 | "Export a course tree as a set of HTML files" 4 | (interactive) 5 | 6 | ;; Manually require ox-reveal 7 | (require 'ox-reveal) 8 | 9 | ;; Make sure org-reveal is loaded and set-up 10 | (load-library "reveal") 11 | (setq org-reveal-root "../../.templates") 12 | 13 | ;; Export the README 14 | (find-file "README.org") 15 | (org-html-export-to-html) 16 | 17 | ;; Then export the rest of the slides 18 | (mapcar 19 | (lambda (file) 20 | (find-file file) 21 | (org-reveal-export-to-html)) 22 | (delete "README.org" (directory-files "." nil "\.org$" t)))) 23 | (provide 'export-course) 24 | -------------------------------------------------------------------------------- /ci/run-in-ci.el: -------------------------------------------------------------------------------- 1 | ;;; A simple CI hook to run the slide builder function with all 2 | ;;; required packages loaded 3 | 4 | (add-to-list 'load-path "/usr/share/emacs/26.3/lisp/") 5 | (print load-path) 6 | 7 | (require 'ox-reveal) 8 | (require 'htmlize) 9 | (require 'export-course) 10 | 11 | (export-course) 12 | -------------------------------------------------------------------------------- /ci/setup.el: -------------------------------------------------------------------------------- 1 | ;; Evaluate this file to set-up emacs in CI for building slides 2 | 3 | (require 'package) 4 | (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/")) 5 | 6 | (package-initialize) 7 | (package-refresh-contents) 8 | 9 | (setq package-selected-packages 10 | '(org-mode 11 | ox-reveal 12 | htmlize)) 13 | 14 | (package-install-selected-packages) 15 | (save-buffers-kill-emacs) 16 | 17 | -------------------------------------------------------------------------------- /courses/01-advanced-async/000-what-is-async.org: -------------------------------------------------------------------------------- 1 | #+Title: What is async? 2 | #+Subtitle: We just don't know yet 3 | #+SETUPFILE: ../../reveal.setup 4 | 5 | * 6 | 7 | I made a video essay about all this a while ago 8 | 9 | #+attr_html: :width 400px 10 | file:imgs/async-essay.png 11 | 12 | https://diode.zone/w/koSvUCmBL11VA2PTVZuRG9 13 | 14 | * 15 | 16 | A synchronous webserver which handles two incoming connections 17 | 18 | file:imgs/concurrency0.png 19 | 20 | * 21 | 22 | A lot of that time might be spent waiting 23 | 24 | file:imgs/concurrency2.png 25 | 26 | * 27 | 28 | So instead, break out "work units" and handle them at the same time 29 | 30 | file:imgs/concurrency1.png 31 | 32 | * Concurrency vs Parallelism 33 | 34 | file:imgs/parallelism1.png 35 | 36 | * Async theory 37 | 38 | + Use system resources more effectively 39 | + Execute code while waiting for outside events 40 | + Developed under many different names 41 | + Coroutines 42 | + Cooperative multitasking 43 | + Non-blocking I/O 44 | 45 | * Async state machines 46 | 47 | + Think of your program like a state machine 48 | + Sometimes states take a while to change 49 | + React to changes when they happen 50 | + Yield to runtime when there's nothing to do 51 | 52 | * Futures 53 | 54 | + Represents a computation that _may_ return a result in the future 55 | + Needs to be polled (in some way or another) to make progress 56 | + A future might not run at all either 57 | + Yields when no progress can be made 58 | 59 | * Executors 60 | 61 | + Acts as a scheduler for async code 62 | + Use cooperative multitasking between futures 63 | + "Wake up" future when new work can be done 64 | 65 | * How do we know when to wake? 66 | 67 | * [[file:README.org][Back to index]] 68 | -------------------------------------------------------------------------------- /courses/01-advanced-async/010-async-in-core-std.org: -------------------------------------------------------------------------------- 1 | #+Title: Async in Rust 2 | #+SETUPFILE: ../../reveal.setup 3 | 4 | * Async foundations in ~core~ 5 | 6 | + Rust's ~libcore~ gained async capabilities in 1.39 7 | + Provides mechanisms to handle futures 8 | + No actual runtime! 9 | 10 | * Lazy futures 11 | 12 | + In Rust all ~Future~ types are lazy 13 | + That means they don't "make progress" unless polled 14 | + This is different in other runtime systems 15 | 16 | * Creating a future alone does nothing! 17 | 18 | \\ 19 | 20 | #+BEGIN_SRC rust 21 | let fut = MyFuture::new(data, config); // impl Future for MyFuture { ... } 22 | 23 | /// Either of these only work in an async function! 24 | // fut.await; 25 | // futures::poll!(fut); 26 | #+END_SRC 27 | 28 | * Future lifecycle 29 | 30 | #+BEGIN_SRC dot :file imgs/gen/future-lifecycle.png :cmdline -Kdot -Tpng 31 | digraph { 32 | node [shape=box, fontsize=24, margin="0.25,0.25"] 33 | rankdir = "LR"; 34 | 35 | new [color=darkgreen, shape=box] 36 | poll [color=teal, shape=box] 37 | yield [color=orange, shape=box] 38 | wake [color=teal, shape=box] 39 | huh [label="?", color=darkgreen] 40 | resolve [color=green, shape=box] 41 | new -> poll -> yield; 42 | wake -> poll; 43 | huh -> wake [style="dashed"]; 44 | poll -> resolve; 45 | } 46 | #+END_SRC 47 | 48 | * The important types at a glance 49 | 50 | These can be found in ~core::future~ and ~core::task~ 51 | 52 | + ~Future~ :: Primary future abstraction trait 53 | + ~Poll~ :: Enum to indicate runtime completion of a future 54 | + ~Waker~ :: A mechanism to wake up a future after it has yielded 55 | 56 | * Future vs Task 57 | 58 | Think of a Future as a single step in a chain of async operations. 59 | 60 | A task is the chain. 61 | 62 | * No runtime in ~std~! 63 | 64 | + Rust doesn't include a runtime in its std library (for good reason!) 65 | + All the programming excercises are solvable with ~smol-rs~, a very 66 | smol async runtime 67 | 68 | * What is a Runtime? 69 | 70 | * 71 | 72 | + Process data, handle I/O 73 | + Schedule available work in an effective way 74 | + Interleave work as it becomes available 75 | + De-allocate futures that are no longer needed 76 | 77 | * Stopping ongoing work 78 | 79 | \\ 80 | 81 | + Because futures are lazy they can be cancelled (most of the time) 82 | + This might result in partial state (← how do you handle this?) 83 | 84 | * The real lifecycle 85 | 86 | \\ 87 | 88 | Any future can be cancelled at any point! 89 | 90 | #+BEGIN_SRC dot :file imgs/gen/future-lifecycle2.png :cmdline -Kdot -Tpng 91 | digraph { 92 | node [shape=box, fontsize=24, margin="0.25,0.25"] 93 | rankdir = "LR"; 94 | 95 | new [color=darkgreen, shape=box] 96 | poll [color=teal, shape=box] 97 | cancel [color=red, shape=box] 98 | yield [color=orange, shape=box] 99 | wake [color=teal, shape=box] 100 | huh [label="?", color=darkgreen] 101 | resolve [color=green, shape=box] 102 | new -> poll -> yield; 103 | wake -> poll; 104 | huh -> wake [style=dashed]; 105 | poll -> resolve; 106 | poll -> cancel [style=dashed] 107 | } 108 | #+END_SRC 109 | 110 | * Your async application is a Runtime! 111 | 112 | * Yeah okay but like... really? 113 | 114 | ** ~tokio~ 115 | 116 | + Probably needs to introduction 117 | + Started in 2016 by Carl Lerche 118 | 119 | #+BEGIN_SRC toml 120 | [dependencies] 121 | tokio = { version = "1.0", features = ["full"] } 122 | #+END_SRC 123 | 124 | #+BEGIN_SRC rust 125 | #[tokio::main] 126 | async fn main() { 127 | // your async code here 128 | } 129 | #+END_SRC 130 | 131 | ** ~async-std~ 132 | 133 | + Started in 2019 by Stjepan Glavina 134 | + Maintained by the "Async Rust WG" 135 | 136 | #+BEGIN_SRC toml 137 | [dependencies] 138 | async-std = { version = "1.0", features = ["attribute"] } 139 | #+END_SRC 140 | 141 | #+BEGIN_SRC rust 142 | #[async_std::main] 143 | async fn main() { 144 | // your async code here 145 | } 146 | #+END_SRC 147 | 148 | ** ~smol-rs~ 149 | 150 | + The actual event reactor behind ~async-std~! 151 | + A bit more clumbsy to use, but just as powerful 152 | + This makes it more embeddable 153 | 154 | #+BEGIN_SRC rust 155 | fn main() { 156 | smol::block_on(async { 157 | // your async code here 158 | }); 159 | } 160 | #+END_SRC 161 | 162 | ** Different runtimes focus on different UX strategies 163 | 164 | * [[file:README.org][Back to index]] 165 | -------------------------------------------------------------------------------- /courses/01-advanced-async/011-future-anatomy.org: -------------------------------------------------------------------------------- 1 | #+Title: Anatomy of a future 2 | #+SETUPFILE: ../../reveal.setup 3 | 4 | * Lifecycle 5 | 6 | file:imgs/gen/future-lifecycle2.png 7 | 8 | * Future trait 9 | 10 | + ~Output~ type is whatever the future produces 11 | + ~Pin~ is a memory safety type 12 | + ~Context~ is a generic way for the runtime to provide ... context :) 13 | 14 | #+BEGIN_SRC rust 15 | pub trait Future { 16 | type Output; 17 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; 18 | } 19 | #+END_SRC 20 | 21 | * Writing a simple future 22 | 23 | A simple future which will never complete 24 | 25 | #+INCLUDE: "exercises/01-future-anatomy/src/never.rs" src rust 26 | 27 | * Writing a simple future 28 | 29 | A simple future which will immediately complete 30 | 31 | #+INCLUDE: "exercises/01-future-anatomy/src/always.rs" src rust 32 | 33 | * Await progress 34 | 35 | + In this example we're using ~async-std~ 36 | + You can run this example via /~cargo run --bin 01_never~/ 37 | 38 | #+INCLUDE: "exercises/01-future-anatomy/src/bin/01_never.rs" src rust 39 | 40 | * So what's up with ~Pin~? 41 | 42 | ** Pin (at a high level) 43 | 44 | + Pin is a way to instruct the Rust compiler to not allow moving of objects 45 | + Futures (internally) require self-referential structs 46 | + Self-referential structs are a bit problematic 47 | + ~Pin~ removes the ability for a type to be moved so that self-references remain valid 48 | 49 | ** 50 | 51 | #+BEGIN_SRC rust 52 | let sql: String = format!("SELECT FROM users WHERE usersname = {}", user); 53 | let db_resp = self.query(&sql).await; 54 | #+END_SRC 55 | 56 | file:imgs/pin10.png 57 | 58 | ** 59 | 60 | #+BEGIN_SRC rust 61 | let sql: String = format!("SELECT FROM users WHERE usersname = {}", user); 62 | let db_resp = self.query(&sql).await; // <-- creates a 'DbFuture' behind the scenes 63 | #+END_SRC 64 | 65 | file:imgs/pin11.png 66 | 67 | ** 68 | 69 | #+BEGIN_SRC rust 70 | let sql: String = format!("SELECT FROM users WHERE usersname = {}", user); 71 | let db_resp = self.query(&sql).await; 72 | #+END_SRC 73 | 74 | file:imgs/pin12.png 75 | 76 | ** Where does my future live? 77 | 78 | \\ 79 | 80 | + Before being polled a future must be pinned to a particular place in memory 81 | + Try to be aware of where this is 82 | + Pin will create errors when trying to move the future 83 | 84 | ** Want to learn more? 85 | 86 | file:imgs/rustlatam2019.png 87 | 88 | https://www.youtube.com/watch?v=skos4B5x7qE 89 | 90 | * A more useful future 91 | 92 | + Set internal boolean to ~true~ on first poll 93 | + Return ~Poll::Ready(())~ on second poll 94 | 95 | #+INCLUDE: "exercises/01-future-anatomy/src/twice.rs" src rust 96 | 97 | * Not so useful... 98 | 99 | + The future only gets polled once! 100 | 101 | #+BEGIN_SRC console 102 | ❤ (tempest) ~/P/t/t/d/e/01-future-anatomy> cargo run --bin 02_twice 103 | Compiling 01-future-anatomy v0.1.0 (/home/Projects/talks/teaching-rust/dd-async/exercises/01-future-anatomy) 104 | Finished dev [unoptimized + debuginfo] target(s) in 0.69s 105 | Running `target/debug/02_twice` 106 | [src/twice.rs:17] Poll::Pending = Pending 107 | #+END_SRC 108 | 109 | * 110 | 111 | #+BEGIN_SRC dot :file imgs/gen/future-lifecycle3.png :cmdline -Kdot -Tpng 112 | digraph { 113 | node [shape=box, fontsize=24, margin="0.25,0.25"] 114 | rankdir = "LR"; 115 | 116 | new [color=darkgreen, shape=box] 117 | poll [color=teal, shape=box] 118 | yield [color=orange, shape=box] 119 | wake [color=teal, shape=box] 120 | huh [label="?", color=darkgreen, penwidth=5] 121 | resolve [color=green, shape=box] 122 | new -> poll -> yield; 123 | wake -> poll; 124 | huh -> wake [style="dashed"]; 125 | poll -> resolve; 126 | } 127 | #+END_SRC 128 | 129 | 130 | * We need to wake our future again 131 | 132 | #+INCLUDE: "exercises/01-future-anatomy/src/good_twice.rs" src rust 133 | 134 | * 135 | 136 | #+BEGIN_SRC dot :file imgs/gen/future-lifecycle3.png :cmdline -Kdot -Tpng 137 | digraph { 138 | node [shape=box, fontsize=24, margin="0.25,0.25"] 139 | rankdir = "LR"; 140 | 141 | new [color=darkgreen, shape=box] 142 | poll [color=teal, shape=box] 143 | yield [color=orange, shape=box] 144 | wake [color=teal, shape=box] 145 | resolve [color=green, shape=box] 146 | new -> poll -> yield 147 | poll -> resolve 148 | wake -> poll [dir="both", style="dashed", label="wake_by_ref()"] 149 | } 150 | #+END_SRC 151 | 152 | #+RESULTS: 153 | [[file:imgs/gen/future-lifecycle3.png]] 154 | 155 | * 156 | 157 | #+BEGIN_SRC console 158 | ❤ (tempest) ~/P/t/t/d/e/01-future-anatomy> cargo run --bin 03_twice 159 | Finished dev [unoptimized + debuginfo] target(s) in 0.03s 160 | Running `target/debug/03_twice` 161 | Future says: () 162 | #+END_SRC 163 | 164 | * In summary... 165 | 166 | * Desugaring 167 | 168 | Async/ Await are relatively modern and hide what Futures look like under the hood 169 | 170 | #+BEGIN_SRC rust 171 | use async_std::{fs::File, io::Read}; 172 | 173 | async fn read_file(path: &str) -> std::io::Result { 174 | 175 | let mut f = File::open(path).await?; 176 | let mut buf = String::new(); 177 | f.read_to_string(&mut buf).await?; 178 | Ok(buf) 179 | 180 | } 181 | #+END_SRC 182 | 183 | * Desugaring 184 | 185 | Async/ Await are relatively modern and hide what Futures look like under the hood 186 | 187 | #+BEGIN_SRC rust 188 | use async_std::{fs::File, io::Read}; 189 | 190 | fn read_file(path: &str) -> impl Future> { 191 | async { 192 | let mut f = File::open(path).await?; 193 | let mut buf = String::new(); 194 | f.read_to_string(&mut buf).await?; 195 | Ok(buf) 196 | } 197 | } 198 | #+END_SRC 199 | 200 | * ~Await~ the end of all things 201 | 202 | + Tell the executor to keep schedule a future 203 | + Just once though 204 | + Afterwards it needs to be woken up 205 | + ~.await~ gets desugared by the compiler 206 | 207 | * [[file:README.org][Back to index]] 208 | -------------------------------------------------------------------------------- /courses/01-advanced-async/012-exercise-basic.org: -------------------------------------------------------------------------------- 1 | #+Title: Async Wrapper 2 | #+SETUPFILE: ../../reveal.setup 3 | 4 | * Hyperpipe 5 | 6 | + https://github.com/spacekookie/hyperpipe 7 | + A toy library for communicating between different processes 8 | + Doesn't use async I/O 9 | + Implement an async wrapper! 10 | 11 | * How to use 12 | 13 | \\ 14 | 15 | + Construct two pipe endpoints (in some directory) 16 | + Push data in, pull data out 17 | + Pull _does not block_ to wait for data 18 | 19 | #+BEGIN_SRC rust 20 | fn main() { 21 | let pipe_path = Path::new("buffer-dir"); 22 | 23 | let mut p1 = HyperPipe::new(pipe_path).unwrap(); 24 | let v1 = vec![1, 2, 3, 4, 5, 6]; 25 | p1.push(v1.clone()).unwrap(); 26 | 27 | let mut p2 = HyperPipe::new(pipe_path).unwrap(); 28 | let v2 = p2.pull().unwrap(); 29 | assert_eq!(v1, v2); 30 | } 31 | #+END_SRC 32 | 33 | * AsyncHyperPipe 34 | 35 | \\ 36 | 37 | + Construct a HyperPipe 38 | + Create a polling future 39 | + Remember to wake yourself 40 | 41 | #+BEGIN_SRC rust 42 | pub struct AsyncHyperPipe { 43 | inner: HyperPipe 44 | } 45 | 46 | impl Future for AsyncHyperPipe { 47 | type Output = Vec; 48 | fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll { 49 | todo!() 50 | } 51 | } 52 | #+END_SRC 53 | 54 | * 55 | 56 | #+BEGIN_SRC rust 57 | let pipe = AsyncHypePipe::new(); 58 | 59 | println("hmmm,,, data: {:?}", pipe.await); 60 | #+END_SRC 61 | 62 | * [[file:README.org][Back to index]] 63 | 64 | -------------------------------------------------------------------------------- /courses/01-advanced-async/020-signals.org: -------------------------------------------------------------------------------- 1 | #+Title: What are Signals? 2 | #+SETUPFILE: ../../reveal.setup 3 | 4 | * Reaction to outside forces 5 | 6 | * How to listen for events? 7 | 8 | * Calls from inside the house 9 | 10 | \\ 11 | 12 | + Some other part of the async runtime wakes us 13 | + For example: channels! 14 | 15 | #+BEGIN_SRC rust 16 | let (tx, rx) = async_channel::bounded(2); 17 | 18 | smol::spawn(async move { 19 | let d = rx.recv().await; 20 | println!("Data: {}", d); 21 | }); 22 | 23 | async_io::Timer::after(Duration::from_secs(1)).await; 24 | tx.send("Hello World!".to_owned()).await; 25 | #+END_SRC 26 | 27 | * Calls from outside the house 28 | 29 | \\ 30 | 31 | + The Kernel would like your attention 32 | + Any external resource (library, filesystem, socket, ...) 33 | + Use blocking threads to wait for signals! 34 | 35 | * Blocking threads 36 | 37 | \\ 38 | 39 | + Not to be confused with ~tokio::task::spawn_blocking~ ! 40 | + Spawn a thread and handle external I/O 41 | + Provide a ~Waker~ to any relevant tasks 42 | + Map blocking I/O to async wake signal 43 | 44 | * 45 | 46 | file:imgs/external-wake.png 47 | 48 | * [[file:README.org][Back to index]] 49 | 50 | -------------------------------------------------------------------------------- /courses/01-advanced-async/022-excercise-real-wake.org: -------------------------------------------------------------------------------- 1 | #+Title: A better async Wrapper 2 | #+SETUPFILE: ../../reveal.setup 3 | 4 | * What signals? 5 | 6 | + If you're on Linux :: ~inotify-rs~ 7 | 8 | #+BEGIN_SRC rust 9 | let mut notify = Inotify::init().expect("failed to initialise Inotify structure"); 10 | notify 11 | .add_watch(&path, WatchMask::MOVE) 12 | .expect(&format!("failed to watch directory {:?}", path)); 13 | #+END_SRC 14 | 15 | + If you're on macOS/ BSD :: ~kqueue~ 16 | 17 | #+BEGIN_SRC rust 18 | let mut watcher = kqueue::Watcher::new()?; 19 | watcher.add_filename(path, kqueue::EventFilter::EVFILT_VNODE, kqueue::FilterFlag::NOTE_DELETE)?; 20 | #+END_SRC 21 | 22 | * Alternatively 23 | 24 | + ~async-io~ provides a ~Timer~ type 25 | + Instead of busy-waking (waking a future after every poll), use a 26 | fixed Timer to reduce system load. 27 | 28 | #+BEGIN_SRC rust 29 | use async_io::Timer; 30 | use std::time::Duration; 31 | 32 | Timer::after(Duration::from_secs(1)).await; 33 | #+END_SRC 34 | 35 | * [[file:README.org][Back to index]] 36 | -------------------------------------------------------------------------------- /courses/01-advanced-async/025-runtimes.org: -------------------------------------------------------------------------------- 1 | #+Title: Runtimes 2 | #+SETUPFILE: ../../reveal.setup 3 | 4 | * Overview 5 | 6 | \\ 7 | 8 | + tokio :: A very "batteries included" runtime and async library 9 | + async-executor :: The runtime behind ~async-std~ and ~smol~ 10 | + embassy :: Rust Embedded async executor and HALs 11 | + fuchsia-async :: Google's Fuchsia OS executor 12 | 13 | * The smallest runtime: ~async-task~ & ~futures-lite~ 14 | 15 | #+INCLUDE: "exercises/03-runtimes/src/bin/async-task.rs" src rust 16 | 17 | * ~block_on~ 18 | 19 | ** Basic setup 20 | 21 | #+BEGIN_SRC rust 22 | use parking::Parker; 23 | use waker_fn::waker_fn; 24 | 25 | pub fn block_on(future: impl Future) -> T { 26 | crate::pin!(future); 27 | 28 | thread_local! { 29 | // Cached parker and waker for efficiency. 30 | static CACHE: RefCell<(Parker, Waker)> = RefCell::new(parker_and_waker()); 31 | } 32 | 33 | // ... 34 | } 35 | #+END_SRC 36 | 37 | ** No ~block_on~ nesting... 38 | 39 | #+BEGIN_SRC rust 40 | match cache.try_borrow_mut() { 41 | // Use the cached parker and waker. 42 | Ok(cache) => { 43 | let (parker, waker) = &*cache; 44 | let cx = &mut Context::from_waker(&waker); 45 | 46 | loop { 47 | match future.as_mut().poll(cx) { 48 | Poll::Ready(output) => return output, 49 | Poll::Pending => parker.park(), 50 | } 51 | } 52 | } 53 | _ => todo!() 54 | } 55 | #+END_SRC 56 | 57 | ** Yes ~block_on~ nesting 58 | 59 | #+BEGIN_SRC rust 60 | match cache.try_borrow_mut() { 61 | // Looks like this is a recursive `block_on()` call. 62 | Err(_) => { 63 | let (parker, waker) = parker_and_waker(); 64 | let cx = &mut Context::from_waker(&waker); 65 | 66 | loop { 67 | match future.as_mut().poll(cx) { 68 | Poll::Ready(output) => return output, 69 | Poll::Pending => parker.park(), 70 | } 71 | } 72 | } 73 | _ => todo!() 74 | } 75 | #+END_SRC 76 | 77 | 78 | ** Oh and a smol other thing 79 | 80 | + ~Parker~ comes from the ~parking~ crate 81 | + ~Waker~ is part of ~core::task~ 82 | + ~waker_fn~ is a convenience builder crate for ~Waker~ 83 | 84 | #+BEGIN_SRC rust 85 | fn parker_and_waker() -> (Parker, Waker) { 86 | let parker = Parker::new(); 87 | let unparker = parker.unparker(); 88 | let waker = waker_fn(move || { 89 | unparker.unpark(); 90 | }); 91 | (parker, waker) 92 | } 93 | #+END_SRC 94 | 95 | ** We just made a runtime! 96 | 97 | Isn't this cool?? 98 | 99 | #+BEGIN_SRC rust 100 | fn main() { 101 | // allow us to attach futures to our state machine after it 102 | // started running 103 | let t = spawn(async { 104 | println!("Hello task!"); 105 | }); 106 | 107 | // blocks the current thread until all futures are done 108 | block_on(t); 109 | } 110 | 111 | #+END_SRC 112 | 113 | * Anyway 114 | 115 | * ~async-std~ 116 | 117 | We can easily create tasks without the syntactic sugar 118 | 119 | #+INCLUDE: "exercises/03-runtimes/src/bin/async-std.rs" src rust 120 | 121 | * ~tokio~ 122 | 123 | We can easily create tasks without the syntactic sugar 124 | 125 | #+INCLUDE: "exercises/03-runtimes/src/bin/tokio.rs" src rust 126 | 127 | * [[file:README.org][Back to index]] 128 | -------------------------------------------------------------------------------- /courses/01-advanced-async/030-shutdown-select.org: -------------------------------------------------------------------------------- 1 | #+Title: Shutting down async systems 2 | #+SETUPFILE: ../../reveal.setup 3 | 4 | * Q: How do you stop disconnected, infinite futures? 5 | 6 | * A: Run state! 7 | 8 | \\ 9 | 10 | #+BEGIN_SRC rust 11 | let run_state = Arc::new(AtomicBool::new(true)); 12 | 13 | let run2 = Arc::clone(&run_state); 14 | smol::spawn(async move { 15 | while run2.load(Ordering::Relaxed) { 16 | // Do things here... 17 | } 18 | }); 19 | 20 | // Somewhere else in your program 21 | run_state.fetch_and(false, Ordering::Relaxed); 22 | #+END_SRC 23 | 24 | * What problems might there be? 25 | 26 | * 27 | 28 | #+BEGIN_SRC rust 29 | while run2.fetch(Ordering::Relaxed) { 30 | // Do things here... 31 | } 32 | #+END_SRC 33 | 34 | + Only check run-state once per loop 35 | + Once the loop has started it can't be stopped again! 36 | + Is this a good or a bad thing? YOU DECIDE! 37 | 38 | * Another scenario 39 | 40 | \\ 41 | 42 | All tasks are connected to each other via channels. A task shuts down 43 | when its channel sender stops existing. 44 | 45 | + A produces data for B and C 46 | + B produces data for D and E 47 | + C produces data for F and G 48 | 49 | * Shutdown will be staggered! 50 | 51 | F will still be running while B and C are already shut down. 52 | 53 | * Basic structure 54 | 55 | + First we start by defining the internal structure of our Future. 56 | + We need it to be ~Clone~ so we wrap ~AtomicBool~ into an ~Arc~. 57 | + The ~Waker~ type is ~Clone~ by default. 58 | 59 | #+BEGIN_SRC rust 60 | use std::sync::{Arc, atomic::AtomicBool}; 61 | use std::task::Waker; 62 | 63 | #[derive(Clone, Default)] 64 | struct ShutdownFuture(Arc, Option); 65 | #+END_SRC 66 | 67 | * 68 | 69 | + Next up we implement the ~Future~ trait 70 | + When we are polled, we check the boolean for its state 71 | + Either return ~Poll::Pending~ or ~Poll::Ready~ 72 | + This determines the shutdown state of our state machine! 73 | + We also store a ~Waker~ for future updates 74 | 75 | #+BEGIN_SRC rust 76 | use std::{future::Future, pin::Pin, task::Context}; 77 | use std::sync::atomic::Ordering; 78 | 79 | impl Future for ShutdownFuture { 80 | type Output = (); // Output type does not matter 81 | 82 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { 83 | if self.0.load(Ordering::Relaxed) { 84 | Poll::Ready(()) // System should shut down 85 | } else { 86 | self.1 = Some(cx.waker().clone()); 87 | Poll::Pending // System should keep running 88 | } 89 | } 90 | } 91 | #+END_SRC 92 | 93 | * What does this do so far? 94 | 95 | + Polling this future will never return ~Poll::Ready(())~ 96 | + This future will only be polled _once_ 97 | + But we stored a ~Waker~! That is important 98 | 99 | #+BEGIN_SRC rust 100 | impl ShutdownFuture { 101 | pub fn stop(&self) { 102 | self.0.fetch_or(true, Ordering::Relaxed); 103 | if let Some(w) = self.1.as_ref() { 104 | w.wake_by_ref(); 105 | } 106 | } 107 | } 108 | #+END_SRC 109 | 110 | *What does this code do?* 111 | 112 | * Selecting the right future 113 | 114 | + Putting all this together we need another mechanism: select! 115 | + In ~tokio~ this is ~tokio::future::select~ 116 | + For ~async_std~ you need to use ~futures~ crate 117 | 118 | #+BEGIN_SRC rust 119 | async fn next_event(&self, shutdown: &ShutdownFuture) -> bool { 120 | let mut next_event = self.event_rx.recv(); 121 | let mut shutdown = shutdown.clone(); 122 | 123 | tokio::select! { 124 | _ = shutdown => { 125 | println!("Received shutdown signal!"); 126 | false 127 | }, 128 | event = next_event => { 129 | handle_event(event).await; 130 | true 131 | } 132 | } 133 | } 134 | #+END_SRC 135 | 136 | * Putting it all together 137 | 138 | + The last thing missing is creating a task :) 139 | + Let's use a channel to send some data to a task, then shut it down 140 | via our shutdown signal 141 | 142 | #+BEGIN_SRC rust 143 | use crate::{event::MyEvent, task::TaskHandle}; // Some other fake code 144 | use tokio::sync::mpsc::bounded; 145 | 146 | #[tokio::main] 147 | async fn main() -> Result<(), Box> { 148 | let (tx, rx) = bounded(32); 149 | let shutdown = ShutdownFuture::default(); 150 | let task_handle = TaskHandle { shutdown: shutdown.clone(), tx: tx.clone(), rx }; 151 | 152 | // Run this loop until next_event returns 'false' 153 | tokio::spawn(async move { while task_handle.next_event().await {} }); 154 | 155 | tx.send(MyEvent::Nop).await?; 156 | shutdown.stop(); 157 | } 158 | #+END_SRC 159 | 160 | * [[file:README.org][Back to index]] 161 | -------------------------------------------------------------------------------- /courses/01-advanced-async/031-wakenotify.org: -------------------------------------------------------------------------------- 1 | #+Title: What if we don't use channels? 2 | #+SETUPFILE: ../../reveal.setup 3 | 4 | * 5 | 6 | You may have noticed a problem when wrapping datastructures in 7 | asynchronous locking mechanisms 8 | 9 | * 10 | 11 | Insert items into collection on task 1 and busy-loop on task 2 12 | 13 | #+BEGIN_SRC rust 14 | // task 1 15 | collection.lock().await.push_back(42); 16 | 17 | // task2 18 | let num = loop { 19 | if let Some(num) = collection.lock().await.pop_front() { 20 | num 21 | } else { 22 | smol::future::yield_now().await; 23 | } 24 | }; 25 | #+END_SRC 26 | 27 | * ~yield_now~ 28 | 29 | \\ 30 | 31 | #+BEGIN_SRC rust 32 | pub struct YieldNow(bool); 33 | 34 | impl Future for YieldNow { 35 | type Output = (); 36 | 37 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 38 | if !self.0 { 39 | self.0 = true; 40 | cx.waker().wake_by_ref(); 41 | Poll::Pending 42 | } else { 43 | Poll::Ready(()) 44 | } 45 | } 46 | } 47 | #+END_SRC 48 | 49 | * Hot take 🔥 busy loops are bad 50 | 51 | * Solution? WakeNotify pattern 52 | 53 | + Wrap any collection in ~Notify~ 54 | + Poll once, then store a waker 55 | + When inserting, call ~wake()~ 56 | 57 | #+BEGIN_SRC rust 58 | use core::task::Waker; 59 | pub struct Notify { 60 | inner: T, 61 | waker: Option 62 | } 63 | #+END_SRC 64 | 65 | * WakeNotify pattern 66 | 67 | #+BEGIN_SRC rust 68 | // A nice and short type signature :) 69 | let collection = Arc::new(Mutex::new(Notify::new(VecDeque::new()))); 70 | 71 | // task 1 72 | let mut mg = c.lock().await; 73 | mg.push_back(42); 74 | Notify::wake(&*mg); 75 | // mg goes out of scope to de-lock the Mutex 76 | #+END_SRC 77 | 78 | * The poll task 79 | 80 | #+BEGIN_SRC rust 81 | futures::future::poll_fn(|ctx| { 82 | let mut lock = Box::pin(t.lock()); // We box this future to easily be able to pin it 83 | match Pin::new(&mut lock).poll(ctx) { // Then poll it for progress 84 | Poll::Ready(ref mut mg) => match mg.pop_front() { 85 | Some(v) => Poll::Ready(v), // Return data if there was any 86 | None => { // Otherwise install a Waker 87 | Notify::add_waker(mg, ctx.waker().clone()); 88 | Poll::Pending 89 | } 90 | }, 91 | _ => Poll::Pending, // If we were not able to acquire a lock, 92 | // Mutex will wake us once we can! 93 | } 94 | }) 95 | .await; 96 | #+END_SRC 97 | 98 | * 99 | 100 | file:imgs/task-notify.png 101 | 102 | https://crates.io/crates/task-notify 103 | 104 | * 105 | 106 | file:imgs/tokio-notify.png 107 | 108 | * Oh about those locks... 109 | 110 | * Async locks 111 | 112 | Don't use ~std::sync~ types to lock! 113 | 114 | + ~tokio::sync::{Mutex, RwLock, Barrier}~ 115 | + ~async_std::sync::{Mutex, RwLock, Barrier}~ 116 | + ~async_lock::{Mutex, RwLock, Barrior}~ 117 | 118 | * [[file:README.org][Back to index]] 119 | -------------------------------------------------------------------------------- /courses/01-advanced-async/032-actor-programming.org: -------------------------------------------------------------------------------- 1 | #+Title: Actor programming 2 | #+SETUPFILE: ../../reveal.setup 3 | 4 | * Actor programming is a model 5 | 6 | * Actor model 7 | 8 | + Split your program into small pieces (called an "Actor") 9 | + Each actor has its own state and can change it 10 | + Each actor can send and receive "Messages" 11 | 12 | That's it. That's really all there is to it 13 | 14 | * 15 | 16 | file:imgs/actor0.png 17 | 18 | * 19 | 20 | file:imgs/actor1.png 21 | 22 | * 23 | 24 | file:imgs/actor2.png 25 | 26 | * 27 | 28 | file:imgs/actor3.png 29 | 30 | * Actors in Rust 31 | 32 | Using an actor framework will reduce boilerplate in your code! Some 33 | frameworks exist already! 34 | 35 | + Actix (built on Tokio) 36 | + Ockam Node (Also built on Tokio, but /differently/) 37 | 38 | * Calculator in Actix 39 | 40 | #+BEGIN_SRC rust 41 | use actix::{Actor, Handler, Context, System}; 42 | 43 | struct Calculator; 44 | 45 | impl Actor for Calculator { 46 | type Context = Context; 47 | } 48 | 49 | #[derive(Message)] 50 | #[rtype(result = "usize")] 51 | struct Sum(usize, usize); 52 | 53 | impl Handler for Calculator { 54 | type Result = usize; 55 | 56 | fn handle(&mut self, msg: Sum, ctx: &mut Context) -> Self::Result { 57 | msg.0 + msg.1 58 | } 59 | } 60 | 61 | #[actix::main] 62 | async fn main() { 63 | let addr = Calculator.start(); 64 | let res = addr.send(Sum(10, 5)).await; 65 | println!("Result: {:?}", res); 66 | } 67 | 68 | #+END_SRC 69 | 70 | 71 | * Calculator with Ockam 72 | 73 | #+BEGIN_SRC rust 74 | use ockam::{Context, Message, Worker, access_control::AllowAll, Routed}; 75 | use serde::{Serialize, Deserialize}; 76 | 77 | #[derive(Debug, Serialize, Deserialize, Message)] 78 | struct SumMessage(usize, usize); 79 | 80 | struct SumWorker; 81 | #[ockam::worker] 82 | impl Worker for SumWorker { 83 | type Context = Context; 84 | type Message = SumMessage; 85 | 86 | async fn handle_message(&mut self, ctx: &mut Context, msg: Routed) -> Result<()> { 87 | ctx.send(msg.return_route(), (msg.0 + msg.1) as u64).await 88 | } 89 | } 90 | 91 | #[ockam::node] 92 | async fn main(mut ctx: Context) -> Result<()> { 93 | ctx.start_worker("sum", SumWorker, AllowAll, AllowAll).await?; 94 | ctx.send("sum", SumMessage(2, 4)).await?; 95 | 96 | // Wait to receive a reply and print it. 97 | let reply = ctx.receive::().await?; 98 | println!("Sum: {}", reply); // should print "6" 99 | 100 | // Shut down everything 101 | ctx.stop().await 102 | } 103 | #+END_SRC 104 | 105 | * 106 | 107 | file:imgs/calypso.png 108 | 109 | Very much not done. 110 | 111 | https://cyberchaos.dev/kookie/calypso 112 | 113 | * [[file:README.org][Back to index]] 114 | -------------------------------------------------------------------------------- /courses/01-advanced-async/033-channels.org: -------------------------------------------------------------------------------- 1 | #+Title: Literally just channels 2 | #+SETUPFILE: ../../reveal.setup 3 | 4 | * How to communicate between tasks? 5 | 6 | * Channels! 7 | 8 | \\ 9 | 10 | #+BEGIN_SRC rust 11 | async fn main() { 12 | let (tx, rx) = async_channel::bounded(64); 13 | smol::spawn(async move { 14 | // Producer loop 15 | while alive() { 16 | let data = get_data_via_magic().await; 17 | tx.send(data).await; 18 | } 19 | }); 20 | 21 | smol::block_on(async move { 22 | // Consumer loop 23 | while let Some(data) = rx.recv().await { 24 | process_data_somehow(data).await; 25 | } 26 | }); 27 | } 28 | #+END_SRC 29 | 30 | * Channels wake up consumers! 31 | 32 | * Type separation (with trait objects) 33 | 34 | \\ 35 | 36 | + In a system with many generic types, channels can provide barriers 37 | + Get type information for a different future 38 | + This was very relevant when writing the Ockam Node runtime 39 | (https://github.com/build-trust/ockam) but might be a bit esoteric 40 | for your application 41 | 42 | * 43 | 44 | file:imgs/type-separation.png 45 | 46 | * 47 | 48 | #+BEGIN_SRC rust 49 | trait Bonkers {} 50 | struct Envelope(pub Box); 51 | 52 | pub struct A { recv: Receiver, } 53 | pub struct B { recv: Receiver, } 54 | 55 | pub struct Lookup { 56 | map: BTreeMap<&'static str, Sender>, 57 | } 58 | 59 | impl Lookup { 60 | fn get_sender_for(&self, id: &str) -> Sender { 61 | self.map.get(id).cloned().unwrap() 62 | } 63 | } 64 | 65 | #+END_SRC 66 | 67 | * 68 | 69 | #+BEGIN_SRC rust 70 | impl A { 71 | fn send_to_b(&self, l: &Lookup, b: Bar) { 72 | let sender = l.get_sender_for("b-my-friend"); 73 | sender.send(Envelope(Box::new(b))).unwrap(); 74 | } 75 | } 76 | 77 | 78 | impl B { 79 | fn handle_new_bar(&self) { 80 | let env = self.recv.recv().unwrap(); 81 | let env_any = env.0.as_any(); 82 | let b: &Bar = env_any.downcast_ref::().unwrap(); 83 | 84 | // Tada >.> 85 | } 86 | } 87 | 88 | impl B { 89 | fn get_bar(&self) -> Box { 90 | let env = self.recv.recv().unwrap(); 91 | core::mem::transmute_copy, Box>(&env.0) 92 | } 93 | } 94 | #+END_SRC 95 | 96 | * Bounded vs unbounded 97 | 98 | *+Not so+ controversial opinion time*: don't use unbounded channels! Why? 99 | 100 | \\ 101 | 102 | + Bounded channels :: Fixed size channels that are _predictable_ and 103 | provide _backpressure_ 104 | + Unbounded channels :: Dynamically grow and shrink with demand. 105 | More _dynamic_ but can grow _infinitely_ 106 | 107 | * What is backpressure? 108 | 109 | \\ 110 | 111 | + A mechanism to bind the production rate to the consumption rate of 112 | two components 113 | + Or: slow down producers for slow consumers 114 | + This can overall slow down a system but prevent it from crashing 115 | 116 | * Backpressure example 117 | 118 | \\ 119 | 120 | file:imgs/bp0.png 121 | 122 | * Backpressure example 123 | 124 | \\ 125 | 126 | file:imgs/bp1.png 127 | 128 | * Backpressure example 129 | 130 | \\ 131 | 132 | file:imgs/bp2.png 133 | 134 | * Backpressure example 135 | 136 | \\ 137 | 138 | file:imgs/bp3.png 139 | 140 | * Backpressure example 141 | 142 | \\ 143 | 144 | file:imgs/bp6.png 145 | 146 | * Backpressure example 147 | 148 | \\ 149 | 150 | file:imgs/bp8.png 151 | 152 | * Backpressure example 153 | 154 | \\ 155 | 156 | file:imgs/bp10.png 157 | 158 | * Demo bounded 159 | 160 | #+INCLUDE: "exercises/02-async-patterns/src/bin/02_backpressure_bounded.rs" src rust 161 | 162 | #+BEGIN_SRC console 163 | $ time -v target/debug/02_backpressure_bounded 164 | Command being timed: "target/debug/02_backpressure_bounded" 165 | Percent of CPU this job got: 5% 166 | Elapsed (wall clock) time (h:mm:ss or m:ss): 0:10.02 167 | Maximum resident set size (kbytes): 4136 168 | Major (requiring I/O) page faults: 291 169 | Minor (reclaiming a frame) page faults: 457 170 | #+END_SRC 171 | 172 | * Demo unbounded 173 | 174 | #+INCLUDE: "exercises/02-async-patterns/src/bin/02_backpressure_unbounded.rs" src rust 175 | 176 | #+BEGIN_SRC console 177 | $ time -v target/debug/02_backpressure_unbounded 178 | Command being timed: "target/debug/02_backpressure_unbounded" 179 | Percent of CPU this job got: 3% 180 | Elapsed (wall clock) time (h:mm:ss or m:ss): 0:10.02 181 | Maximum resident set size (kbytes): 11984 182 | Major (requiring I/O) page faults: 378 183 | Minor (reclaiming a frame) page faults: 2775 184 | #+END_SRC 185 | 186 | 187 | * Types of channels 188 | 189 | \\ 190 | 191 | + Bounded 192 | + Unbounded 193 | + Single Producer, Single Consumer (SPSC) 194 | + Multi Producer, Single Consumer (MPSC) 195 | + Multi Producer, Multi Consumer (MPMC) 196 | + Oneshot 197 | 198 | * [[file:README.org][Back to index]] 199 | -------------------------------------------------------------------------------- /courses/01-advanced-async/033-pin-project.org: -------------------------------------------------------------------------------- 1 | #+Title: Pinning and Pin Project 2 | #+SETUPFILE: ../../reveal.setup 3 | 4 | * Creating ~Pin

~ is annoying 5 | 6 | * Scenario 7 | 8 | \\ 9 | 10 | + ~Arc>>~ as data storage 11 | + Async workers insert data into the map 12 | + Use Notify wrapper to wake consumer after inserts 13 | 14 | * 15 | 16 | #+BEGIN_SRC rust 17 | /// Poll for new work on a particular frame sequence 18 | pub(super) async fn get(&self, seq: &Id) -> Frame { 19 | let incoming = Arc::clone(&self.incoming); 20 | future::poll_fn(|ctx| { 21 | let lock = &mut incoming.lock(); 22 | match unsafe { Pin::new_unchecked(lock).poll(ctx) } { 23 | Poll::Ready(ref mut map) => match map.get_mut(seq) { 24 | Some(ref mut vec) if vec.len() > 0 => Poll::Ready(vec.pop_front().unwrap()), 25 | Some(ref mut vec) => { 26 | Notify::register_waker(vec, ctx.waker()); 27 | Poll::Pending 28 | } 29 | None => unimplemented!(), // No work queue _should_ never happen 30 | }, 31 | _ => Poll::Pending, 32 | } 33 | }) 34 | .await 35 | } 36 | 37 | #+END_SRC 38 | 39 | * Creating the Pin requires ~unsafe { }~. Why? 40 | 41 | * Pin API 42 | 43 | \\ 44 | 45 | + ~Pin

::new~ requires ~P: Unpin~ 46 | + ~Unpin~: reversing Pinning (safe to move after pinning) 47 | + Many types _can't_ be ~Unpin~! 48 | 49 | -------------------------------------------------------------------------------- /courses/01-advanced-async/040-async-hacking.org: -------------------------------------------------------------------------------- 1 | #+Title: Async Hacking 🪓 2 | #+SETUPFILE: ../../reveal.setup 3 | 4 | * Putting all this into practice 5 | 6 | * Chat Client 7 | 8 | (encryption optional) 9 | 10 | \\ 11 | 12 | + Async Server :: Accept connections (TCP, UDP, unix sockets, ... up 13 | to you), handle a message type, and replicate messages to relevant 14 | clients. 15 | + Async Client :: Connect to the server, join a "room", send and 16 | receive messages for this room. 17 | 18 | * Chat Message Type 19 | 20 | \\ 21 | 22 | #+BEGIN_SRC rust 23 | pub enum Message { 24 | TextPayload { room: String, nick: String, content: String, } 25 | JoinRoom { room: String, nick: String } 26 | CreateRoom { room: String } 27 | } 28 | #+END_SRC 29 | 30 | * What structure? 31 | 32 | Pick a runtime/ framework/ design philosophy! 33 | 34 | + async_std/ tokio :: "batteries included", provide synchronisation, 35 | network access, etc 36 | + smol + util crates :: Compose a larger runtime system from smaller 37 | crates. All the tools are there, but need to be assembled in some 38 | way. 39 | + actix/ ockam :: "batteries included" (ish), but will require some 40 | work to map async I/O to actors 41 | 42 | * Boilerplate crate 43 | 44 | \\ 45 | 46 | https://github.com/spacekookie/learning-rust/tree/main/courses/01-advanced-async/exercises/06-async-chat 47 | 48 | (great short url) 49 | 50 | * Other utilities 51 | 52 | \\ 53 | 54 | + serde :: Serialise data (and pick a format) 55 | + futures-rs :: Lots of great combinators for working with futures 56 | (re-exported from smol) 57 | 58 | * Have questions? Getting stuck? 59 | 60 | \\ 61 | 62 | *YELL AT ME (or the other teaching assistants)!* 63 | 64 | Good luck 🚀 65 | 66 | * [[file:README.org][Back to index]] 67 | -------------------------------------------------------------------------------- /courses/01-advanced-async/README.org: -------------------------------------------------------------------------------- 1 | #+Title: Rust async deep-dive course 2 | #+Author: Katharina Fey 3 | #+SETUPFILE: ../../html.setup 4 | 5 | ** Introduction 6 | 7 | This is an _intermediate level_ course, targeted at developers who 8 | have at least _some familiarity with Rust and async development_ 9 | models. 10 | 11 | ** Prerequisites 12 | 13 | + [[./010-what-is-async.org][Async theory: what is async?]] 14 | 15 | 16 | ** Section 1: Basic async I/O 17 | 18 | + [[file:010-async-in-core-std.org][Async in core/std]] 19 | + [[file:011-future-anatomy.org][Anatomy of a Future]] 20 | + [[file:012-exercise-basic.org][Exercise: Write a basic Async wrapper]] 21 | 22 | ** Section 2: Signals & Reactor loops 23 | 24 | + [[file:020-signals.org][What are signals?]] 25 | + [[file:025-runtimes.org][Dive into runtimes]] 26 | + [[file:022-excercise-real-wake.org][Exercise: Write a _better_ Async wrapper]] 27 | 28 | ** Section 3: Advanced Patterns 29 | 30 | + [[file:033-channels.org][Pattern: Channels]] 31 | + [[file:030-shutdown-select.org][Pattern: Shutdown select]] 32 | + [[file:031-wakenotify.org][Pattern: WakeNotify]] 33 | + [[file:032-actor-programming.org][Actor programming]] 34 | + [[file:040-async-hacking.org][Exercise: Write an async chat client]] 35 | 36 | 37 | ** Build these slides 38 | 39 | It's generally recommended to use the [[https://git.irde.st/kookiespace/teaching-rust/-/jobs][CI artifacts]] for these slides, 40 | but if you must build them yourself, you need to have Emacs (v26+) and 41 | org-mode installed! 42 | 43 | The following function will export the full course into an HTML slide 44 | tree. 45 | 46 | #+INCLUDE: "../../ci/export-course.el" src emacs-lisp 47 | 48 | ** License 49 | 50 | This course, as well as any associated media assets is licensed under 51 | Creative Commons CC-BY-SA 3.0. All associated code examples are 52 | licensed under the GNU General Public License Version 3.0 (or later). 53 | 54 | See the [[../licenses][licenses]] directory for complete copies of the applicable 55 | license texts. 56 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/01-future-anatomy/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "async-attributes" 7 | version = "1.1.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" 10 | dependencies = [ 11 | "quote", 12 | "syn", 13 | ] 14 | 15 | [[package]] 16 | name = "async-channel" 17 | version = "1.6.1" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" 20 | dependencies = [ 21 | "concurrent-queue", 22 | "event-listener", 23 | "futures-core", 24 | ] 25 | 26 | [[package]] 27 | name = "async-executor" 28 | version = "1.4.1" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" 31 | dependencies = [ 32 | "async-task", 33 | "concurrent-queue", 34 | "fastrand", 35 | "futures-lite", 36 | "once_cell", 37 | "slab", 38 | ] 39 | 40 | [[package]] 41 | name = "async-global-executor" 42 | version = "2.0.2" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" 45 | dependencies = [ 46 | "async-channel", 47 | "async-executor", 48 | "async-io", 49 | "async-mutex", 50 | "blocking", 51 | "futures-lite", 52 | "num_cpus", 53 | "once_cell", 54 | ] 55 | 56 | [[package]] 57 | name = "async-io" 58 | version = "1.6.0" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" 61 | dependencies = [ 62 | "concurrent-queue", 63 | "futures-lite", 64 | "libc", 65 | "log", 66 | "once_cell", 67 | "parking", 68 | "polling", 69 | "slab", 70 | "socket2", 71 | "waker-fn", 72 | "winapi", 73 | ] 74 | 75 | [[package]] 76 | name = "async-lock" 77 | version = "2.4.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" 80 | dependencies = [ 81 | "event-listener", 82 | ] 83 | 84 | [[package]] 85 | name = "async-mutex" 86 | version = "1.4.0" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" 89 | dependencies = [ 90 | "event-listener", 91 | ] 92 | 93 | [[package]] 94 | name = "async-std" 95 | version = "1.10.0" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "f8056f1455169ab86dd47b47391e4ab0cbd25410a70e9fe675544f49bafaf952" 98 | dependencies = [ 99 | "async-attributes", 100 | "async-channel", 101 | "async-global-executor", 102 | "async-io", 103 | "async-lock", 104 | "crossbeam-utils", 105 | "futures-channel", 106 | "futures-core", 107 | "futures-io", 108 | "futures-lite", 109 | "gloo-timers", 110 | "kv-log-macro", 111 | "log", 112 | "memchr", 113 | "num_cpus", 114 | "once_cell", 115 | "pin-project-lite", 116 | "pin-utils", 117 | "slab", 118 | "wasm-bindgen-futures", 119 | ] 120 | 121 | [[package]] 122 | name = "async-task" 123 | version = "4.0.3" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" 126 | 127 | [[package]] 128 | name = "atomic-waker" 129 | version = "1.0.0" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" 132 | 133 | [[package]] 134 | name = "blocking" 135 | version = "1.1.0" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "046e47d4b2d391b1f6f8b407b1deb8dee56c1852ccd868becf2710f601b5f427" 138 | dependencies = [ 139 | "async-channel", 140 | "async-task", 141 | "atomic-waker", 142 | "fastrand", 143 | "futures-lite", 144 | "once_cell", 145 | ] 146 | 147 | [[package]] 148 | name = "bumpalo" 149 | version = "3.8.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" 152 | 153 | [[package]] 154 | name = "cache-padded" 155 | version = "1.1.1" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" 158 | 159 | [[package]] 160 | name = "cc" 161 | version = "1.0.72" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" 164 | 165 | [[package]] 166 | name = "cfg-if" 167 | version = "1.0.0" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 170 | 171 | [[package]] 172 | name = "concurrent-queue" 173 | version = "1.2.2" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" 176 | dependencies = [ 177 | "cache-padded", 178 | ] 179 | 180 | [[package]] 181 | name = "crossbeam-utils" 182 | version = "0.8.5" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" 185 | dependencies = [ 186 | "cfg-if", 187 | "lazy_static", 188 | ] 189 | 190 | [[package]] 191 | name = "ctor" 192 | version = "0.1.21" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" 195 | dependencies = [ 196 | "quote", 197 | "syn", 198 | ] 199 | 200 | [[package]] 201 | name = "event-listener" 202 | version = "2.5.1" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" 205 | 206 | [[package]] 207 | name = "fastrand" 208 | version = "1.5.0" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" 211 | dependencies = [ 212 | "instant", 213 | ] 214 | 215 | [[package]] 216 | name = "future-anatomy" 217 | version = "0.1.0" 218 | dependencies = [ 219 | "async-std", 220 | ] 221 | 222 | [[package]] 223 | name = "futures-channel" 224 | version = "0.3.18" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" 227 | dependencies = [ 228 | "futures-core", 229 | ] 230 | 231 | [[package]] 232 | name = "futures-core" 233 | version = "0.3.18" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" 236 | 237 | [[package]] 238 | name = "futures-io" 239 | version = "0.3.18" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11" 242 | 243 | [[package]] 244 | name = "futures-lite" 245 | version = "1.12.0" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" 248 | dependencies = [ 249 | "fastrand", 250 | "futures-core", 251 | "futures-io", 252 | "memchr", 253 | "parking", 254 | "pin-project-lite", 255 | "waker-fn", 256 | ] 257 | 258 | [[package]] 259 | name = "gloo-timers" 260 | version = "0.2.1" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" 263 | dependencies = [ 264 | "futures-channel", 265 | "futures-core", 266 | "js-sys", 267 | "wasm-bindgen", 268 | "web-sys", 269 | ] 270 | 271 | [[package]] 272 | name = "hermit-abi" 273 | version = "0.1.19" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 276 | dependencies = [ 277 | "libc", 278 | ] 279 | 280 | [[package]] 281 | name = "instant" 282 | version = "0.1.12" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 285 | dependencies = [ 286 | "cfg-if", 287 | ] 288 | 289 | [[package]] 290 | name = "js-sys" 291 | version = "0.3.55" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" 294 | dependencies = [ 295 | "wasm-bindgen", 296 | ] 297 | 298 | [[package]] 299 | name = "kv-log-macro" 300 | version = "1.0.7" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" 303 | dependencies = [ 304 | "log", 305 | ] 306 | 307 | [[package]] 308 | name = "lazy_static" 309 | version = "1.4.0" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 312 | 313 | [[package]] 314 | name = "libc" 315 | version = "0.2.109" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01" 318 | 319 | [[package]] 320 | name = "log" 321 | version = "0.4.14" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 324 | dependencies = [ 325 | "cfg-if", 326 | "value-bag", 327 | ] 328 | 329 | [[package]] 330 | name = "memchr" 331 | version = "2.4.1" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 334 | 335 | [[package]] 336 | name = "num_cpus" 337 | version = "1.13.0" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 340 | dependencies = [ 341 | "hermit-abi", 342 | "libc", 343 | ] 344 | 345 | [[package]] 346 | name = "once_cell" 347 | version = "1.8.0" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" 350 | 351 | [[package]] 352 | name = "parking" 353 | version = "2.0.0" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" 356 | 357 | [[package]] 358 | name = "pin-project-lite" 359 | version = "0.2.7" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 362 | 363 | [[package]] 364 | name = "pin-utils" 365 | version = "0.1.0" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 368 | 369 | [[package]] 370 | name = "polling" 371 | version = "2.2.0" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" 374 | dependencies = [ 375 | "cfg-if", 376 | "libc", 377 | "log", 378 | "wepoll-ffi", 379 | "winapi", 380 | ] 381 | 382 | [[package]] 383 | name = "proc-macro2" 384 | version = "1.0.32" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" 387 | dependencies = [ 388 | "unicode-xid", 389 | ] 390 | 391 | [[package]] 392 | name = "quote" 393 | version = "1.0.10" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" 396 | dependencies = [ 397 | "proc-macro2", 398 | ] 399 | 400 | [[package]] 401 | name = "slab" 402 | version = "0.4.5" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" 405 | 406 | [[package]] 407 | name = "socket2" 408 | version = "0.4.2" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" 411 | dependencies = [ 412 | "libc", 413 | "winapi", 414 | ] 415 | 416 | [[package]] 417 | name = "syn" 418 | version = "1.0.82" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" 421 | dependencies = [ 422 | "proc-macro2", 423 | "quote", 424 | "unicode-xid", 425 | ] 426 | 427 | [[package]] 428 | name = "unicode-xid" 429 | version = "0.2.2" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 432 | 433 | [[package]] 434 | name = "value-bag" 435 | version = "1.0.0-alpha.8" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "79923f7731dc61ebfba3633098bf3ac533bbd35ccd8c57e7088d9a5eebe0263f" 438 | dependencies = [ 439 | "ctor", 440 | "version_check", 441 | ] 442 | 443 | [[package]] 444 | name = "version_check" 445 | version = "0.9.3" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 448 | 449 | [[package]] 450 | name = "waker-fn" 451 | version = "1.1.0" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" 454 | 455 | [[package]] 456 | name = "wasm-bindgen" 457 | version = "0.2.78" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" 460 | dependencies = [ 461 | "cfg-if", 462 | "wasm-bindgen-macro", 463 | ] 464 | 465 | [[package]] 466 | name = "wasm-bindgen-backend" 467 | version = "0.2.78" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" 470 | dependencies = [ 471 | "bumpalo", 472 | "lazy_static", 473 | "log", 474 | "proc-macro2", 475 | "quote", 476 | "syn", 477 | "wasm-bindgen-shared", 478 | ] 479 | 480 | [[package]] 481 | name = "wasm-bindgen-futures" 482 | version = "0.4.28" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" 485 | dependencies = [ 486 | "cfg-if", 487 | "js-sys", 488 | "wasm-bindgen", 489 | "web-sys", 490 | ] 491 | 492 | [[package]] 493 | name = "wasm-bindgen-macro" 494 | version = "0.2.78" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" 497 | dependencies = [ 498 | "quote", 499 | "wasm-bindgen-macro-support", 500 | ] 501 | 502 | [[package]] 503 | name = "wasm-bindgen-macro-support" 504 | version = "0.2.78" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" 507 | dependencies = [ 508 | "proc-macro2", 509 | "quote", 510 | "syn", 511 | "wasm-bindgen-backend", 512 | "wasm-bindgen-shared", 513 | ] 514 | 515 | [[package]] 516 | name = "wasm-bindgen-shared" 517 | version = "0.2.78" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" 520 | 521 | [[package]] 522 | name = "web-sys" 523 | version = "0.3.55" 524 | source = "registry+https://github.com/rust-lang/crates.io-index" 525 | checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" 526 | dependencies = [ 527 | "js-sys", 528 | "wasm-bindgen", 529 | ] 530 | 531 | [[package]] 532 | name = "wepoll-ffi" 533 | version = "0.1.2" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" 536 | dependencies = [ 537 | "cc", 538 | ] 539 | 540 | [[package]] 541 | name = "winapi" 542 | version = "0.3.9" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 545 | dependencies = [ 546 | "winapi-i686-pc-windows-gnu", 547 | "winapi-x86_64-pc-windows-gnu", 548 | ] 549 | 550 | [[package]] 551 | name = "winapi-i686-pc-windows-gnu" 552 | version = "0.4.0" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 555 | 556 | [[package]] 557 | name = "winapi-x86_64-pc-windows-gnu" 558 | version = "0.4.0" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 561 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/01-future-anatomy/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "future-anatomy" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | async-std = { version = "1.0", features = ["attributes"] } -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/01-future-anatomy/src/always.rs: -------------------------------------------------------------------------------- 1 | use core::{future::Future, pin::Pin, task::{Context, Poll}}; 2 | 3 | pub struct Always; 4 | 5 | impl Future for Always { 6 | type Output = (); 7 | fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<()> { 8 | Poll::Ready(()) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/01-future-anatomy/src/bin/01_never.rs: -------------------------------------------------------------------------------- 1 | use future_anatomy::never::*; 2 | 3 | #[async_std::main] 4 | async fn main() { 5 | let _ = MyFuture.await; // blocks forever 6 | } 7 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/01-future-anatomy/src/bin/02_twice.rs: -------------------------------------------------------------------------------- 1 | use future_anatomy::twice::*; 2 | 3 | #[async_std::main] 4 | async fn main() { 5 | Twice::new().await 6 | } 7 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/01-future-anatomy/src/bin/03_twice.rs: -------------------------------------------------------------------------------- 1 | use future_anatomy::good_twice::*; 2 | 3 | #[async_std::main] 4 | async fn main() { 5 | println!("Future says: {:?}", Twice::new().await) 6 | } 7 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/01-future-anatomy/src/bin/10_timer.rs: -------------------------------------------------------------------------------- 1 | use std::time::{Duration, Instant}; 2 | 3 | struct Timer { 4 | then: Instant, 5 | len: Duration, 6 | } 7 | 8 | #[async_std::main] 9 | async fn main() { 10 | println!("Hello world!"); 11 | Timer::new(Duration::from_secs(1)).await; 12 | println!("This is one second later!"); 13 | } 14 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/01-future-anatomy/src/good_twice.rs: -------------------------------------------------------------------------------- 1 | use core::{future::Future,pin::Pin,task::{Context, Poll}}; 2 | 3 | pub struct Twice(bool); 4 | impl Twice { 5 | pub fn new() -> Self { 6 | Self(false) 7 | } 8 | } 9 | 10 | impl Future for Twice { 11 | type Output = (); 12 | fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<()> { 13 | if self.0 { 14 | Poll::Ready(()) 15 | } else { 16 | self.0 = true; 17 | ctx.waker().wake_by_ref(); 18 | Poll::Pending 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/01-future-anatomy/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Fake library 2 | 3 | pub mod always; 4 | pub mod never; 5 | pub mod twice; 6 | pub mod good_twice; 7 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/01-future-anatomy/src/never.rs: -------------------------------------------------------------------------------- 1 | use core::{future::Future, pin::Pin, task::{Context, Poll}}; 2 | 3 | pub struct Never; 4 | 5 | impl Future for Never { 6 | type Output = (); 7 | fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<()> { 8 | Poll::Pending 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/01-future-anatomy/src/twice.rs: -------------------------------------------------------------------------------- 1 | use core::{future::Future,pin::Pin,task::{Context, Poll}}; 2 | 3 | pub struct Twice(bool); 4 | impl Twice { 5 | pub fn new() -> Self { 6 | Self(false) 7 | } 8 | } 9 | 10 | impl Future for Twice { 11 | type Output = (); 12 | fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<()> { 13 | if self.0 { 14 | dbg!(Poll::Ready(())) 15 | } else { 16 | self.0 = true; 17 | dbg!(Poll::Pending) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/02-async-patterns/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "async-patterns" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | async-std = { version = "1.0", features = ["attributes"] } 8 | tokio = { version = "1.0", features = ["full"] } -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/02-async-patterns/src/bin/01_channels.rs: -------------------------------------------------------------------------------- 1 | use async_std::{channel, task}; 2 | use std::time::Duration; 3 | 4 | #[async_std::main] 5 | async fn main() { 6 | let (tx, rx) = channel::unbounded(); 7 | 8 | task::spawn(async move { 9 | for i in 0..3 { 10 | task::sleep(Duration::from_secs(1)).await; 11 | tx.send(i as i64).await; 12 | } 13 | }); 14 | 15 | while let Ok(i) = rx.recv().await { 16 | println!("Received message: {}", i); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/02-async-patterns/src/bin/02_backpressure_bounded.rs: -------------------------------------------------------------------------------- 1 | use async_std::{channel, task}; 2 | use std::time::Duration; 3 | 4 | #[async_std::main] 5 | async fn main() { 6 | let (tx, rx) = channel::bounded(4); 7 | 8 | task::spawn(async move { 9 | for _ in 0..100 { 10 | tx.send((0..100_000).map(|i| i as u8).collect::>()) 11 | .await 12 | .unwrap(); 13 | } 14 | }); 15 | 16 | while let Ok(i) = rx.recv().await { 17 | println!("Received message: {:?}", i.first()); 18 | task::sleep(Duration::from_millis(100)).await; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/02-async-patterns/src/bin/02_backpressure_unbounded.rs: -------------------------------------------------------------------------------- 1 | use async_std::{channel, task}; 2 | use std::time::Duration; 3 | 4 | #[async_std::main] 5 | async fn main() { 6 | let (tx, rx) = channel::unbounded(); 7 | 8 | task::spawn(async move { 9 | for _ in 0..100 { 10 | tx.send((0..100_000).map(|i| i as u8).collect::>()) 11 | .await 12 | .unwrap(); 13 | } 14 | }); 15 | 16 | while let Ok(i) = rx.recv().await { 17 | println!("Received message: {:?}", i.first()); 18 | task::sleep(Duration::from_millis(100)).await; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/02-async-patterns/src/bin/03_cancel_future.rs: -------------------------------------------------------------------------------- 1 | use async_std::task; 2 | use core::{ 3 | future::Future, 4 | pin::Pin, 5 | task::{Context, Poll}, 6 | }; 7 | use std::time::Duration; 8 | 9 | async fn print_in_10_seconds() { 10 | task::sleep(Duration::from_secs(10)).await; 11 | println!("It's been like... 5 seconds?") 12 | } 13 | 14 | #[async_std::main] 15 | async fn main() { 16 | let p = print_in_10_seconds(); 17 | 18 | task::spawn(p); 19 | task::sleep(Duration::from_secs(2)).await; 20 | println!("It's been 2 seconds and I'm getting impatient..."); 21 | drop(p); 22 | task::sleep(Duration::from_secs(5)).await; 23 | } 24 | 25 | struct BlockHere; 26 | impl Future for BlockHere { 27 | type Output = (); 28 | fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<()> { 29 | Poll::Pending 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/02-async-patterns/src/bin/04_select_tokio.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | use tokio::{select, time::sleep}; 3 | 4 | async fn quickly() -> String { 5 | "Available immediately!".into() 6 | } 7 | 8 | async fn slowly() -> String { 9 | println!("Running slowly..."); 10 | sleep(Duration::from_secs(1)).await; 11 | "Available slowly...".into() 12 | } 13 | 14 | #[tokio::main] 15 | async fn main() { 16 | println!( 17 | "Msg: {}", 18 | select! { 19 | s = slowly() => s, 20 | s = quickly() => s, 21 | } 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/03-runtimes/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "runtimes" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | tokio = { version = "1.0", features = ["full"] } 10 | async-std = { version = "1.0", features = ["attributes"] } 11 | 12 | smol = "1.0" 13 | futures-lite = "1.0" 14 | async-task = "4.0" 15 | 16 | once_cell = "1.0" 17 | flume = "0.10" -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/03-runtimes/src/bin/async-std.rs: -------------------------------------------------------------------------------- 1 | use async_std::task; 2 | 3 | async fn hello() { 4 | println!("Hello world!"); 5 | } 6 | 7 | fn main() { 8 | task::block_on(hello()); 9 | } 10 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/03-runtimes/src/bin/async-task.rs: -------------------------------------------------------------------------------- 1 | use std::{future::Future, panic::catch_unwind, thread}; 2 | 3 | use async_task::{Runnable, Task}; 4 | use futures_lite::future; 5 | use once_cell::sync::Lazy; 6 | 7 | fn main() { 8 | let t = spawn(async { 9 | println!("Hello task!"); 10 | }); 11 | 12 | future::block_on(t); 13 | } 14 | 15 | fn spawn(future: F) -> Task 16 | where 17 | F: Future + Send + 'static, 18 | T: Send + 'static, 19 | { 20 | static Q: Lazy> = Lazy::new(|| { 21 | let (tx, rx) = flume::unbounded::(); 22 | 23 | thread::spawn(move || { 24 | while let Ok(runnable) = rx.recv() { 25 | let _ = catch_unwind(|| runnable.run()); 26 | } 27 | }); 28 | 29 | tx 30 | }); 31 | 32 | let schedule = |runnable| Q.send(runnable).unwrap(); 33 | let (runnable, task) = async_task::spawn(future, schedule); 34 | 35 | runnable.schedule(); 36 | 37 | task 38 | } 39 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/03-runtimes/src/bin/tokio.rs: -------------------------------------------------------------------------------- 1 | use tokio::{runtime::Runtime, task}; 2 | 3 | async fn hello() { 4 | println!("Hello world!"); 5 | } 6 | 7 | fn main() { 8 | let rt = Runtime::new().unwrap(); 9 | task::block_in_place(move || { 10 | let local = task::LocalSet::new(); 11 | local.block_on(&rt, hello()); 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/03-runtimes/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Fake lib 2 | 3 | // use std::time::Duration; 4 | 5 | // pub struct TimedBusyLoop(Duration); 6 | 7 | // impl Future for TimedBusyLoop { 8 | // type Output = (); 9 | // } 10 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/04-wake-notify/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "async-attributes" 7 | version = "1.1.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" 10 | dependencies = [ 11 | "quote", 12 | "syn", 13 | ] 14 | 15 | [[package]] 16 | name = "async-channel" 17 | version = "1.6.1" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" 20 | dependencies = [ 21 | "concurrent-queue", 22 | "event-listener", 23 | "futures-core", 24 | ] 25 | 26 | [[package]] 27 | name = "async-executor" 28 | version = "1.4.1" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" 31 | dependencies = [ 32 | "async-task", 33 | "concurrent-queue", 34 | "fastrand", 35 | "futures-lite", 36 | "once_cell", 37 | "slab", 38 | ] 39 | 40 | [[package]] 41 | name = "async-global-executor" 42 | version = "2.0.2" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" 45 | dependencies = [ 46 | "async-channel", 47 | "async-executor", 48 | "async-io", 49 | "async-mutex", 50 | "blocking", 51 | "futures-lite", 52 | "num_cpus", 53 | "once_cell", 54 | ] 55 | 56 | [[package]] 57 | name = "async-io" 58 | version = "1.6.0" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" 61 | dependencies = [ 62 | "concurrent-queue", 63 | "futures-lite", 64 | "libc", 65 | "log", 66 | "once_cell", 67 | "parking", 68 | "polling", 69 | "slab", 70 | "socket2", 71 | "waker-fn", 72 | "winapi", 73 | ] 74 | 75 | [[package]] 76 | name = "async-lock" 77 | version = "2.4.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" 80 | dependencies = [ 81 | "event-listener", 82 | ] 83 | 84 | [[package]] 85 | name = "async-mutex" 86 | version = "1.4.0" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" 89 | dependencies = [ 90 | "event-listener", 91 | ] 92 | 93 | [[package]] 94 | name = "async-std" 95 | version = "1.10.0" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "f8056f1455169ab86dd47b47391e4ab0cbd25410a70e9fe675544f49bafaf952" 98 | dependencies = [ 99 | "async-attributes", 100 | "async-channel", 101 | "async-global-executor", 102 | "async-io", 103 | "async-lock", 104 | "crossbeam-utils", 105 | "futures-channel", 106 | "futures-core", 107 | "futures-io", 108 | "futures-lite", 109 | "gloo-timers", 110 | "kv-log-macro", 111 | "log", 112 | "memchr", 113 | "num_cpus", 114 | "once_cell", 115 | "pin-project-lite", 116 | "pin-utils", 117 | "slab", 118 | "wasm-bindgen-futures", 119 | ] 120 | 121 | [[package]] 122 | name = "async-task" 123 | version = "4.0.3" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" 126 | 127 | [[package]] 128 | name = "atomic-waker" 129 | version = "1.0.0" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" 132 | 133 | [[package]] 134 | name = "blocking" 135 | version = "1.1.0" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "046e47d4b2d391b1f6f8b407b1deb8dee56c1852ccd868becf2710f601b5f427" 138 | dependencies = [ 139 | "async-channel", 140 | "async-task", 141 | "atomic-waker", 142 | "fastrand", 143 | "futures-lite", 144 | "once_cell", 145 | ] 146 | 147 | [[package]] 148 | name = "bumpalo" 149 | version = "3.8.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" 152 | 153 | [[package]] 154 | name = "cache-padded" 155 | version = "1.1.1" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" 158 | 159 | [[package]] 160 | name = "cc" 161 | version = "1.0.72" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" 164 | 165 | [[package]] 166 | name = "cfg-if" 167 | version = "1.0.0" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 170 | 171 | [[package]] 172 | name = "concurrent-queue" 173 | version = "1.2.2" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" 176 | dependencies = [ 177 | "cache-padded", 178 | ] 179 | 180 | [[package]] 181 | name = "crossbeam-utils" 182 | version = "0.8.5" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" 185 | dependencies = [ 186 | "cfg-if", 187 | "lazy_static", 188 | ] 189 | 190 | [[package]] 191 | name = "ctor" 192 | version = "0.1.21" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" 195 | dependencies = [ 196 | "quote", 197 | "syn", 198 | ] 199 | 200 | [[package]] 201 | name = "event-listener" 202 | version = "2.5.1" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" 205 | 206 | [[package]] 207 | name = "fastrand" 208 | version = "1.5.0" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" 211 | dependencies = [ 212 | "instant", 213 | ] 214 | 215 | [[package]] 216 | name = "futures-channel" 217 | version = "0.3.18" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" 220 | dependencies = [ 221 | "futures-core", 222 | ] 223 | 224 | [[package]] 225 | name = "futures-core" 226 | version = "0.3.18" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" 229 | 230 | [[package]] 231 | name = "futures-io" 232 | version = "0.3.18" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11" 235 | 236 | [[package]] 237 | name = "futures-lite" 238 | version = "1.12.0" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" 241 | dependencies = [ 242 | "fastrand", 243 | "futures-core", 244 | "futures-io", 245 | "memchr", 246 | "parking", 247 | "pin-project-lite", 248 | "waker-fn", 249 | ] 250 | 251 | [[package]] 252 | name = "gloo-timers" 253 | version = "0.2.2" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "6f16c88aa13d2656ef20d1c042086b8767bbe2bdb62526894275a1b062161b2e" 256 | dependencies = [ 257 | "futures-channel", 258 | "futures-core", 259 | "js-sys", 260 | "wasm-bindgen", 261 | "web-sys", 262 | ] 263 | 264 | [[package]] 265 | name = "hermit-abi" 266 | version = "0.1.19" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 269 | dependencies = [ 270 | "libc", 271 | ] 272 | 273 | [[package]] 274 | name = "instant" 275 | version = "0.1.12" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 278 | dependencies = [ 279 | "cfg-if", 280 | ] 281 | 282 | [[package]] 283 | name = "js-sys" 284 | version = "0.3.55" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" 287 | dependencies = [ 288 | "wasm-bindgen", 289 | ] 290 | 291 | [[package]] 292 | name = "kv-log-macro" 293 | version = "1.0.7" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" 296 | dependencies = [ 297 | "log", 298 | ] 299 | 300 | [[package]] 301 | name = "lazy_static" 302 | version = "1.4.0" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 305 | 306 | [[package]] 307 | name = "libc" 308 | version = "0.2.109" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01" 311 | 312 | [[package]] 313 | name = "log" 314 | version = "0.4.14" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 317 | dependencies = [ 318 | "cfg-if", 319 | "value-bag", 320 | ] 321 | 322 | [[package]] 323 | name = "memchr" 324 | version = "2.4.1" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 327 | 328 | [[package]] 329 | name = "num_cpus" 330 | version = "1.13.0" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 333 | dependencies = [ 334 | "hermit-abi", 335 | "libc", 336 | ] 337 | 338 | [[package]] 339 | name = "once_cell" 340 | version = "1.8.0" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" 343 | 344 | [[package]] 345 | name = "parking" 346 | version = "2.0.0" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" 349 | 350 | [[package]] 351 | name = "pin-project-lite" 352 | version = "0.2.7" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 355 | 356 | [[package]] 357 | name = "pin-utils" 358 | version = "0.1.0" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 361 | 362 | [[package]] 363 | name = "polling" 364 | version = "2.2.0" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" 367 | dependencies = [ 368 | "cfg-if", 369 | "libc", 370 | "log", 371 | "wepoll-ffi", 372 | "winapi", 373 | ] 374 | 375 | [[package]] 376 | name = "proc-macro2" 377 | version = "1.0.33" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" 380 | dependencies = [ 381 | "unicode-xid", 382 | ] 383 | 384 | [[package]] 385 | name = "quote" 386 | version = "1.0.10" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" 389 | dependencies = [ 390 | "proc-macro2", 391 | ] 392 | 393 | [[package]] 394 | name = "slab" 395 | version = "0.4.5" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" 398 | 399 | [[package]] 400 | name = "socket2" 401 | version = "0.4.2" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" 404 | dependencies = [ 405 | "libc", 406 | "winapi", 407 | ] 408 | 409 | [[package]] 410 | name = "syn" 411 | version = "1.0.82" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" 414 | dependencies = [ 415 | "proc-macro2", 416 | "quote", 417 | "unicode-xid", 418 | ] 419 | 420 | [[package]] 421 | name = "unicode-xid" 422 | version = "0.2.2" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 425 | 426 | [[package]] 427 | name = "value-bag" 428 | version = "1.0.0-alpha.8" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "79923f7731dc61ebfba3633098bf3ac533bbd35ccd8c57e7088d9a5eebe0263f" 431 | dependencies = [ 432 | "ctor", 433 | "version_check", 434 | ] 435 | 436 | [[package]] 437 | name = "version_check" 438 | version = "0.9.3" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 441 | 442 | [[package]] 443 | name = "wake-notify" 444 | version = "0.1.0" 445 | dependencies = [ 446 | "async-std", 447 | ] 448 | 449 | [[package]] 450 | name = "waker-fn" 451 | version = "1.1.0" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" 454 | 455 | [[package]] 456 | name = "wasm-bindgen" 457 | version = "0.2.78" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" 460 | dependencies = [ 461 | "cfg-if", 462 | "wasm-bindgen-macro", 463 | ] 464 | 465 | [[package]] 466 | name = "wasm-bindgen-backend" 467 | version = "0.2.78" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" 470 | dependencies = [ 471 | "bumpalo", 472 | "lazy_static", 473 | "log", 474 | "proc-macro2", 475 | "quote", 476 | "syn", 477 | "wasm-bindgen-shared", 478 | ] 479 | 480 | [[package]] 481 | name = "wasm-bindgen-futures" 482 | version = "0.4.28" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" 485 | dependencies = [ 486 | "cfg-if", 487 | "js-sys", 488 | "wasm-bindgen", 489 | "web-sys", 490 | ] 491 | 492 | [[package]] 493 | name = "wasm-bindgen-macro" 494 | version = "0.2.78" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" 497 | dependencies = [ 498 | "quote", 499 | "wasm-bindgen-macro-support", 500 | ] 501 | 502 | [[package]] 503 | name = "wasm-bindgen-macro-support" 504 | version = "0.2.78" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" 507 | dependencies = [ 508 | "proc-macro2", 509 | "quote", 510 | "syn", 511 | "wasm-bindgen-backend", 512 | "wasm-bindgen-shared", 513 | ] 514 | 515 | [[package]] 516 | name = "wasm-bindgen-shared" 517 | version = "0.2.78" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" 520 | 521 | [[package]] 522 | name = "web-sys" 523 | version = "0.3.55" 524 | source = "registry+https://github.com/rust-lang/crates.io-index" 525 | checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" 526 | dependencies = [ 527 | "js-sys", 528 | "wasm-bindgen", 529 | ] 530 | 531 | [[package]] 532 | name = "wepoll-ffi" 533 | version = "0.1.2" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" 536 | dependencies = [ 537 | "cc", 538 | ] 539 | 540 | [[package]] 541 | name = "winapi" 542 | version = "0.3.9" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 545 | dependencies = [ 546 | "winapi-i686-pc-windows-gnu", 547 | "winapi-x86_64-pc-windows-gnu", 548 | ] 549 | 550 | [[package]] 551 | name = "winapi-i686-pc-windows-gnu" 552 | version = "0.4.0" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 555 | 556 | [[package]] 557 | name = "winapi-x86_64-pc-windows-gnu" 558 | version = "0.4.0" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 561 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/04-wake-notify/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wake-notify" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | async-std = { version = "1.0", features = ["attributes"] } -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/04-wake-notify/src/lib.rs: -------------------------------------------------------------------------------- 1 | use core::task::Waker; 2 | use std::ops::{Deref, DerefMut}; 3 | 4 | #[derive(Default, Debug, Clone)] 5 | pub struct Notify { 6 | inner: T, 7 | waker: Option, 8 | } 9 | 10 | impl Deref for Notify { 11 | type Target = T; 12 | fn deref(&self) -> &Self::Target { 13 | &self.inner 14 | } 15 | } 16 | 17 | impl DerefMut for Notify { 18 | fn deref_mut(&mut self) -> &mut Self::Target { 19 | self.waker.as_ref().map(|w| w.wake_by_ref()); 20 | &mut self.inner 21 | } 22 | } 23 | 24 | impl Notify { 25 | pub fn new(inner: T) -> Self { 26 | Self { inner, waker: None } 27 | } 28 | 29 | pub fn wake(ptr: &Notify) { 30 | if let Some(ref w) = ptr.waker { 31 | w.wake_by_ref(); 32 | } 33 | } 34 | 35 | pub fn add_waker(ptr: &mut Notify, w: Waker) { 36 | ptr.waker = Some(w); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/04-wake-notify/src/main.rs: -------------------------------------------------------------------------------- 1 | use async_std::{ 2 | future::{self, Future}, 3 | sync::{Arc, Mutex}, 4 | task, 5 | }; 6 | use std::{collections::BTreeMap, pin::Pin, task::Poll, time::Duration}; 7 | use wake_notify::Notify; 8 | 9 | type Collection = Arc>>>; 10 | 11 | #[async_std::main] 12 | async fn main() { 13 | let c = Arc::new(Mutex::new(Notify::new(BTreeMap::new()))); 14 | 15 | task::spawn(insert_task(Arc::clone(&c))); 16 | get_task(Arc::clone(&c)).await; 17 | } 18 | 19 | async fn insert_task(t: Collection) { 20 | for i in 0..10 { 21 | let mut mg = t.lock().await; 22 | println!("Inserting item..."); 23 | mg.insert(format!("Key {}", i), format!("Value {}", i * 2)); 24 | Notify::wake(&*mg); 25 | drop(mg); 26 | task::sleep(Duration::from_millis(1)).await; 27 | } 28 | } 29 | 30 | async fn get_task(t: Collection) { 31 | let mut i = 0; 32 | while i < 10 { 33 | let item = future::poll_fn(|ctx| { 34 | let mut lock = Box::pin(t.lock()); 35 | match Pin::new(&mut lock).poll(ctx) { 36 | Poll::Ready(ref mut mg) => match mg.remove(&format!("Key {}", i)) { 37 | Some(v) => { 38 | i += 1; // Increment for the next key 39 | Poll::Ready(v) 40 | } 41 | None => { 42 | println!("Lock acquired but no new item"); 43 | Notify::add_waker(mg, ctx.waker().clone()); 44 | Poll::Pending 45 | } 46 | }, 47 | _ => Poll::Pending, 48 | } 49 | }) 50 | .await; 51 | 52 | println!("Item: {:?}", item); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/05-actors/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "actors-example" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | actix = "0.12" 8 | ockam = { version = "0.41", no-default-features = true, features = ["std"] } 9 | serde = { version = "1.0", features = ["derive"] } -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/05-actors/src/bin/actix.rs: -------------------------------------------------------------------------------- 1 | use actix::prelude::*; 2 | 3 | #[derive(Message)] 4 | #[rtype(result = "usize")] 5 | struct Sum(usize, usize); 6 | 7 | struct Calculator; 8 | 9 | impl Actor for Calculator { 10 | type Context = Context; 11 | } 12 | 13 | impl Handler for Calculator { 14 | type Result = usize; 15 | 16 | fn handle(&mut self, msg: Sum, _: &mut Context) -> Self::Result { 17 | msg.0 + msg.1 18 | } 19 | } 20 | 21 | #[actix::main] 22 | async fn main() { 23 | let addr = Calculator.start(); 24 | let res = addr.send(Sum(10, 5)).await; 25 | 26 | match res { 27 | Ok(result) => println!("SUM: {}", result), 28 | _ => println!("Communication to the actor has failed"), 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/05-actors/src/bin/ockam.rs: -------------------------------------------------------------------------------- 1 | use ockam::{Context, Message, Result, Routed, Worker}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | struct Calculator; 5 | 6 | #[derive(Serialize, Deserialize, Message)] 7 | struct Sum(usize, usize); 8 | 9 | #[derive(Serialize, Deserialize, Message)] 10 | struct SumReply(usize); 11 | 12 | #[ockam::worker] 13 | impl Worker for Calculator { 14 | type Context = Context; 15 | type Message = Sum; 16 | 17 | async fn handle_message(&mut self, ctx: &mut Context, msg: Routed) -> Result<()> { 18 | ctx.send(msg.return_route(), SumReply(msg.0 + msg.1)).await 19 | } 20 | } 21 | 22 | #[ockam::node] 23 | async fn main(ctx: &mut Context) -> Result<()> { 24 | ctx.start_worker("calc", Calculator).await?; 25 | ctx.send("calc", Sum(10, 5)).await?; 26 | 27 | let res = ctx.receive::().await?; 28 | println!("Sum: {}", res.0); 29 | 30 | ctx.stop().await 31 | } 32 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/06-async-chat/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "async-chat" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | ### First, you should pick a basic structure for this exercise! 7 | [dependencies] 8 | 9 | ### The differences between tokio and async-std are very small. 10 | # tokio = { version = "1.0", features = ["full"] } 11 | # async-std = { version = "1.0", features = ["attribute"] } 12 | 13 | 14 | ### If you pick smol you will need to rely on some other utility 15 | ### crates as well (for example async-lock, async-net, async-channel) 16 | # smol = "1.0" 17 | # async-lock = "2.0" 18 | # async-net = "1.0" 19 | # async-channel = "1.0" 20 | 21 | 22 | ### You can also try your hand at actor programming with Actix. Two 23 | ### crates are needed here: Actix, and the Actix runtime, which 24 | ### re-exports a lot of tokio utilities for network and socket access! 25 | # actix = "0.11" 26 | # actix-rt = "2.0" 27 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/06-async-chat/src/bin/client.rs: -------------------------------------------------------------------------------- 1 | use async_chat::*; 2 | 3 | fn main() { 4 | // 1. Initialise some kind of runtime 5 | // 2. Listen for connections on a socket (TCP, UDP, Unix, ... again, up to you) 6 | // 3. Listen for user input (for example via stdin) 7 | // 4. For each "line" of input... 8 | // - Parse input into command/ Message 9 | // - Send message to server 10 | // - Respond to server reply 11 | 12 | // How do you handle shutdowns? Can the client shut down the 13 | // server? Or does the client only respond to shutdowns? 14 | } 15 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/06-async-chat/src/bin/server.rs: -------------------------------------------------------------------------------- 1 | use async_chat::*; 2 | 3 | fn main() { 4 | // 1. Initialise some kind of runtime 5 | // 2. Listen for connections on a socket (TCP, UDP, Unix, ... again, up to you) 6 | // 3. For each connection... 7 | // - Parse incoming message 8 | // - Handle any relevant state 9 | // - Send out messages to relevant clients 10 | 11 | // How do you handle shutdowns? What information is passed to clients? 12 | } 13 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/06-async-chat/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Main library crate entry point 2 | //! 3 | //! Any code that could potentially be shared between client and 4 | //! server should go here. 5 | 6 | pub mod message; 7 | -------------------------------------------------------------------------------- /courses/01-advanced-async/exercises/06-async-chat/src/message.rs: -------------------------------------------------------------------------------- 1 | //! This is the only part of the system that is pre-specified 2 | //! 3 | //! You can change this message structure of course, but it will give 4 | //! you some guidance on how to proceed. 5 | 6 | pub enum Message { 7 | /// A text message sent from one person to a room, or relayed from 8 | /// a room to a client 9 | TextPayload { 10 | room: String, 11 | nick: String, 12 | content: String, 13 | }, 14 | /// A request to join a room. You _can_ add another message type 15 | /// for leaving rooms, but this can usually also be handled via 16 | /// the connection state 17 | JoinRoom { room: String, nick: String }, 18 | /// A request to create a room 19 | CreateRoom { room: String }, 20 | // Potentially missing: ShutdownRequest and/or ShutdownNotice 21 | } 22 | -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/actor.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 40 | 42 | 50 | 55 | 56 | 64 | 69 | 70 | 78 | 83 | 84 | 92 | 97 | 98 | 99 | 103 | 110 | MyActor 121 | 128 | ActorState 139 | 146 | ActorState 157 | 158 | 186 | 191 | 198 | Message 209 | 213 | 214 | 225 | 226 | -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/actor0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/actor0.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/actor1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/actor1.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/actor2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/actor2.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/actor3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/actor3.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/async-essay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/async-essay.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/backpressure.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 43 | 50 | 57 | 58 | 60 | 68 | 73 | 74 | 82 | 87 | 88 | 89 | 93 | 100 | 107 | 112 | Producer 123 | Consumer 134 | 135 | 141 | ! 152 | 153 | 159 | 165 | 172 | 173 | 179 | 186 | 191 | 192 | 198 | 205 | 206 | 212 | 219 | 220 | 226 | 233 | 234 | 240 | 247 | 248 | 254 | 261 | 262 | 268 | 275 | 276 | 277 | 278 | -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/bp0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/bp0.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/bp1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/bp1.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/bp10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/bp10.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/bp2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/bp2.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/bp3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/bp3.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/bp4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/bp4.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/bp5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/bp5.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/bp6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/bp6.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/bp7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/bp7.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/bp8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/bp8.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/bp9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/bp9.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/calypso.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/calypso.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/concurrency0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/concurrency0.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/concurrency1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/concurrency1.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/concurrency2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/concurrency2.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/external-signal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 36 | 38 | 46 | 51 | 52 | 60 | 65 | 66 | 74 | 79 | 80 | 88 | 93 | 94 | 102 | 107 | 108 | 116 | 121 | 122 | 123 | 239 | 243 | 250 | 253 | 260 | A<Foo> 271 | 272 | 275 | 282 | B<Bar> 293 | 294 | /Some kind of lookup structure/ 305 | 309 | 313 | Sender<Bar> 324 | 328 | 329 | 330 | -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/external-wake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/external-wake.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/gen/future-lifecycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/gen/future-lifecycle.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/gen/future-lifecycle2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/gen/future-lifecycle2.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/gen/future-lifecycle3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/gen/future-lifecycle3.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/parallelism1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/parallelism1.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/pin0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/pin0.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/pin10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/pin10.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/pin11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/pin11.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/pin12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/pin12.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/rust.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/rust.gif -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/rustlatam2019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/rustlatam2019.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/task-notify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/task-notify.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/tokio-notify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/tokio-notify.png -------------------------------------------------------------------------------- /courses/01-advanced-async/imgs/type-separation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/01-advanced-async/imgs/type-separation.png -------------------------------------------------------------------------------- /courses/02-ownership/10-memory-management.org: -------------------------------------------------------------------------------- 1 | #+Title: What is memory management? 2 | #+Subtitle: I forgot 3 | #+SETUPFILE: ../reveal.setup 4 | 5 | * Why is memory management important? 6 | 7 | + Computer programs are fundamentally about managing memory 8 | + Even if it sometimes doesn't seem like this 9 | + Bad memory management can have very bad consequences 10 | + Most security vulnerabilities are caused by bad memory management 11 | + Bad memory management can massively impact performance 12 | 13 | #+BEGIN_NOTES 14 | + [ ] Add security citations 15 | + [ ] Rephrase second section 16 | #+END_NOTES 17 | 18 | 19 | * _Computers are abstraction machines_ 20 | 21 | 22 | * Memory model 23 | 24 | In the following slide-decks we will use a model of memory to 25 | demonstrate scenarios. 26 | 27 | + Memory is split into _Heap_ and _Stack_ 28 | + Stack stores local variables and function call data 29 | + Heap stores program data and dynamic allocations 30 | + We keep track of important variables and function calls 31 | + What the CPU does exactly is not important 32 | 33 | 34 | * Scenario 1: allocate memory 35 | 36 | Initially we only have our currenty function call on the stack 37 | 38 | file:imgs/cpu0.png 39 | 40 | 41 | * Scenario 1: allocate memory 42 | 43 | We allocate some memory on the heap 44 | 45 | file:imgs/cpu1.png 46 | 47 | 48 | * Scenario 1: allocate memory 49 | 50 | Other function calls can then use this memory 51 | 52 | file:imgs/cpu2.png 53 | 54 | 55 | * _This is manual memory management_ 56 | 57 | 58 | * Manual memory management 59 | 60 | + All memory is allocated and de-allocated by the user 61 | + Use pointers explicitly to refer to data 62 | + Very "low level" 63 | + What could go wrong? :) 64 | 65 | 66 | * Scenario 2: use after free 67 | 68 | In this scenario we start with some allocated memory 69 | 70 | file:imgs/uaf0.png 71 | 72 | 73 | * Scenario 2: use after free 74 | 75 | We now call ~free~ to de-allocate the memory again 76 | 77 | file:imgs/uaf1.png 78 | 79 | 80 | * Scenario 2: use after free 81 | 82 | Now we do something silly and try to use the memory anyway 83 | 84 | file:imgs/uaf2.png 85 | 86 | 87 | * Manual memory management 88 | 89 | + Expecting the user to manage memory _can_ be beneficial to performance 90 | + Most likely it will be bad for _stability_ and _security_! 91 | + What is the alternative? 92 | 93 | 94 | * Garbage collection 95 | 96 | 97 | * Garbage collection 98 | 99 | + Instead of making the user free memory themselves, "we" (the 100 | program) counts memory/ object "references" 101 | + When no more references to a piece of memory exist, that object 102 | can be removed 103 | + This is done by a special runtime called _Garbage collector_ 104 | 105 | 106 | * Garbage collection 107 | 108 | We start with an empty call-stack and (mostly) empty heap 109 | 110 | file:imgs/gc0.png 111 | 112 | 113 | * Garbage collection 114 | 115 | Instead of _allocating memory_ we _create a string_ 116 | 117 | file:imgs/gc1.png 118 | 119 | 120 | * Garbage collection 121 | 122 | Increment the use-count when using the string to create a new object 123 | 124 | file:imgs/gc2.png 125 | 126 | 127 | * Garbage collection 128 | 129 | When the function returns the stack usage is removed 130 | 131 | file:imgs/gc3.png 132 | 133 | 134 | * Garbage collection 135 | 136 | At some point in the future the ~Foo~ object goes out of scope 137 | 138 | file:imgs/gc4.png 139 | 140 | 141 | * Garbage collection 142 | 143 | Which then also triggers the string to go out of scopen 144 | 145 | file:imgs/gc5.png 146 | 147 | 148 | * Garbage collection 149 | 150 | And memory is empty again 151 | 152 | file:imgs/gc6.png 153 | 154 | 155 | * Summary 156 | 157 | + Memory management is fundamental to writing code 158 | + Impacts language usability and program stability/ security 159 | + Vastly different design philosophies exist 160 | + Explicit model: use ~malloc~ and ~free~ directly 161 | + Implicit model: hide memory allocations behind objects and 162 | reference counting 163 | 164 | **What does Rust do?** 165 | 166 | [[file:README.org][Back to index]] 167 | -------------------------------------------------------------------------------- /courses/02-ownership/20-why-ownership.org: -------------------------------------------------------------------------------- 1 | #+Title: Why ownership? 2 | #+Subtitle: ☭☭☭ 3 | #+SETUPFILE: ../reveal.setup 4 | 5 | * Fundamental design 6 | 7 | + Every value has exactly **one owner** 8 | + Memory is cleaned up by the **owner** 9 | + Ownership can be passed on 10 | + Memory may be borrowed (according to rules) 11 | + Memory can't be cleaned up if borrowed 12 | 13 | * _These rules are a fundamental part of the Rust type system_ 14 | 15 | * Example 16 | 17 | We create a ~Dot~ and let pacman eat it. nom nom nom! 18 | 19 | #+BEGIN_SRC rust 20 | #[derive(Debug)] 21 | struct Dot { 22 | x: i64, 23 | y: i64, 24 | } 25 | 26 | fn main() { 27 | let dot = Dot { x: 2, y: 1 }; 28 | 29 | pacman(dot); 30 | } 31 | 32 | fn pacman(dot: Dot) { 33 | println!("Eating {:?}", dot); 34 | } 35 | #+END_SRC 36 | 37 | * Quiz #1 38 | 39 | What happens if we call '~pacman(dot)~' twice? 40 | 41 | #+BEGIN_SRC rust 42 | #[derive(Debug)] 43 | struct Dot { 44 | x: i64, 45 | y: i64, 46 | } 47 | 48 | fn main() { 49 | let dot = Dot { x: 2, y: 1 }; 50 | pacman(dot); 51 | pacman(dot); 52 | } 53 | 54 | fn pacman(dot: Dot) { 55 | println!("Eating {:?}", dot); 56 | } 57 | #+END_SRC 58 | 59 | * Quiz #1 - Answer 60 | 61 | When we call ~pacman~ ownership is moved. When ~pacman~ function ends the value is dropped. 62 | 63 | #+BEGIN_SRC dot :file imgs/gen/move-owner.png :cmdline -Kdot -Tpng 64 | digraph { 65 | node [shape=box, fontsize=24, margin="0.25,0.25"] 66 | rankdir = "LR" 67 | 68 | main [color=darkgreen, shape=box] 69 | pacman [color=darkgreen, shape=box] 70 | 🗑️ [color=red, shape=box] 71 | main -> pacman -> 🗑️; 72 | } 73 | #+END_SRC 74 | 75 | #+RESULTS: 76 | [[file:imgs/gen/move-owner.png]] 77 | 78 | * Cloning technology 79 | 80 | To get around this, we can explicitly clone ~Dot~! 81 | 82 | #+BEGIN_SRC rust 83 | #[derive(Debug, Clone)] // <-- implement Clone 84 | struct Dot { 85 | x: i64, 86 | y: i64, 87 | } 88 | 89 | fn main() { 90 | let dot = Dot { x: 2, y: 1 }; 91 | pacman(dot.clone()); // <-- Clone 'dot' 92 | pacman(dot); 93 | } 94 | 95 | fn pacman(dot: Dot) { 96 | println!("Eating {:?}", dot); 97 | } 98 | #+END_SRC 99 | 100 | * Cloning technology 101 | 102 | #+BEGIN_SRC dot :file imgs/gen/clone-move.png :cmdline -Kdot -Tpng 103 | digraph { 104 | node [shape=box, fontsize=24, margin="0.25,0.25"] 105 | rankdir = "LR" 106 | 107 | main [color=darkgreen, shape=box] 108 | clone [color=teal, shape=box] 109 | pacman1 [label="pacman", color=darkgreen, shape=box] 110 | pacman2 [label="pacman", color=darkgreen, shape=box] 111 | drop1 [label="🗑️", color=red, shape=box] 112 | drop2 [label="🗑️", color=red, shape=box] 113 | main -> pacman1 -> drop1; 114 | main -> clone -> pacman2 -> drop2; 115 | } 116 | #+END_SRC 117 | 118 | #+RESULTS: 119 | [[file:imgs/gen/clone-move.png]] 120 | 121 | * Cloning is always a deep-clone and _can_ become costly! 122 | 123 | * ~Copy~ vs ~Clone~ 124 | 125 | Alternatively types can implement ~Copy~. This is meant for data 126 | that can be quickly copied in-memory (using ~memcopy~) and are 127 | allowed to be copied. 128 | 129 | #+BEGIN_SRC rust 130 | #[derive(Copy, Clone, Debug)] // <-- Add both Copy _and_ Clone here 131 | struct Dot { x: i64, y: i64 } 132 | 133 | fn main() { 134 | let dot = Dot { x: 2, y: 1 }; 135 | pacman(dot); // <-- Implicitly copy dot here 136 | pacman(dot); 137 | } 138 | 139 | fn pacman(dot: Dot) { 140 | println!("Eating {:?}", dot); 141 | } 142 | #+END_SRC 143 | 144 | Important: ~Copy~ is just a marker trait. A ~Copy~ type must still 145 | implement ~Clone~! 146 | 147 | * Quiz #2 148 | 149 | What happens if we call ~use_file~ twice? 150 | 151 | #+BEGIN_SRC rust 152 | use std::fs::File; 153 | 154 | fn main() { 155 | let f = File::open("/dev/zero").unwrap(); 156 | 157 | use_file(f); 158 | use_file(f); 159 | } 160 | 161 | fn use_file(f: File) { 162 | // ... do some stuff 163 | } 164 | #+END_SRC 165 | 166 | * Quiz #3 167 | 168 | How is ~core::mem::drop~ implemented? 169 | 170 | #+BEGIN_SRC rust 171 | use std::fs::File; 172 | 173 | fn main() { 174 | let f = File::open("/dev/zero").unwrap(); 175 | drop(f); 176 | 177 | // 'f' no longer available! 178 | } 179 | #+END_SRC 180 | 181 | * Quiz #3 - Answer 182 | 183 | + ~drop(...)~ takes ownership of any generic type 184 | + Then does absolutely nothing 185 | + ~rustc~ will ( _at compile time_ ) insert statements to free memory 186 | at the end of this function scope 187 | 188 | #+BEGIN_SRC rust 189 | #[inline] 190 | fn drop(_x: T) { 191 | // take ownership, drop out of scope 192 | } 193 | #+END_SRC 194 | 195 | * Ownership scopes 196 | 197 | + An owning type 198 | + An owning function 199 | + An owning ~{ }~ scope 200 | 201 | #+BEGIN_SRC rust 202 | struct MyStruct { 203 | // They who own MyStruct control the String 204 | txt: String, 205 | } 206 | 207 | fn function_scope() { 208 | let s = String::from("Hello function"); println!("{}", s); 209 | // s goes out of scope here 210 | 211 | { 212 | let s2 = String::from("Hello scope"); println!("{}", s2); 213 | // s2 goes out of scope here 214 | } 215 | } 216 | #+END_SRC 217 | 218 | * In conclusion 219 | 220 | + Ownership allows the compiler to _reason about our code_ 221 | + This is good 222 | + Ownership places _restrictions and limitations_ on our code 223 | + This is bad 224 | + ...or is it? 225 | 226 | [[file:README.org][Back to index]] 227 | -------------------------------------------------------------------------------- /courses/02-ownership/21-thought-on-raii.org: -------------------------------------------------------------------------------- 1 | #+Title: A thought on RAII 2 | #+Subtitle: For you C++ weirdos in the audience :) 3 | #+SETUPFILE: ../reveal.setup 4 | 5 | * Rust enforces RAII 6 | 7 | Resource Acquisition Is Initialisation 8 | 9 | * 10 | 11 | This prevents memory leaks and provides a linear structure for 12 | memory ownership 13 | 14 | * Lifecycle 15 | 16 | #+BEGIN_SRC dot :file imgs/gen/raii.png :cmdline -Kdot -Tpng 17 | digraph { 18 | node [color=teal, shape=box, fontsize=24, margin="0.25,0.25"] 19 | rankdir = "LR" 20 | 21 | Destruction [color=red] 22 | Acquisition [color=green] 23 | Lifetime [color=green] 24 | Borrow [color=cyan] 25 | BorrowDrop [label="Borrow out\nof scope", color=cyan] 26 | 27 | Start -> Acquisition -> Lifetime -> "Out of scope" -> Destruction; 28 | Lifetime -> Borrow -> BorrowDrop -> Lifetime 29 | } 30 | #+END_SRC 31 | 32 | * What if a borrow outlives its owner? 33 | 34 | * Destructor trait 35 | 36 | + Rust provides destructor mechanics via ~Drop~ trait 37 | + Provides mutible access before being cleaned up 38 | 39 | #+BEGIN_SRC rust 40 | struct Point(i64, i64); 41 | 42 | impl Drop for Point { 43 | fn drop(&mut self) { 44 | println!("De-allocating Point ({}:{})", self.0, self.1); 45 | } 46 | } 47 | #+END_SRC 48 | 49 | * [[file:README.org][Back to index]] 50 | -------------------------------------------------------------------------------- /courses/02-ownership/25-ownership-quiz.org: -------------------------------------------------------------------------------- 1 | #+Title: Exercise: seizing ownership 2 | #+SETUPFILE: ../reveal.setup 3 | 4 | 5 | * 6 | 7 | In these exercises you need to apply the ownership principles 8 | introduced in the last slide deck to make the demos work. 9 | 10 | https://teach.spacekookie.de/rust/ownership 11 | 12 | 13 | * 14 | 15 | **Q:** Why does this code not compile? 16 | 17 | #+BEGIN_SRC rust 18 | fn main() { 19 | { 20 | let x = 42; 21 | println!("x: {}", x); 22 | } 23 | 24 | println!("x: {}", x); 25 | } 26 | #+END_SRC 27 | 28 | 29 | * 30 | 31 | **Q:** In what order are the statements printed? 32 | 33 | #+BEGIN_SRC rust 34 | #[derive(Debug)] struct DropMe; 35 | 36 | impl Drop for DropMe { 37 | fn drop(&mut self) { 38 | println!("Dropping 'DropMe'"); 39 | } 40 | } 41 | 42 | fn main() { 43 | println!("Start"); 44 | { 45 | let x = DropMe; 46 | println!("x: {:?}", x); 47 | } 48 | 49 | println!("End"); 50 | } 51 | #+END_SRC 52 | 53 | 54 | * 55 | 56 | **Q:** Why does this code not compile? 57 | 58 | #+BEGIN_SRC rust 59 | fn main() { 60 | let a = vec![1, 2, 3]; 61 | let b = a; 62 | 63 | println!("vec: {:?}", a); 64 | } 65 | #+END_SRC 66 | 67 | * [[file:README.org][Back to index]] 68 | -------------------------------------------------------------------------------- /courses/02-ownership/30-borrowing.org: -------------------------------------------------------------------------------- 1 | #+Title: Borrowing 2 | #+REVEAL_TITLE_SLIDE_BACKGROUND: ./imgs/ned_flanders.jpg 3 | #+SETUPFILE: ../reveal.setup 4 | 5 | * Anything owned can be borrowed 6 | 7 | * 8 | 9 | Ownership provides a good base for managing memory, but becomes 10 | impractical for larger programs! 11 | 12 | * 13 | 14 | #+BEGIN_SRC rust 15 | #[derive(Debug)] 16 | struct Dot { 17 | x: i64, 18 | y: i64, 19 | } 20 | 21 | fn main() { 22 | let mut dot = Dot { x: 2, y: 1 }; 23 | inspect(&dot); 24 | dot.x = 1; 25 | inspect(&dot); 26 | } 27 | 28 | fn inspect(dot: &Dot) { 29 | println!("An interesting dot {:?}", dot); 30 | } 31 | #+END_SRC 32 | 33 | * Immutable borrow 34 | 35 | + Gives access to memory without ownership 36 | + Doesn't allow to make changes! 37 | 38 | #+BEGIN_SRC dot :file imgs/gen/borrow1.png :cmdline -Kdot -Tpng 39 | digraph { 40 | node [shape=box, fontsize=24, margin="0.25,0.25"] 41 | rankdir = "LR" 42 | 43 | main [color=darkgreen, shape=box] 44 | inspect1 [label="inspect", color=cyan, shape=box] 45 | inspect2 [label="inspect", color=cyan, shape=box] 46 | 🗑️ [color=red, shape=box] 47 | main -> inspect1 [label="&", style=dashed] 48 | main -> inspect2 [label="&", style=dashed] 49 | main -> 🗑️; 50 | } 51 | #+END_SRC 52 | 53 | * What if you want to change things? 54 | * 55 | 56 | #+BEGIN_SRC rust 57 | #[derive(Debug)] 58 | struct Dot { x: i64, y: i64, } 59 | 60 | fn main() { 61 | let mut dot = Dot { x: 2, y: 1 }; 62 | println!("Before: {:?}", dot); 63 | move_by(&mut dot, 1, 3); 64 | println!("After: {:?}", dot); 65 | } 66 | 67 | fn move_by(dot: &mut Dot, x: i64, y: i64) { 68 | dot.x += x; 69 | dot.y += y; 70 | } 71 | #+END_SRC 72 | 73 | * Mutable borrow 74 | 75 | + Gives mutable access to memory without ownership 76 | + Can make changes in-place 77 | 78 | #+BEGIN_SRC dot :file imgs/gen/borrow2.png :cmdline -Kdot -Tpng 79 | digraph { 80 | node [shape=box, fontsize=24, margin="0.25,0.25"] 81 | rankdir = "LR" 82 | 83 | main [color=darkgreen, shape=box] 84 | println1 [label="println", color=cyan, shape=box] 85 | move_by [color=orange, shape=box] 86 | println2 [label="println", color=cyan, shape=box] 87 | 🗑️ [color=red, shape=box] 88 | main -> println1 [label="&", style=dashed] 89 | main -> move_by [label="&mut", style=dashed] 90 | main -> println2 [label="&", style=dashed] 91 | main -> 🗑️; 92 | } 93 | #+END_SRC 94 | 95 | * Borrow types 96 | 97 | + &T :: Immutable borrow of ~T~ 98 | + &mut T :: Mutable borrow of ~T~ 99 | + &&T :: Immutable borrow of an immutable borrow of ~T~ 100 | + ... :: Etc. 101 | 102 | * Borrow rules 103 | 104 | Just like ownership, Rust imposes some rules for borrows! 105 | 106 | + An unlimited number of immutable borrows 107 | + _Exactly one_ mutable borrow 108 | 109 | Ownership remains in the calling context, which handles deallocation 110 | 111 | * Don't try this at home 112 | 113 | #+BEGIN_SRC rust 114 | fn main() { 115 | let mut og = String::from("Yikes!"); 116 | let b1 = &og; 117 | let b2 = &og; 118 | let b3 = &mut og; 119 | 120 | println!("{}, {}, {}", b1, b2, b3); 121 | } 122 | #+END_SRC 123 | 124 | * Just like ownership: _this is part of the Rust type system!_ 125 | 126 | * Quiz #1 127 | 128 | Why does this code not compile? 129 | 130 | #+BEGIN_SRC rust 131 | #[derive(Debug)] 132 | struct Dot { x: i64, y: i64, } 133 | 134 | fn main() { 135 | let mut dot = Dot { x: 2, y: 1 }; 136 | increment(&mut dot, &mut dot.x, 3); 137 | } 138 | 139 | fn increment(dot: &mut Dot, x: &mut i64, num: u64) { 140 | dot.y += num; 141 | *x += num; 142 | } 143 | #+END_SRC 144 | 145 | * Conclusion 146 | 147 | + Borrows are vital for building complex applications 148 | + There are some limitations attached. 149 | + Fundamental part of the Rust type system. You can't "turn off" 150 | the borrow checker 151 | 152 | [[file:README.org][Back to index]] 153 | 154 | -------------------------------------------------------------------------------- /courses/02-ownership/35-borrowing-exercises.org: -------------------------------------------------------------------------------- 1 | #+Title: Lend me your ~&T~ 2 | #+Subtitle: Practical application of borrows, lifetimes, and more 3 | #+SETUPFILE: ../reveal.setup 4 | 5 | * Let's put theory into praxis! 6 | 7 | * 8 | 9 | #+BEGIN_SRC rust 10 | fn make_vec<'num>(x: &'num i64, y: &'num i64, z: &'num i64) -> Vec<&'num i64> { 11 | // ... fill in this function 12 | } 13 | 14 | fn main() { 15 | let (x, y, z) = (1, 5, 5); 16 | let v = make_vec(&x, &y, &z); 17 | println!("Vector: {:?}", v); 18 | } 19 | #+END_SRC 20 | 21 | * 22 | 23 | Why doesn't this code compile? 24 | 25 | #+BEGIN_SRC rust 26 | #[derive(Debug)] 27 | struct Wrapper<'buf> { 28 | inner: &'buf mut Vec, 29 | } 30 | 31 | impl<'buf> Wrapper<'buf> { 32 | fn new() -> Self { 33 | Self { inner: vec![] } 34 | } 35 | } 36 | 37 | fn main() { 38 | let mut v = vec![]; 39 | let w = Wrapper::new(); 40 | 41 | w.inner.push(1); 42 | w.inner.push(3); 43 | w.inner.push(5); 44 | 45 | println!("Wrapper: {:?}", w); 46 | } 47 | #+END_SRC 48 | 49 | What else is interesting about this example? 50 | 51 | * Multiple lifetimes 1 52 | 53 | Why is the lifetime ~'b~ redundant? 54 | 55 | #+BEGIN_SRC rust 56 | fn compare<'a, 'b>(a: &'a String, b: &'b String) { 57 | if a.len() > b.len() { 58 | println!("{:?} is longer", a); 59 | } else { 60 | println!("Hard to say really..."); 61 | } 62 | } 63 | 64 | fn main() { 65 | let a = String::from("abc"); 66 | let b = String::from("de"); 67 | compare(&a, &b); 68 | } 69 | #+END_SRC 70 | 71 | * Multiple lifetimes 2 72 | 73 | Why are multiple lifetimes needed here? :) 74 | 75 | #+BEGIN_SRC rust 76 | struct Pair<'a> { 77 | x: &'a i32, 78 | y: &'a i32, 79 | } 80 | 81 | fn main() { 82 | let x = 3; let r; 83 | { 84 | let y = 4; 85 | let pair = Pair { x: &x, y: &y }; 86 | r = pair.x; 87 | } 88 | 89 | println!("{}", r); 90 | } 91 | #+END_SRC 92 | 93 | * Box lifetimes 94 | 95 | #+BEGIN_SRC rust 96 | // .... ???? 97 | #+END_SRC 98 | 99 | * [[file:README.org][Back to index]] 100 | -------------------------------------------------------------------------------- /courses/02-ownership/40-lifetimes.org: -------------------------------------------------------------------------------- 1 | #+Title: Lifetimes 2 | #+SETUPFILE: ../reveal.setup 3 | 4 | * So how long do borrows last?? 5 | 6 | * 7 | 8 | #+BEGIN_SRC rust 9 | #[derive(Debug)] 10 | struct NumRef { 11 | x: &i64, 12 | y: &i64 13 | } 14 | 15 | fn new_numref(x: i64, y: i64) -> NumRef { 16 | NumRef { x: &x, y: &y } 17 | } 18 | 19 | fn main() { 20 | let num = new_numref(5, 9); 21 | println!("Numref: {:?}", num); 22 | } 23 | #+END_SRC 24 | 25 | * Explicit lifetime syntax 26 | 27 | + ~<'_>~ is an anonymous lifetime 28 | + ~<'meep>~ is a named lifetime called "meep" 29 | + ~<'static>~ is a special/ reserved lifetime 30 | 31 | * 32 | 33 | Does this work? If not, what is the problem? 34 | 35 | #+BEGIN_SRC rust 36 | #[derive(Debug)] 37 | struct NumRef<'num> { 38 | x: &'num i64, 39 | y: &'num i64 40 | } 41 | 42 | fn new_numref<'num>(x: i64, y: i64) -> NumRef<'num> { 43 | NumRef { x: &x, y: &y } 44 | } 45 | 46 | fn main() { 47 | let num = new_numref(5, 9); 48 | println!("Numref: {:?}", num); 49 | } 50 | #+END_SRC 51 | 52 | * _Lifetimes are an indicator of when your memory model is incomplete!_ 53 | 54 | * 55 | 56 | file:imgs/numref0.png 57 | 58 | * 59 | 60 | file:imgs/numref1.png 61 | 62 | * 63 | 64 | file:imgs/numref2.png 65 | 66 | * 67 | 68 | file:imgs/numref3.png 69 | 70 | * 71 | 72 | #+BEGIN_SRC rust 73 | #[derive(Debug)] 74 | struct NumRef<'num> { 75 | x: &'num i64, 76 | y: &'num i64 77 | } 78 | 79 | fn new_numref<'num>(x: &'num i64, y: &'num i64) -> NumRef<'num> { 80 | NumRef { x, y } 81 | } 82 | 83 | fn main() { 84 | let num = new_numref(&5, &9); 85 | println!("Numref: {:?}", num); 86 | } 87 | #+END_SRC 88 | 89 | * Lifetimes are a way to annotate your code for the compiler 90 | 91 | \\ 92 | 93 | You are describing your code, not forcing things to work. 94 | 95 | * Lifetimes are types! 96 | 97 | * Lifetime bounds 98 | 99 | #+BEGIN_SRC rust 100 | #[derive(Debug)] 101 | struct Wrapper<'inner, T: 'inner> { 102 | t: &'inner T 103 | } 104 | 105 | fn main() { 106 | let w = { 107 | let t = String::from("t"); 108 | Wrapper { t: &t } 109 | }; 110 | 111 | println!("Wrapper: {:?}", w); 112 | } 113 | #+END_SRC 114 | 115 | * Lifetimes are memory analysis tautologies 116 | 117 | * Speaking of ~'static~ 118 | 119 | + Special lifetime that is longer than any other 120 | + Not necessarily forever! 121 | + Some examples of ~'static~ 122 | + Data contained in the binary data section 123 | + Heap allocated types (as long as no other lifetime bounds exist) 124 | + Global variables 125 | 126 | * Example Box lifetime 127 | 128 | + By default the lifetime bound on values contained in ~Box~ is ~'static~ 129 | + This can be changed 130 | 131 | #+BEGIN_SRC rust 132 | fn to_iter<'list>(v: &'list Vec) -> Box + 'list> { 133 | Box::new(v.iter()) 134 | } 135 | 136 | fn main() { 137 | let v = vec![1, 2, 3, 4]; 138 | for i in to_iter(&v) { 139 | println!("{}", i); 140 | } 141 | } 142 | #+END_SRC 143 | 144 | * [[file:README.org][Back to index]] 145 | -------------------------------------------------------------------------------- /courses/02-ownership/45-borrowing-exercises.org: -------------------------------------------------------------------------------- 1 | #+Title: Borrowing Exercises 2 | #+SETUPFILE: ../reveal.setup 3 | 4 | * Nested borrows 5 | 6 | So far examples have been simple. Let's try nesting some borrows 7 | -------------------------------------------------------------------------------- /courses/02-ownership/50-threading.org: -------------------------------------------------------------------------------- 1 | #+Title: Threads and borrowing 2 | #+SETUPFILE: ../reveal.setup 3 | 4 | * 5 | 6 | So far we have only used a single thread! 7 | 8 | * So how long _do_ borrows last? 9 | 10 | * 11 | 12 | #+BEGIN_SRC rust 13 | use std::thread; 14 | 15 | fn main() { 16 | let s = String::from("Hello World!"); 17 | 18 | let t = thread::spawn(|| { 19 | let s2 = &s; 20 | println!("s2: {}", s2); 21 | }); 22 | 23 | println!("s: {}", s); 24 | t.join().unwrap(); 25 | } 26 | #+END_SRC 27 | 28 | * What are threads? 29 | 30 | + Pieces of your program that run in parallel 31 | + Can be "alive" for different amount of time 32 | + Importantly: threads are a runtime feature! 33 | + ~rustc~ has no way of knowing about how long a thread will be 34 | alive for! 35 | 36 | * _Thus: borrows can not be shared between threads!_ 37 | 38 | * Why? 39 | 40 | * ~Send~ & ~Sync~ 41 | 42 | + Rust comes with two "marker" traits to _express thread-safety_ 43 | + Signal to the compiler that a type is thread-safe in a specific 44 | way 45 | + Require ~unsafe~ code to implement 46 | + Form the foundation of thread-safety in Rust 47 | 48 | * ~Send~ 49 | 50 | + Express that an object can safely be shared between thread 51 | boundaries. 52 | + A type implements ~Send~ if all of its children implement ~Send~. 53 | 54 | \\ 55 | 56 | + Rc :: is a non-thread-safe reference counter, and thus does 57 | not implement ~Send~ 58 | + Arc :: is a thread-safe reference counter, and thus does 59 | implement ~Send~ 60 | 61 | * ~Sync~ 62 | 63 | + Express that an object can be safely referenced from multiple 64 | threads 65 | + A type ~T~ implements ~Sync~ if (and only if!) ~&T~ is ~Send~ 66 | (meaning it can be shared between threads without undefined 67 | behaviour) 68 | 69 | \\ 70 | 71 | + ~i64~ :: is ~Sync~ because ~&T~ can be sent between threads 72 | + ~Cell~ :: not ~Sync~ because it provides interior-mutability 73 | via immutable references 74 | 75 | * Wait! 76 | 77 | Then why couldn't we share ~&i64~ across a thread-bound earlier?? 78 | 79 | * ~'static~ lifetime 80 | 81 | #+BEGIN_SRC rust norun 82 | pub fn spawn(f: F) -> JoinHandle where 83 | F: FnOnce() -> T, 84 | F: Send + 'static, 85 | T: Send + 'static, 86 | { 87 | // ... 88 | } 89 | #+END_SRC 90 | 91 | + Spawning a thread requires a ~'static~ lifetime bound, in addition to ~Send~ 92 | + Just because something is ~Send~ it doesn't mean it can be _moved 93 | into a thread function_ 94 | 95 | * The ~Arc~ of types 96 | 97 | + Provides a mechanism to fulfill the ~'static~ lifetime 98 | requirements of thread-spawning 99 | + Provides a thread-safe atomic reference counter 100 | + ~.clone()~ increments the reference counter 101 | + When reference counter reaches ~0~, the memory is cleaned up 102 | 103 | * 104 | 105 | #+BEGIN_SRC rust 106 | use std::{sync::Arc, thread}; 107 | 108 | fn main() { 109 | let s = Arc::new(String::from("Hello World!")); 110 | 111 | let s2 = Arc::clone(&s); 112 | thread::spawn(move || { 113 | println!("s2: {}", s2); 114 | }); 115 | 116 | println!("s: {}", s); 117 | } 118 | #+END_SRC 119 | 120 | * How to ~Sync~? 121 | 122 | Use wrapper types to provide thread-safe reference access. 123 | 124 | + ~Mutex~ :: exclusive locking mechanism wrapper 125 | + ~RwLock~ :: granual read/write locking wrapper 126 | 127 | * 128 | 129 | #+BEGIN_SRC rust 130 | use std::{thread, sync::{Arc, Mutex}}; 131 | 132 | fn main() { 133 | let data = Arc::new(Mutex::new(vec![])); 134 | 135 | for n in 0..10 { 136 | let data2 = Arc::clone(&data); 137 | thread::spawn(move || { 138 | data2.lock().unwrap().push(n * 2); 139 | }).join(); 140 | } 141 | 142 | let v = data.lock().unwrap(); 143 | for n in v.iter() { 144 | println!("{}", n); 145 | } 146 | } 147 | #+END_SRC 148 | 149 | * [[file:README.org][Back to index]] 150 | -------------------------------------------------------------------------------- /courses/02-ownership/51-race-conditians.org: -------------------------------------------------------------------------------- 1 | #+Title: Thoughts on race conditions 2 | #+SETUPFILE: ../reveal.setup 3 | 4 | * Rust claims to "prevent data races" 5 | 6 | \\ 7 | 8 | But... what _is_ a data race? 9 | 10 | * I have a talk about this a while ago 11 | 12 | \\ 13 | 14 | #+attr_html: :width 400px 15 | [[file:imgs/peertube.png]] 16 | 17 | https://diode.zone/w/ni4Phe9SqtB91jDDqftVuP 18 | 19 | * Consider this slide deck the TLDR 20 | 21 | * Let's increment a number in memory 22 | 23 | * 24 | 25 | file:imgs/races/cpu0.png 26 | 27 | * 28 | file:imgs/races/cpu1.png 29 | 30 | * 31 | file:imgs/races/cpu2.png 32 | 33 | * 34 | file:imgs/races/cpu3.png 35 | 36 | * 37 | file:imgs/races/cpu4.png 38 | 39 | * What about multiple threads? 40 | 41 | 42 | * 43 | file:imgs/races/cpu0.png 44 | 45 | * 46 | file:imgs/races/race_condition1.png 47 | 48 | * 49 | file:imgs/races/race_condition2.png 50 | 51 | * 52 | file:imgs/races/race_condition3.png 53 | 54 | * 55 | file:imgs/races/race_condition4.png 56 | 57 | * 58 | 59 | A race condition is an _invariant of parallelism_ 60 | 61 | * [[file:README.org][Back to index]] 62 | -------------------------------------------------------------------------------- /courses/02-ownership/55-thread-exercises.org: -------------------------------------------------------------------------------- 1 | #+Title: Borrowing and threads 2 | #+SETUPFILE: ../reveal.setup 3 | 4 | * Let's write a multi-threaded message mailbox 5 | 6 | + We know all the tools by now 7 | + Use ~Arc~ to share references between threads 8 | + Use ~Mutex~ to gain exclusive (and thread-safe!) mutable access 9 | + Probably no real need for lifetime syntax 10 | 11 | * 12 | 13 | This pattern is a very simple multi-producer, single-consumer 14 | channel! 15 | 16 | #+BEGIN_SRC dot :file imgs/gen/mailbox-simple.png :cmdline -Kdot -Tpng 17 | digraph { 18 | node [shape=box, fontsize=24, margin="0.25,0.25"] 19 | rankdir = "LR" 20 | 21 | Mailbox [color=darkgreen, shape=box] 22 | Generator1 [label="Generator", color=teal, shape=box] 23 | Generator2 [label="Generator", color=teal, shape=box] 24 | Consumer [color=orange, shape=box] 25 | Generator1 -> Mailbox; 26 | Generator2 -> Mailbox; 27 | Mailbox -> Consumer -> Mailbox; 28 | } 29 | #+END_SRC 30 | 31 | #+RESULTS: 32 | [[file:imgs/gen/mailbox-simple.png]] 33 | 34 | * 35 | 36 | Code at https://teach.spacekookie.de/rust/ownership/examples/mailbox! 37 | 38 | #+BEGIN_SRC rust 39 | use std::collections::VecDeque; 40 | use std::sync::{Arc, Mutex}; 41 | 42 | #[derive(Clone)] 43 | struct Mailbox { 44 | inner: Arc>>, 45 | } 46 | 47 | impl Mailbox { 48 | /// Create a new mailbox object 49 | pub fn new() -> Self { 50 | todo!() 51 | } 52 | 53 | /// Queue a new message to the back 54 | pub fn queue(&self, s: String) { 55 | todo!() 56 | } 57 | 58 | /// Pop the first message off the front 59 | pub fn pop(&self) -> Option { 60 | todo!() 61 | } 62 | } 63 | #+END_SRC 64 | 65 | * Using the mailbox 66 | 67 | #+BEGIN_SRC rust 68 | fn main() { 69 | let mb = Mailbox::new(); 70 | 71 | { // Use this thread to generate message (2x) 72 | let mb = mb.clone(); 73 | thread::spawn(|| { todo!() }); 74 | } 75 | 76 | while let Some(msg) = mb.pop() { 77 | println!("Message received: {}", msg); 78 | } 79 | 80 | println!("No more messages..."); 81 | } 82 | #+END_SRC 83 | 84 | * Using the mailbox 85 | 86 | #+BEGIN_SRC rust 87 | pub struct Generator { 88 | mb: crate::Mailbox, 89 | } 90 | 91 | impl Generator { 92 | pub fn start(mb: Mailbox) { 93 | Self { mb }.spawn(); 94 | } 95 | 96 | fn spawn(self) { 97 | thread::spawn(move || { 98 | todo!() 99 | }); 100 | } 101 | } 102 | #+END_SRC 103 | 104 | * Off you go :) 105 | 106 | * There's a race condition in that code 107 | 108 | Can you see where? 109 | 110 | #+BEGIN_SRC rust 111 | fn main() { 112 | let mb = Mailbox::new(); 113 | 114 | // Start 2 generator threads 115 | Generator::start(mb.clone()); 116 | Generator::start(mb.clone()); 117 | 118 | while let Some(msg) = mb.pop() { 119 | println!("Message received: {}", msg); 120 | } 121 | } 122 | #+END_SRC 123 | 124 | ** How to fix it 125 | 126 | + Terrible way: ~std::time::sleep(...)~ 🙈 127 | + Less terrible way: don't stop the loop when no messages exist 128 | + Creates a busy loop! 129 | + Program can never exit 130 | + Best way: keep track of active generators 131 | + Only shut down the consumer when all generators are gone 132 | + We can do this via Channels, or a simple ~AtomicBool~ 133 | 134 | ** Generator shutdown signal 135 | 136 | Use an ~AtomicBool~ inside an ~Arc~ to signal run state to the 137 | consumer. 138 | 139 | #+BEGIN_SRC rust 140 | use crate::Mailbox; 141 | use std::sync::{Arc, atomic::AtomicBool}; 142 | 143 | pub struct Generator { 144 | mb: Mailbox, 145 | run: Arc, 146 | } 147 | 148 | impl Generator { 149 | pub fn start(mb: Mailbox) -> Arc { todo!() } 150 | } 151 | #+END_SRC 152 | 153 | 154 | ** Generator shutdown signal 155 | 156 | #+BEGIN_SRC rust 157 | let g1 = Generator::start(mb.clone()); 158 | let g2 = Generator::start(mb.clone()); 159 | 160 | while g1.load(Ordering::Relaxed) | g2.load(Ordering::Relaxed) { 161 | match mb.pop() { 162 | Some(msg) => println!("Message received: '{}'", msg), 163 | None => {}, // still a busy-loop :( 164 | } 165 | } 166 | #+END_SRC 167 | 168 | ** Fixing busy loops 169 | 170 | + Terrible way: ~std::time::sleep(...)~ 171 | + Less terrible way: ~std::thread::yield_now~ 172 | + Great way: waking mechanism (but this gets too complicated for 173 | today!) 174 | + Spoiler: this is how async runtimes work 175 | 176 | * [[file:README.org][Back to index]] 177 | -------------------------------------------------------------------------------- /courses/02-ownership/60-patterns-arc-mutex.org: -------------------------------------------------------------------------------- 1 | #+Title: Concurrency Patterns 2 | #+Subtitle: ~Arc~ and ~Mutex~ 3 | #+SETUPFILE: ../reveal.setup 4 | 5 | * In the previous exercise you used Arc and Mutex 6 | 7 | * ~Arc~ 8 | 9 | + Provides a way for multiple references to point to the same 10 | location in memory 11 | + Uses atomics to synchronise threads 12 | 13 | * 14 | 15 | file:imgs/arc0.png 16 | 17 | * 18 | 19 | file:imgs/arc1.png 20 | 21 | * 22 | 23 | file:imgs/arc2.png 24 | 25 | * 26 | 27 | file:imgs/arc3.png 28 | 29 | * 30 | 31 | file:imgs/arc4.png 32 | 33 | * ~Mutex~ 34 | 35 | + Provides interior mutability 36 | + Only one access to ~lock()~ allowed at a time 37 | + Implements ~Sync~ for any ~T~ 38 | + Thus provides thread-safety for types that don't have any of 39 | their own 40 | 41 | * Quiz 42 | 43 | Which of these two types makes sense, which does not? 44 | 45 | + ~Arc>~ :: A list of Strings, wrapped in a Mutex, 46 | wrapped in an Arc 47 | + ~Mutex>>~ :: A list of Strings, wrapped in an Arc, 48 | wrapped in a Mutex 49 | 50 | * 51 | 52 | ~Arc~ removes concurrent mutability. ~Mutex~ provides it. 53 | 54 | * These guarantees apply even when not immediately nested! 55 | 56 | * 57 | 58 | #+BEGIN_SRC rust 59 | use std::collections::VecDeque; 60 | use std::sync{Arc, Mutex}; 61 | 62 | pub struct Mailbox { 63 | inner: Mutex>, 64 | } 65 | 66 | impl Mailbox { 67 | pub fn new() -> Arc { 68 | Arc::new(Self { 69 | inner: Mutex::new(VecDeque::new()) 70 | }) 71 | } 72 | } 73 | #+END_SRC 74 | 75 | * [[file:README.org][Back to index]] 76 | -------------------------------------------------------------------------------- /courses/02-ownership/65-patterns-channels.org: -------------------------------------------------------------------------------- 1 | #+Title: Concurrency Patterns 2 | #+Subtitle: Channels 3 | #+SETUPFILE: ../reveal.setup 4 | 5 | * 6 | 7 | /“Do not communicate by sharing memory; instead, share memory by communicating.”/ 8 | 9 | -- someone, somewhere, sometime 10 | 11 | * 12 | 13 | A lot of complicated ownership models become redundant when you use 14 | channels to pass messages between threads 15 | 16 | * ~stdlib~ provides some simple channels 17 | 18 | + These are not very good 19 | + Personally I recommend ~crossbeam_channel~ or ~flume~ 20 | + Channels of course exist on the heap somewhere 21 | + But access control is much simpler 22 | 23 | * 24 | 25 | file:imgs/channel0.png 26 | 27 | * 28 | 29 | file:imgs/channel1.png 30 | 31 | * 32 | 33 | file:imgs/channel2.png 34 | 35 | * 36 | 37 | file:imgs/channel3.png 38 | 39 | * 40 | 41 | file:imgs/channel2.png 42 | 43 | * 44 | 45 | file:imgs/channel4.png 46 | 47 | * Channels in ~std~ 48 | 49 | + mpsc: multi-producer, single-consumer 50 | 51 | #+BEGIN_SRC rust 52 | use std::sync::mpsc; 53 | 54 | fn main() { 55 | let (tx, rx) = mpsc::channel(); 56 | 57 | tx.send(String::from("E C H O ECHO echo ᵉᶜʰᵒ")); 58 | 59 | let msg = rx.recv().unwrap(); 60 | println!("The cave goes {}", msg); 61 | } 62 | #+END_SRC 63 | 64 | * Channel senders can be shared across threads! 65 | 66 | + Easily connect data structures together 67 | + ~rx.recv()~ will block until _all_ senders have gone away 68 | 69 | #+BEGIN_SRC rust 70 | use std::{sync::mpsc, thread}; 71 | 72 | fn main() { 73 | let (tx, rx) = mpsc::channel(); 74 | thread::spawn(move || { 75 | tx.send(String::from("Hello from another thread!")); 76 | }); 77 | 78 | let msg = rx.recv().unwrap(); 79 | println!("Message: {}", msg); 80 | } 81 | #+END_SRC 82 | 83 | * [[file:README.org][Back to index]] 84 | -------------------------------------------------------------------------------- /courses/02-ownership/70-message-cache.org: -------------------------------------------------------------------------------- 1 | #+Title: Network message cache 2 | #+Subtitle: It's basically redis 3 | #+SETUPFILE: ../reveal.setup 4 | 5 | * Let's put all this together! 6 | 7 | * Overview 8 | 9 | + Accept TCP connections on one thread 10 | + Send message payload to parsing threads 11 | + Poll for updates on a consumer thread 12 | 13 | * Accept TCP connections 14 | 15 | + ~std::net~ has you covered 16 | 17 | #+BEGIN_SRC rust 18 | let listener = TcpListener::bind("127.0.0.1:6000")?; 19 | for stream in listener.incoming() { 20 | handle_connection(&mut stream?, &mut pool); 21 | } 22 | #+END_SRC 23 | 24 | * Payloads 25 | 26 | + Let's parse some JSON 27 | + Use ~serde~ and ~serde_json~ crates for this 28 | + Specify some type ~Payload~ that acts as a data model 29 | 30 | #+BEGIN_SRC rust 31 | #[derive(Serialize, Deserialize)] 32 | struct Payload { 33 | msg: String, 34 | sev: Option, 35 | } 36 | #+END_SRC 37 | 38 | * Extra credit: work scheduler 39 | 40 | + Wouldn't it be cool if we sent work to a thread for parsing? 41 | + This has real advantages: a long parse time won't block new 42 | connections! 43 | 44 | #+BEGIN_SRC rust 45 | pub struct WorkPool { 46 | ring: VecDeque>>, 47 | } 48 | 49 | impl WorkPool { 50 | /// TODO: also provide a handle to mailbox 51 | pub fn new(num: u8) -> Self { 52 | todo!() 53 | } 54 | 55 | /// TODO: implement round-robin strategy 56 | pub fn queue(&mut self, buf: Vec) {} 57 | } 58 | #+END_SRC 59 | 60 | * Alternatively 61 | 62 | + Parse the incoming payload 63 | + Then queue it into the mailbox 64 | 65 | #+BEGIN_SRC rust 66 | match serde_json::from_slice::(&vec) { 67 | Ok(msg) => { /* TODO: queue payload in mailbox */ } 68 | Err(e) => { 69 | eprintln!("Received invalid payload: '{}'!", e); 70 | } 71 | } 72 | #+END_SRC 73 | 74 | * Lastly 75 | 76 | + Spawn a thread that polls the mailbox for updates in set intervals 77 | 78 | #+BEGIN_SRC rust 79 | pub struct MessageConsumer { 80 | dur: Duration, 81 | // TODO: add reference to your mailbox here 82 | } 83 | 84 | impl MessageConsumer { 85 | // ... 86 | 87 | fn run(self) { 88 | thread::spawn(move || { 89 | // TODO: Get _all_ new messages as a chunk 90 | 91 | // Then sleep for a while 92 | sleep(self.dur.clone()).unwrap(); 93 | }) 94 | } 95 | } 96 | #+END_SRC 97 | 98 | * More details in the repository! 99 | 100 | https://git.irde.st/kookiespace/teaching-rust/-/tree/main/dd-ownership/exercises/network-mailbox 101 | 102 | 103 | * [[file:README.org][Back to index]] 104 | -------------------------------------------------------------------------------- /courses/02-ownership/README.org: -------------------------------------------------------------------------------- 1 | #+Title: Rust ownership deep-dive 2 | #+Author: Katharina Fey 3 | #+SETUPFILE: ../html.setup 4 | 5 | * Introduction 6 | 7 | This is an _beginner level_ course, targeted at developers who have 8 | _little to no Rust experience_. Some _general programming_ 9 | experience can be helpful, but is not required. 10 | 11 | * Course outline 12 | 13 | + [[file:10-memory-management.org][Memory management basics]] 14 | + [[file:20-why-ownership.org][Why ownership?]] 15 | + [[file:21-thought-on-raii.org][A thought on RAII]] 16 | + [[file:25-ownership-quiz.org][Exercise: seizing ownership]] 17 | + [[file:30-borrowing.org][Borrowing]] 18 | + [[file:40-lifetimes.org][Lifetimes]] 19 | + [[file:35-borrowing-exercises.org][Exercise: lend me your T]] 20 | + [[file:50-threading.org][Threading & Ownership]] 21 | + [[file:51-race-conditians.org][Thoughts on race conditions]] 22 | + [[file:55-thread-exercises.org][Exercise: concurrently borrowing stuff]] 23 | + [[file:60-patterns-arc-mutex.org][Concurrency patterns: Arc & Mutex]] 24 | + [[file:65-patterns-channels.org][Concurrency patterns: Channels]] 25 | + [[file:70-message-cache.org][Exercise: Network message cache]] 26 | 27 | \\ 28 | 29 | + [[https://git.irde.st/kookiespace/teaching-rust/-/tree/main/dd-ownership/exercises][Exercise overview]] 30 | 31 | * About these slides 32 | 33 | You can find a copy of these slides at 34 | https://teach.spacekookie.de/rust/ownership! If you find any 35 | mistakes, please feel free to send a merge-request on [[https://git.irde.st/kookiespace/teaching-rust/][Gitlab]]! 36 | 37 | * How to build 38 | 39 | These slide-decks are built with emacs and [[https://orgmode.org][org-mode]]. The following 40 | function will export the full course into an HTML slide tree. 41 | 42 | #+INCLUDE: "../ci/export-course.el" src emacs-lisp 43 | 44 | * License 45 | 46 | This course, as well as any associated media assets is licensed 47 | under Creative Commons CC-BY-SA 4.0. All associated code examples 48 | are licensed under the GNU General Public License Version 3.0 (or 49 | later). 50 | 51 | See the [[../licenses][licenses]] directory for complete copies of the applicable 52 | license texts. 53 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/00_playground/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "playground" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/00_playground/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "playground" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/00_playground/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/01_seizing_ownership/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "seizing-ownership" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/01_seizing_ownership/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "seizing-ownership" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/01_seizing_ownership/README.org: -------------------------------------------------------------------------------- 1 | #+Title: Seizing ownership exercises 2 | #+Author: Katharina Fey 3 | #+SETUPFILE: ../../../html.setup 4 | 5 | [[file:~/Projects/talks/teaching-rust/README.org][Back to course overview]] 6 | 7 | * Quizzes 8 | 9 | Make the code compile 10 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/01_seizing_ownership/src/bin/01_scopes.rs: -------------------------------------------------------------------------------- 1 | // What needs to change about this code to make it compile 2 | fn main() { 3 | { 4 | let x = 42; 5 | println!("x: {}", x); 6 | } 7 | 8 | println!("x: {}", x); 9 | } 10 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/01_seizing_ownership/src/bin/02_drop.rs: -------------------------------------------------------------------------------- 1 | // In what order are the println statements printed? 2 | 3 | #[derive(Debug)] 4 | struct DropMe; 5 | 6 | impl Drop for DropMe { 7 | fn drop(&mut self) { 8 | println!("Dropping 'DropMe'"); 9 | } 10 | } 11 | 12 | fn main() { 13 | println!("Start"); 14 | { 15 | let x = DropMe; 16 | println!("x: {:?}", x); 17 | } 18 | 19 | println!("End"); 20 | } 21 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/01_seizing_ownership/src/bin/03_move.rs: -------------------------------------------------------------------------------- 1 | // Why does this code not compile? 2 | fn main() { 3 | let a = vec![1, 2, 3]; 4 | let b = a; 5 | 6 | println!("vec: {:?}", a); 7 | } 8 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/01_seizing_ownership/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Fake library 2 | 3 | pub fn test() -> &'static str { 4 | "test!" 5 | } 6 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/02_mailbox/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "mailbox" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/02_mailbox/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mailbox" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/02_mailbox/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | use std::sync::{Arc, Mutex}; 3 | use std::thread; 4 | 5 | /// Implement this mailbox which can queue and pop messages from its 6 | /// internal state without requiring external mutable access. 7 | /// 8 | /// Instead use the Mutex provided within. 9 | #[derive(Clone)] 10 | struct Mailbox { 11 | inner: Arc>>, 12 | } 13 | 14 | impl Mailbox { 15 | /// Create a new mailbox object 16 | pub fn new() -> Self { 17 | Self { 18 | inner: Arc::new(Mutex::new(VecDeque::new())), 19 | } 20 | } 21 | 22 | /// Queue a new message to the back 23 | pub fn queue(&self, s: String) { 24 | self.inner.lock().unwrap().push_back(s); 25 | } 26 | 27 | /// Pop the first message off the front 28 | pub fn pop(&self) -> Option { 29 | self.inner.lock().unwrap().pop_front() 30 | } 31 | } 32 | 33 | /// Optionally you can use this "Generator" abstraction to spawn 34 | /// threads. Some code is missing 35 | pub struct Generator { 36 | mb: crate::Mailbox, 37 | } 38 | 39 | impl Generator { 40 | fn start(mb: Mailbox) { 41 | Self { mb }.spawn(); 42 | } 43 | 44 | fn spawn(self) { 45 | thread::spawn(move || { 46 | let mb = self.mb; 47 | for i in 0..20 { 48 | mb.queue(format!("String #{}", i)); 49 | } 50 | }); 51 | } 52 | } 53 | 54 | fn main() { 55 | let mb = Mailbox::new(); 56 | 57 | Generator::start(mb.clone()); 58 | Generator::start(mb.clone()); 59 | 60 | std::thread::sleep_ms(100); 61 | 62 | while let Some(msg) = mb.pop() { 63 | println!("Message received: {}", msg); 64 | } 65 | 66 | println!("No more messages..."); 67 | } 68 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/03_network_mailbox/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "itoa" 7 | version = "0.4.8" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" 10 | 11 | [[package]] 12 | name = "network-mailbox" 13 | version = "0.1.0" 14 | dependencies = [ 15 | "serde", 16 | "serde_json", 17 | ] 18 | 19 | [[package]] 20 | name = "proc-macro2" 21 | version = "1.0.32" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" 24 | dependencies = [ 25 | "unicode-xid", 26 | ] 27 | 28 | [[package]] 29 | name = "quote" 30 | version = "1.0.10" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" 33 | dependencies = [ 34 | "proc-macro2", 35 | ] 36 | 37 | [[package]] 38 | name = "ryu" 39 | version = "1.0.6" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568" 42 | 43 | [[package]] 44 | name = "serde" 45 | version = "1.0.130" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" 48 | dependencies = [ 49 | "serde_derive", 50 | ] 51 | 52 | [[package]] 53 | name = "serde_derive" 54 | version = "1.0.130" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" 57 | dependencies = [ 58 | "proc-macro2", 59 | "quote", 60 | "syn", 61 | ] 62 | 63 | [[package]] 64 | name = "serde_json" 65 | version = "1.0.72" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" 68 | dependencies = [ 69 | "itoa", 70 | "ryu", 71 | "serde", 72 | ] 73 | 74 | [[package]] 75 | name = "syn" 76 | version = "1.0.82" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" 79 | dependencies = [ 80 | "proc-macro2", 81 | "quote", 82 | "unicode-xid", 83 | ] 84 | 85 | [[package]] 86 | name = "unicode-xid" 87 | version = "0.2.2" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 90 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/03_network_mailbox/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "network-mailbox" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | serde_json = "1.0" 8 | serde = { version = "1.0", features = ["derive"] } -------------------------------------------------------------------------------- /courses/02-ownership/exercises/03_network_mailbox/src/consumer.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | use std::time::{sleep, Duration}; 3 | 4 | pub struct MessageConsumer { 5 | dur: Duration, 6 | // TODO: add reference to your mailbox here 7 | } 8 | 9 | impl MessageConsumer { 10 | pub fn start(dur: Duration) { 11 | Self { dur }.run(); 12 | } 13 | 14 | fn run(self) { 15 | thread::spawn(move || { 16 | // Get _all_ new messages as a chunk 17 | // while let Some(msg) = self.mailbox.pop() { 18 | // println!("Message received: {}", msg); 19 | // } 20 | 21 | // Then sleep for a while 22 | sleep(self.dur.clone()).unwrap(); 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/03_network_mailbox/src/main.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::io::{self, Read}; 3 | use std::net::{TcpListener, TcpStream}; 4 | 5 | mod pool; 6 | use pool::WorkPool; 7 | 8 | mod consumer; 9 | use consumer::MessageConsumer; 10 | 11 | // Copy your previous solution over! 12 | // mod mailbox; 13 | 14 | /// A payload that this application expects 15 | #[derive(Serialize, Deserialize)] 16 | struct Payload { 17 | msg: String, 18 | sev: Option, 19 | } 20 | 21 | fn handle_connection(s: &mut TcpStream, pool: &mut WorkPool) -> io::Result<()> { 22 | let mut buf = vec![]; 23 | s.read_to_end(&mut buf)?; 24 | pool.queue(buf); 25 | Ok(()) 26 | } 27 | 28 | fn main() -> io::Result<()> { 29 | let mut pool = WorkPool::new(4); 30 | let listener = TcpListener::bind("127.0.0.1:6000")?; 31 | 32 | // For every incoming connection we first read its message inputs, 33 | // then forward them to a parser 34 | for stream in listener.incoming() { 35 | handle_connection(&mut stream?, &mut pool); 36 | } 37 | 38 | Ok(()) 39 | } 40 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/03_network_mailbox/src/pool.rs: -------------------------------------------------------------------------------- 1 | use crate::Payload; 2 | use std::collections::VecDeque; 3 | use std::sync::mpsc::{channel, Receiver, Sender}; 4 | use std::thread; 5 | 6 | /// A round-robin worker pool 7 | pub struct WorkPool { 8 | ring: VecDeque>>, 9 | } 10 | 11 | impl WorkPool { 12 | // TODO: provide the WorkPool with a reference to your mailbox 13 | pub fn new(num: u8) -> Self { 14 | // basically this is just a loop via the 15 | // Iterator API. You could just as easily have written "for _ in 16 | // (0..num)" but that would have been too simple :) 17 | let ring = (0..num) 18 | .map(|_| { 19 | let (tx, rx) = channel(); 20 | thread::spawn(move || Worker::new(rx).run()); 21 | tx 22 | }) 23 | .collect(); 24 | 25 | Self { ring } 26 | } 27 | 28 | pub fn queue(&mut self, buf: Vec) { 29 | // TODO: implement round-robin work queuing 30 | } 31 | } 32 | 33 | struct Worker { 34 | rx: Receiver>, 35 | // TODO: add a reference to your mailbox here 36 | } 37 | 38 | impl Worker { 39 | fn new(rx: Receiver>) -> Self { 40 | Self { rx } 41 | } 42 | 43 | fn run(self) { 44 | while let Ok(vec) = self.rx.recv() { 45 | match serde_json::from_slice::(&vec) { 46 | Ok(msg) => { /* TODO: queue payload in mailbox */ } 47 | Err(e) => { 48 | eprintln!("Received invalid payload: '{}'!", e); 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /courses/02-ownership/exercises/README.org: -------------------------------------------------------------------------------- 1 | #+Title: Ownership exercises 2 | #+Author: Katharina Fey 3 | #+SETUPFILE: ../../html.setup 4 | 5 | This directory contains various exercises to practise concepts taught 6 | in this course. To compile them you require ~rustc~ and ~cargo~ 7 | installed on your system. 8 | 9 | 10 | -------------------------------------------------------------------------------- /courses/02-ownership/imgs/arc0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/arc0.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/arc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/arc1.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/arc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/arc2.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/arc3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/arc3.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/arc4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/arc4.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/channel0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/channel0.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/channel1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/channel1.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/channel2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/channel2.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/channel3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/channel3.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/channel4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/channel4.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/cpu0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/cpu0.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/cpu1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/cpu1.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/cpu2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/cpu2.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gc0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gc0.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gc1.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gc2.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gc3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gc3.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gc4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gc4.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gc5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gc5.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gc6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gc6.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gen/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gen/.keep -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gen/borrow1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gen/borrow1.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gen/borrow2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gen/borrow2.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gen/clone-move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gen/clone-move.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gen/mailbox-simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gen/mailbox-simple.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gen/move-owner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gen/move-owner.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/gen/raii.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/gen/raii.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/ned_flanders.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/ned_flanders.jpg -------------------------------------------------------------------------------- /courses/02-ownership/imgs/numref0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/numref0.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/numref1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/numref1.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/numref2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/numref2.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/numref3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/numref3.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/peertube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/peertube.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/races/cpu0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/races/cpu0.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/races/cpu1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/races/cpu1.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/races/cpu2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/races/cpu2.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/races/cpu3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/races/cpu3.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/races/cpu4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/races/cpu4.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/races/race_condition1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/races/race_condition1.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/races/race_condition2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/races/race_condition2.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/races/race_condition3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/races/race_condition3.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/races/race_condition4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/races/race_condition4.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/rust.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/rust.gif -------------------------------------------------------------------------------- /courses/02-ownership/imgs/uaf0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/uaf0.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/uaf1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/uaf1.png -------------------------------------------------------------------------------- /courses/02-ownership/imgs/uaf2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacekookie/learning-rust/6a4fca6f6b742837bf3c08439ed420a4d9024ddb/courses/02-ownership/imgs/uaf2.png -------------------------------------------------------------------------------- /html.setup: -------------------------------------------------------------------------------- 1 | # -*- mode: org; -*- 2 | 3 | This file contains common HTML export settings for org-mode. 4 | 5 | ** Disable table of contents and header numbering 6 | 7 | #+Options: toc:nil num:nil html_postamble:nil 8 | 9 | ** Include google font 10 | 11 | #+HTML_HEAD: 12 | 13 | ** Use custom CSS 14 | 15 | It's important to note that the link is relative _from_ the 16 | sub-directory (where the overviews are stored). 17 | 18 | #+HTML_HEAD: 19 | #+HTML_HEAD: 20 | -------------------------------------------------------------------------------- /into.org: -------------------------------------------------------------------------------- 1 | #+Title: Who am I? 2 | #+Subtitle: Hope you care :') 3 | #+SETUPFILE: reveal.setup 4 | 5 | * How to reach me 6 | 7 | + Name: *Katharina Fey* 8 | + Location: *Berlin* 9 | + E-mail: *kookie@spacekookie.de* 10 | + Matrix: *@spacekookie:fairydust.space* 11 | + IRC: *spacekookie* (on libera.chat and hackint) 12 | + Twitter: *@spacekookie* 13 | 14 | * The work I do 15 | 16 | + Distributed systems software researcher 17 | + Currently working at *Ockam* (https://ockam.io) 18 | + Also working on EU funded reseanch project *Irdest* (https://irde.st) 19 | 20 | * Some links to my work 21 | 22 | + Website: *https://spacekookie.de* 23 | + Gitea: *https://dev.spacekookie.de/kookie/nomicon* 24 | + Gitlab: *https://git.irde.st/spacekookie* 25 | + GitHub: *https://github.com/spacekookie* 26 | 27 | * I teach workshops! 28 | 29 | (oh really??) 30 | 31 | + Rust workshops since 2018 32 | + Nix workshops since 2020 33 | + Does your company need trainings? Contact me for details! 34 | 35 | * Finally 36 | 37 | You can find this teaching material at 38 | https://learn.spacekookie.de/rust. 39 | 40 | * [[file:README.org][Back to overview]] 41 | -------------------------------------------------------------------------------- /overview.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Exo', sans-serif; 3 | font-size: 1.5rem; 4 | display: flex; 5 | justify-content: center; 6 | } 7 | 8 | h1 { 9 | font-size: 2.5rem; 10 | padding-bottom: 1rem; 11 | text-decoration: underline; 12 | } 13 | 14 | h2 { 15 | font-size: 2rem; 16 | padding-top: 1rem; 17 | } 18 | 19 | #content { 20 | max-width: 900px; 21 | align: center; 22 | } 23 | 24 | a { color: #377ffc; } 25 | 26 | a:visited { color: #377ffc; } 27 | 28 | a:hover { 29 | color: #000000; 30 | background-color: #377ffc; 31 | } 32 | 33 | #postamble { 34 | display: none; 35 | } 36 | -------------------------------------------------------------------------------- /reveal.setup: -------------------------------------------------------------------------------- 1 | # -*- mode: org; -*- 2 | 3 | This file contains common reveal.js export settings for org-mode. 4 | 5 | ** Set some general options 6 | 7 | I don't want a TOC or bullet numbering by default. We have the 8 | dedicated HTML pages as an index 9 | 10 | #+Options: toc:nil num:nil 11 | 12 | ** Get reveal.js from a CDN 13 | 14 | #+REVEAL_ROOT: https://cdn.jsdelivr.net/npm/reveal.js 15 | 16 | *** TODO Figure out why the local copy of reveal.js doesn't work! 17 | 18 | For some reason we get an error (invalid type something something) 19 | when using a local copy of reveal.js. Investigate why! 20 | 21 | ** General reveal.js options 22 | 23 | Now come options that are very specific to reveal.js and the way it works. 24 | 25 | #+REVEAL_INIT_OPTIONS: transition:'none', width:1200, height:800, margin: 0.1, minScale:0.2, maxScale:2.5, progress:false, hash:true 26 | #+REVEAL_THEME: simple 27 | 28 | We also customise the title slide to have a link back to the ../README.org! 29 | 30 | #+REVEAL_TITLE_SLIDE:

%t

%s


Back to index 31 | 32 | #+REVEAL_PLUGINS: highlight 33 | 34 | ** Setup extra javascript 35 | 36 | #+REVEAL_SLIDE_HEADER: 37 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | import { 2 | userPackages = (pkgs: [ 3 | pkgs.graphviz 4 | ]); 5 | } 6 | --------------------------------------------------------------------------------