├── .editorconfig ├── .github └── workflows │ └── pages.yaml ├── .gitignore ├── .node-version ├── .vscode └── settings.json ├── BUILD.adoc ├── CHANGELOG.md ├── Gemfile ├── Gemfile.lock ├── README.adoc ├── Rakefile.rb ├── assignments ├── _preliminary │ ├── async_parser_codealong │ │ ├── .cargo │ │ │ └── config │ │ ├── .gitignore │ │ ├── .vscode │ │ │ └── launch.json │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── solution │ │ │ ├── lib.rs │ │ │ └── main.rs │ │ └── src │ │ │ ├── lib.rs │ │ │ └── main.rs │ └── calculator │ │ ├── calc-ffi │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── build.rs │ │ ├── build_all.sh │ │ ├── demo.c │ │ ├── solution │ │ │ ├── cbindgen.toml │ │ │ └── lib.rs │ │ ├── src │ │ │ └── lib.rs │ │ └── trainer-notes.md │ │ └── calc │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── src │ │ ├── bin │ │ │ ├── cli.rs │ │ │ └── tcp.rs │ │ ├── eval.rs │ │ ├── lib.rs │ │ └── parse.rs │ │ └── tests │ │ ├── demo_test.rs │ │ └── demo_test2.rs ├── _templates │ └── concurrency │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── actix.adoc ├── actix │ └── chat-websockets │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── Readme.md │ │ └── src │ │ ├── chat_server.rs │ │ └── main.rs ├── async-channels.adoc ├── async-chat-template │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── async-mailbox.adoc ├── binding-to-leveldb.adoc ├── calc.adoc ├── connected-mailbox.adoc ├── durable-file.adoc ├── files-match-result-assignment.adoc ├── files-match-result-assignment │ ├── solution │ │ ├── Step2.rs │ │ ├── Step3.rs │ │ ├── Step4.rs │ │ ├── Step5.rs │ │ └── Step6.rs │ └── template │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ ├── data │ │ └── content.txt │ │ └── main.rs ├── fizzbuzz-command-line.adoc ├── fizzbuzz.adoc ├── green_yellow.adoc ├── leveldb-mdbook │ ├── .gitignore │ ├── README.md │ ├── book.toml │ ├── netlify.toml │ ├── solution │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── src │ │ ├── SUMMARY.md │ │ ├── ffi-1-exercise.md │ │ ├── ffi-1-solution.md │ │ ├── ffi-2-exercise.md │ │ ├── ffi-2-solution.md │ │ ├── ffi-3-exercise.md │ │ ├── ffi-3-solution.md │ │ ├── ffi-full-solution.md │ │ └── ffi_illustration.jpg ├── library-client.adoc ├── multithreaded-mailbox.adoc ├── narcissistic-number-check.adoc ├── redis-protobuf.adoc ├── redis-protobuf │ ├── config.proto │ └── phonebook.proto ├── redis.adoc ├── redisish.adoc ├── rustlatin.adoc ├── semver │ └── parse_file │ │ ├── solution │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── releases.txt │ │ └── src │ │ │ └── main.rs │ │ └── template │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── releases.txt │ │ └── src │ │ └── main.rs ├── semver_from_file.adoc ├── semver_server.adoc ├── serde-lifetimes.adoc ├── shapes.adoc ├── simple-chat.adoc ├── solutions │ ├── actix-semver │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── client.py │ │ └── src │ │ │ └── main.rs │ ├── actix │ │ └── chat-websockets │ │ │ ├── .gitignore │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ ├── Readme.md │ │ │ └── src │ │ │ ├── chat_server.rs │ │ │ └── main.rs │ ├── async-std-mailbox-connection-limit │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── mailbox │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── main.rs │ │ └── redisish │ │ │ ├── .gitignore │ │ │ ├── Cargo.toml │ │ │ ├── src │ │ │ └── lib.rs │ │ │ └── tests │ │ │ └── test.rs │ ├── async-std-mailbox-tracing │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── mailbox │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── main.rs │ │ └── redisish │ │ │ ├── .gitignore │ │ │ ├── Cargo.toml │ │ │ ├── src │ │ │ └── lib.rs │ │ │ └── tests │ │ │ └── test.rs │ ├── async-std-mailbox │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── mailbox │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── main.rs │ │ └── redisish │ │ │ ├── .gitignore │ │ │ ├── Cargo.toml │ │ │ ├── src │ │ │ └── lib.rs │ │ │ └── tests │ │ │ └── test.rs │ ├── calc │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── lib.rs │ │ │ └── solution_skeleton.rs │ ├── connected-mailbox │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── mailbox │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── main.rs │ │ └── redisish │ │ │ ├── Cargo.toml │ │ │ ├── src │ │ │ └── lib.rs │ │ │ └── tests │ │ │ └── test.rs │ ├── durable_file │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── fill_in_the_blanks │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ └── bin │ │ │ └── closures.rs │ ├── fizzbuzz │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── green-yellow │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── redis-protobuf │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── build.rs │ │ └── src │ │ │ ├── config.proto │ │ │ ├── main.rs │ │ │ ├── phone.rs │ │ │ └── phonebook.proto │ ├── redis │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── lib.rs │ │ │ └── main.rs │ ├── redisish │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── lib.rs │ │ └── tests │ │ │ └── test.rs │ ├── semver-client-server │ │ ├── semver-api │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── semver-client-async │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── main.rs │ │ ├── semver-client │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── main.rs │ │ ├── semver-server-actix │ │ │ ├── .gitignore │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ ├── README.md │ │ │ ├── src │ │ │ │ ├── client.rs │ │ │ │ ├── shared-server.rs │ │ │ │ └── simple-server.rs │ │ │ ├── static │ │ │ │ ├── actixLogo.png │ │ │ │ └── favicon.ico │ │ │ └── websocket-client.py │ │ ├── semver-server-async-channels │ │ │ ├── .gitignore │ │ │ ├── .vscode │ │ │ │ └── settings.json │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── main.rs │ │ ├── semver-server-async │ │ │ ├── .gitignore │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── main.rs │ │ ├── semver-server-threaded │ │ │ ├── .gitignore │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── main.rs │ │ └── semver-server │ │ │ ├── .gitignore │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── main.rs │ ├── semver │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── shapes │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── tcp-client │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── tcp-echo-server │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── terrarium │ │ ├── accepting_json.rs │ │ ├── http_request.rs │ │ └── message_storage.rs │ ├── threaded-mailbox │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── mailbox │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── main.rs │ │ └── redisish │ │ │ ├── .gitignore │ │ │ ├── Cargo.toml │ │ │ ├── src │ │ │ └── lib.rs │ │ │ └── tests │ │ │ └── test.rs │ └── tracing-future │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── examples │ │ └── main.rs │ │ └── src │ │ └── lib.rs ├── tcp-client.adoc ├── tcp-echo-server.adoc ├── terrarium-http.adoc ├── terrarium-kv.adoc └── terrarium-serde.adoc ├── build.sh ├── examples ├── ffi_use_c_in_rust │ ├── Cargo.lock │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── cool_library.c │ │ └── main.rs └── ffi_use_rust_in_c │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Makefile │ ├── example.c │ ├── example.h │ └── src │ └── lib.rs ├── fill_in_the_blanks ├── closures.adoc └── enums_match.adoc ├── package-lock.json ├── package.json ├── presentations ├── advanced-generics-bounds │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ ├── 7.rs │ ├── 8.rs │ ├── 9.rs │ └── slides.adoc ├── async-await-intro │ ├── async_main_1.rs │ ├── async_main_2.rs │ ├── async_stream_read.rs │ ├── async_trait.rs │ ├── block_on.rs │ ├── example │ │ └── async-await-intro │ │ │ ├── .gitignore │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── main.rs │ ├── fetch_into_string.rs │ ├── is_website_up.rs │ ├── join.rs │ ├── lazy.rs │ ├── select.rs │ ├── slides.adoc │ └── task_spawn.rs ├── async-await-laziness-in-detail │ ├── futures-vs-promises.js │ ├── futures_vs_promises.rs │ └── slides.adoc ├── async-await │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ └── slides.adoc ├── async-building-blocks │ └── slides.adoc ├── async-component-interaction │ └── slides.adoc ├── async-growth-handling │ └── slides.adoc ├── async-implementation │ └── slides.adoc ├── async-tokio-intro │ └── slides.adoc ├── basic-types │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ └── slides.adoc ├── cargo │ ├── 1.toml │ ├── 2.toml │ ├── 3.toml │ ├── 4.toml │ ├── 5.toml │ ├── 6.rs │ ├── 7.toml │ ├── 8.toml │ └── slides.adoc ├── check-for-errors.sh ├── closures │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ └── slides.adoc ├── compound-types │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ ├── 7.rs │ ├── 8.rs │ ├── 9.rs │ └── slides.adoc ├── control-flow │ ├── 1.rs │ ├── 10.rs │ ├── 11.rs │ ├── 11a.rs │ ├── 11b.rs │ ├── 12.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ ├── 7.rs │ ├── 7_5.rs │ ├── 8.rs │ ├── 9.rs │ └── slides.adoc ├── crates │ ├── 0.rs │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.toml │ └── slides.adoc ├── debugging-rust │ └── slides.adoc ├── deref-coersions │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ └── slides.adoc ├── design-patterns │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ ├── 7.rs │ └── slides.adoc ├── docinfo-footer.html ├── documentation │ ├── 1.bash │ ├── 2.rs │ └── slides.adoc ├── drop-panic-abort │ ├── 1.rs │ ├── 2.rs │ └── slides.adoc ├── dynamic-and-static-libs │ ├── 1.rs │ ├── 2.c │ ├── 3.toml │ ├── 4.c │ ├── 5.sh │ ├── 6.sh │ ├── 7.rs │ └── slides.adoc ├── dynamic-dispatch │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ └── slides.adoc ├── error-handling │ ├── 8 │ ├── 1.diagram │ ├── 1.rs │ ├── 2.output │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.output │ ├── 6.rs │ ├── 7.rs │ ├── 8.rs │ └── slides.adoc ├── ffi │ ├── callbacks.rs │ ├── cool_library.c │ ├── cool_library.h │ ├── cool_library.rs │ ├── load_bindings.rs │ ├── naming.rs │ ├── opaque.rs │ ├── reg.rs │ ├── rustlib-Cargo.toml │ ├── rustlib-wrapper.h │ ├── rustlib-wrapper.rs │ ├── rustlib.rs │ ├── slides.adoc │ └── using_cool_library.rs ├── functions │ ├── 1.rs │ ├── 10.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ ├── 7.rs │ ├── 8.rs │ ├── 9.rs │ └── slides.adoc ├── futures │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ └── slides.adoc ├── generics-basics │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ └── slides.adoc ├── imports-modules-and-visibility │ ├── 1.rs │ ├── 10.rs │ ├── 11.rs │ ├── 12.rs │ ├── 13.rs │ ├── 14.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4-5.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ ├── 7.rs │ ├── 8.rs │ ├── 9-2.rs │ ├── 9.rs │ └── slides.adoc ├── index.adoc ├── inner-mutability │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ └── slides.adoc ├── installation │ ├── 1.sh │ ├── 3.sh │ ├── 4.rs │ ├── 5a.sh │ ├── 5b.sh │ ├── 6.sh │ ├── 7.sh │ ├── 8.sh │ └── slides.adoc ├── iterators-again │ ├── 1.rs │ └── slides.adoc ├── iterators │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ └── slides.adoc ├── libcore-and-libstd │ └── slides.adoc ├── lifetimes │ ├── 1.rs │ ├── 10.rs │ ├── 11.rs │ ├── 12.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ ├── 7.rs │ ├── 8.rs │ ├── 9.rs │ └── slides.adoc ├── little-helpers │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ └── slides.adoc ├── macros │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ └── slides.adoc ├── match │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ ├── 7.rs │ ├── 8.rs │ └── slides.adoc ├── mutability │ ├── 1.rs │ ├── 2.rs │ └── slides.adoc ├── overview │ ├── 1.rs │ └── slides.adoc ├── ownership-borrowing-in-brief │ ├── 1.diagram │ ├── 1.rs │ ├── 2.rs │ ├── 3.error │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ ├── 7.rs │ ├── 8.rs │ ├── 9.rs │ └── slides.adoc ├── proptest │ ├── 1.rs │ ├── 2.txt │ ├── 3.txt │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ └── slides.adoc ├── redis-protobuf │ └── slides.adoc ├── redis │ └── slides.adoc ├── send-and-sync │ ├── 1.rs │ ├── 2.rs │ ├── 3.output │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ └── slides.adoc ├── serde │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ └── slides.adoc ├── slides.css ├── smart-pointers │ ├── 1.rs │ ├── 2.rs │ └── slides.adoc ├── stack-and-heap │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ └── slides.adoc ├── standard-types │ ├── 1.rs │ ├── 10.rs │ ├── 11.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ ├── 7.rs │ ├── 8.rs │ ├── 9.rs │ └── slides.adoc ├── std-lib-tour │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ └── slides.adoc ├── strings │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ ├── 7.rs │ ├── 8.rs │ └── slides.adoc ├── testing │ ├── 1.rs │ ├── 2.bash │ ├── 3.rs │ ├── 4.bash │ ├── 5.bash │ ├── 6.rs │ ├── 7.bash │ └── slides.adoc ├── traits │ ├── 1.rs │ ├── 2.rs │ ├── 3.rs │ ├── 4.rs │ ├── 5.rs │ ├── 6.rs │ ├── 7.rs │ └── slides.adoc ├── unsafe │ ├── 1.rs │ ├── 2.rs │ ├── slides.adoc │ └── vscode-settings.json ├── wasm │ ├── 1.wat │ ├── 2.bash │ ├── 3.bash │ ├── 4.bash │ └── slides.adoc └── working-with-nightly │ ├── 1.bash │ ├── 2.rs │ ├── 3.rs │ └── slides.adoc ├── rake └── semver-codealong ├── .gitignore ├── Cargo.lock ├── Cargo.toml └── src ├── bin ├── 01 hello Rust.rs ├── 02 println, numbers.rs ├── 03 return, if, call.rs ├── 04 structs.rs ├── 05 structs II - inference.rs ├── 06 structs III - constructors.rs ├── 07 structs IV - derive Debug.rs ├── 08 structs V - impl block.rs ├── 08a_enum_and_match.rs ├── 09 mutability.rs ├── 10 ownership.rs ├── 11 ownership II.rs ├── 12 references.rs ├── 13 borrowing.rs ├── 14 tuples, collections.rs ├── 15 iterators.rs ├── 16 strings.rs ├── 17 From String.rs ├── exercise_01_parse.rs ├── xx default, phantom.rs ├── xx maths, traits.rs ├── xx_documentation.rs ├── xx_enum_and_match.rs ├── xx_impl_display.rs ├── xx_lifetimes.rs ├── xx_modules.rs └── xx_test.rs └── main.rs /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = space 9 | 10 | [*.{rs, toml}] 11 | indent_size = 4 12 | 13 | [*.rb, Gemfile] 14 | indent_size = 2 15 | 16 | [*.{js, json, .css}] 17 | indent_size = 2 18 | 19 | [*.{yaml, yml}] 20 | indent_size = 2 21 | 22 | [*.sh] 23 | indent_style = tab 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | node_modules/ 3 | target/ 4 | *.html 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 16 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "emeraldwalk.runonsave": { 3 | "commands": [ 4 | { 5 | "match": ".*", 6 | "cmd": "./rake" 7 | } 8 | ] 9 | }, 10 | "cSpell.words": [ 11 | "Asynchrony" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'asciidoctor-diagram', '= 2.2.3' 4 | gem 'asciidoctor-revealjs', '= 5.0.0.rc1' 5 | gem 'rake' 6 | gem 'rouge' 7 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | asciidoctor (2.0.17) 5 | asciidoctor-diagram (2.2.3) 6 | asciidoctor (>= 1.5.7, < 3.x) 7 | asciidoctor-diagram-ditaamini (~> 1.0) 8 | asciidoctor-diagram-plantuml (~> 1.2021) 9 | rexml 10 | asciidoctor-diagram-ditaamini (1.0.3) 11 | asciidoctor-diagram-plantuml (1.2022.5) 12 | asciidoctor-revealjs (5.0.0.rc1) 13 | asciidoctor (>= 2.0.0, < 3.0.0) 14 | rake (13.0.1) 15 | rexml (3.2.5) 16 | rouge (3.17.0) 17 | 18 | PLATFORMS 19 | ruby 20 | 21 | DEPENDENCIES 22 | asciidoctor-diagram (= 2.2.3) 23 | asciidoctor-revealjs (= 5.0.0.rc1) 24 | rake 25 | rouge 26 | 27 | BUNDLED WITH 28 | 2.3.15 29 | -------------------------------------------------------------------------------- /assignments/_preliminary/async_parser_codealong/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["--cfg", "tokio_unstable"] 3 | -------------------------------------------------------------------------------- /assignments/_preliminary/async_parser_codealong/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /assignments/_preliminary/async_parser_codealong/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "lldb", 9 | "request": "launch", 10 | "name": "Debug", 11 | "program": "${workspaceFolder}/", 12 | "args": [], 13 | "cwd": "${workspaceFolder}" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /assignments/_preliminary/async_parser_codealong/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "async_parser_codealong" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | futures = "0.3.17" 10 | async-stream = "0.3.2" 11 | rand = "0.8.4" 12 | tokio = { version = "1.12.0", features = ["full"] } 13 | # console-subscriber = { path = "../console/console-subscriber"} -------------------------------------------------------------------------------- /assignments/_preliminary/async_parser_codealong/src/main.rs: -------------------------------------------------------------------------------- 1 | use async_parser_codealong::{random_packet, raw_packets_stream, Handler}; 2 | use futures::{future::select_all, pin_mut, StreamExt}; 3 | use rand::thread_rng; 4 | use tokio::task::JoinHandle; 5 | 6 | #[tokio::main] 7 | async fn main() { 8 | // console_subscriber::init(); 9 | 10 | let bad_task = async_blocking_task(); 11 | //let good_task = good_task(); 12 | 13 | let _ = select_all([bad_task /* , good_task */]).await; 14 | } 15 | 16 | // previously: 17 | async fn do_stream() { 18 | let mut handler = Handler::new("STREAM".to_string()); 19 | let packet_data = raw_packets_stream(); 20 | pin_mut!(packet_data); 21 | while let Some(raw_packet) = packet_data.next().await { 22 | handler.handle_raw_packet(raw_packet); 23 | } 24 | } 25 | 26 | fn async_blocking_task() -> JoinHandle<()> { 27 | tokio::spawn(async move { 28 | let mut handler = Handler::new("BLOCK".to_string()); 29 | loop { 30 | let raw_packet = random_packet(thread_rng()); 31 | handler.handle_raw_packet(raw_packet); 32 | } 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /assignments/_preliminary/calculator/calc-ffi/.gitignore: -------------------------------------------------------------------------------- 1 | demo 2 | calc_ffi.h 3 | /cbindgen.toml 4 | -------------------------------------------------------------------------------- /assignments/_preliminary/calculator/calc-ffi/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 = "calc" 7 | version = "0.1.0" 8 | 9 | [[package]] 10 | name = "calc-ffi" 11 | version = "0.1.0" 12 | dependencies = [ 13 | "calc", 14 | "xshell", 15 | ] 16 | 17 | [[package]] 18 | name = "xshell" 19 | version = "0.1.17" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "eaad2035244c56da05573d4d7fda5f903c60a5f35b9110e157a14a1df45a9f14" 22 | dependencies = [ 23 | "xshell-macros", 24 | ] 25 | 26 | [[package]] 27 | name = "xshell-macros" 28 | version = "0.1.17" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "4916a4a3cad759e499a3620523bf9545cc162d7a06163727dde97ce9aaa4cf39" 31 | -------------------------------------------------------------------------------- /assignments/_preliminary/calculator/calc-ffi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "calc-ffi" 3 | version = "0.1.0" 4 | authors = ["James Munns "] 5 | edition = "2018" 6 | 7 | [lib] 8 | # crate-type = ["cdylib"] - Make a dynamic library, 9 | # e.g. a `.so` or `.dll` 10 | # crate-type = ["staticlib"] - Make a static library, 11 | # e.g. a `.a` or `.lib` file 12 | crate-type = ["staticlib"] 13 | 14 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 15 | 16 | [dependencies.calc] 17 | path = "../calc" 18 | 19 | [build-dependencies] 20 | xshell = "0.1.12" 21 | -------------------------------------------------------------------------------- /assignments/_preliminary/calculator/calc-ffi/build.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | use xshell::{cmd, write_file}; 4 | 5 | fn main() -> Result<(), Box> { 6 | let header = cmd!("cbindgen --parse-dependencies --lang c").read()?; 7 | write_file("calc_ffi.h", header).unwrap(); 8 | println!("cargo:rerun-if-changed=src/lib.rs"); 9 | Ok(()) 10 | } 11 | -------------------------------------------------------------------------------- /assignments/_preliminary/calculator/calc-ffi/build_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | 4 | # build native library 5 | cargo build 6 | 7 | # build executable that links to library 8 | gcc \ 9 | demo.c \ 10 | -L./target/debug \ 11 | -lcalc_ffi \ 12 | -lpthread \ 13 | -ldl \ 14 | -lm \ 15 | -o demo -------------------------------------------------------------------------------- /assignments/_preliminary/calculator/calc-ffi/trainer-notes.md: -------------------------------------------------------------------------------- 1 | Unsafe, FFI, and Bindings 2 | 3 | * Safe binding, both manually and automatically 4 | * Binding strategies 5 | * The role of unsafe 6 | * The scope of unsafe 7 | * Working with raw pointers and helping pointers 8 | * Do’s and Don’ts of unsafe Rust 9 | * Introduction into support APIs, like non-null pointers 10 | * Potential undefined behaviour arising from the use of unsafe 11 | * Checking unsafe Rust for safety 12 | * Using Rusts guarantees for security gains 13 | 14 | James: 15 | 16 | What I want to expose: 17 | * single function 18 | * takes a C string of "input" 19 | * returns (if successful) the output 20 | 21 | parse_and_eval 22 | 23 | Arguments? 24 | * const char 25 | Return type? 26 | * integer 27 | 28 | returns 0 if success, returns nonzero if failure 29 | on success, output is updated with the result 30 | 31 | int parse_and_eval(char*, int64_t* output); 32 | -------------------------------------------------------------------------------- /assignments/_preliminary/calculator/calc/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /assignments/_preliminary/calculator/calc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "calc" 3 | version = "0.1.0" 4 | authors = ["James Munns "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /assignments/_preliminary/calculator/calc/tests/demo_test.rs: -------------------------------------------------------------------------------- 1 | use calc::{eval::eval, parse::parse}; 2 | 3 | #[test] 4 | fn round_trip_add() { 5 | let text = "3 2 +"; 6 | let expected = 5i64; 7 | let parsed = parse(text).unwrap(); 8 | let evald = eval(&parsed).unwrap(); 9 | assert_eq!(expected, evald); 10 | } 11 | -------------------------------------------------------------------------------- /assignments/_preliminary/calculator/calc/tests/demo_test2.rs: -------------------------------------------------------------------------------- 1 | use calc::{eval::eval, parse::parse}; 2 | 3 | #[test] 4 | fn round_trip_sqr() { 5 | let text = "3 sqr"; 6 | let expected = 9i64; 7 | let parsed = parse(text).unwrap(); 8 | let evald = eval(&parsed).unwrap(); 9 | assert_eq!(expected, evald); 10 | } 11 | -------------------------------------------------------------------------------- /assignments/_templates/concurrency/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 = "concurrency" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /assignments/_templates/concurrency/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "concurrency" 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 | -------------------------------------------------------------------------------- /assignments/_templates/concurrency/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | sync::{Arc, Mutex}, 3 | thread, 4 | }; 5 | 6 | fn main() { 7 | solution(); 8 | } 9 | 10 | fn problem() { 11 | let mut numbers = vec![0]; 12 | 13 | for i in 0..10 { 14 | // compiler suggests move || but that doesn't work (first thread consumes) 15 | // creating one &mut numbers - one for each thread - also doesn't work (multiple &mut at the same time) 16 | thread::spawn(|| { 17 | numbers.push(i); 18 | }); 19 | } 20 | } 21 | 22 | fn solution() { 23 | let numbers = Arc::new(Mutex::new(vec![])); // try using Rc instead of Arc - what happens? 24 | 25 | for i in 0..10 { 26 | let nr = numbers.clone(); 27 | thread::spawn(move || { 28 | // same as (*nr).lock().unwrap() - why? 29 | let mut guard = nr.lock().unwrap(); 30 | 31 | let numbers = &mut *guard; 32 | numbers.push(i); 33 | }); 34 | } 35 | // bonus task: these numbers are in order - 0..9 -, so we're only concurrent, but not parallel! 36 | // how to fix this? 37 | dbg!(numbers); 38 | } 39 | -------------------------------------------------------------------------------- /assignments/actix/chat-websockets/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /assignments/actix/chat-websockets/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "actix-example" 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 | [[bin]] 9 | name = "server" 10 | path = "src/main.rs" 11 | 12 | [dependencies] 13 | actix = "0.10" 14 | actix-web = "3.3.2" 15 | actix-web-actors = "3" 16 | actix-files = "0.3" 17 | actix-codec = "0.3" 18 | 19 | rand = "0.8.4" 20 | bytes = "0.5.3" 21 | byteorder = "1.2" 22 | futures = "0.3" 23 | log = "0.4" 24 | env_logger = "0.9" 25 | serde = { version = "1.0", features = ["derive"] } 26 | serde_json = "1.0" 27 | -------------------------------------------------------------------------------- /assignments/actix/chat-websockets/Readme.md: -------------------------------------------------------------------------------- 1 | # Websocket Chat Server 2 | 3 | This is an example of a HTTP chat server using [`actix-web`](https://github.com/actix/actix-web) and `websockets` with [`actix-web-actors`](https://github.com/actix/actix-web/tree/master/actix-web-actors). 4 | 5 | The assignment can be found here: https://ferrous-systems.github.io/teaching-material/assignments/actix.html 6 | 7 | To start the chat server execute `cargo run`. To connect to the chat server via client, open your browser at http://localhost:8080/. 8 | 9 | To enable logs set the `RUST_LOG` environment variable. 10 | 11 | ```shell 12 | RUST_LOG=info cargo run 13 | ``` 14 | -------------------------------------------------------------------------------- /assignments/async-channels.adoc: -------------------------------------------------------------------------------- 1 | = Exercise: async channels 2 | :source-language: rust 3 | 4 | Let's refactor our async application a little bit. Instead 5 | of using a Mutex to moderate our queue, let's instead use 6 | a single task and use a channel for synchronisation. 7 | 8 | == Task 9 | 10 | 1. Pick a MPMC channel module (recommended tokio, async-std or async-channel) 11 | 2. Implement a function `mailbox` that loops over all incoming messages and 12 | ** On "PUBLISH", just stores data 13 | ** On "RETRIEVE", sends the message back to the task requesting the data 14 | 3. Make sure this function gets started correctly 15 | 16 | NOTE: you will need to implement 2 channels, one towards your mailbox and one backchannel. 17 | 18 | == Getting started 19 | 20 | Use this template: 21 | 22 | [source,rust] 23 | ---- 24 | async fn mailbox_function(storage: VecDeque, recv: Receiver) { 25 | // ... 26 | } 27 | ---- 28 | -------------------------------------------------------------------------------- /assignments/async-chat-template/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "async-chat-template" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | async-std = { version = "1", features = ["unstable"] } 11 | -------------------------------------------------------------------------------- /assignments/files-match-result-assignment/solution/Step2.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | 3 | fn main() { 4 | 5 | let open_result = File::open("src/data/content.txt"); 6 | 7 | match open_result { 8 | Ok(file) => println!("File opened!"), 9 | Err(e) => println!("Problem opening the file: {:?}", e), 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /assignments/files-match-result-assignment/solution/Step3.rs: -------------------------------------------------------------------------------- 1 | use std::io::Read; 2 | use std::fs::File; 3 | 4 | fn main() { 5 | 6 | let open_result = File::open("src/data/content.txt"); 7 | 8 | let mut file = match open_result { 9 | Ok(file) => file, 10 | Err(e) => panic!("Problem opening the file: {:?}", e), 11 | }; 12 | 13 | let mut content_string = String::new(); 14 | file.read_to_string(&mut content_string).unwrap(); 15 | println!("{}", content_string); 16 | } 17 | -------------------------------------------------------------------------------- /assignments/files-match-result-assignment/solution/Step4.rs: -------------------------------------------------------------------------------- 1 | use std::io::{BufReader, BufRead}; 2 | use std::fs::File; 3 | 4 | fn main() { 5 | 6 | let open_result = File::open("src/data/content.txt"); 7 | 8 | let file = match open_result { 9 | Ok(file) => file, 10 | Err(e) => panic!("Problem opening the file: {:?}", e), 11 | }; 12 | 13 | let buf_reader = BufReader::new(file); 14 | 15 | let mut number = 0; 16 | 17 | for _line in buf_reader.lines() { 18 | number += 1; 19 | } 20 | 21 | println!("{}", number); 22 | } 23 | -------------------------------------------------------------------------------- /assignments/files-match-result-assignment/solution/Step5.rs: -------------------------------------------------------------------------------- 1 | use std::io::{BufReader, BufRead}; 2 | use std::fs::File; 3 | 4 | fn main() { 5 | 6 | let open_result = File::open("src/data/content.txt"); 7 | 8 | let file = match open_result { 9 | Ok(file) => file, 10 | Err(e) => panic!("Problem opening the file: {:?}", e), 11 | }; 12 | 13 | let buf_reader = BufReader::new(file); 14 | 15 | for line in buf_reader.lines() { 16 | 17 | let line = match line { 18 | Ok(content) => content, 19 | Err(e) => panic!("Problem reading the line: {:?}", e), 20 | }; 21 | 22 | println!("{}", line); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /assignments/files-match-result-assignment/solution/Step6.rs: -------------------------------------------------------------------------------- 1 | use url::Url; 2 | use std::io::{BufReader, BufRead}; 3 | use std::fs::File; 4 | 5 | fn parse_line(line: String) -> Option { 6 | match Url::parse(&line) { 7 | Ok(u) => Some(u), 8 | Err(_e) => None 9 | } 10 | } 11 | 12 | fn main() { 13 | let open_result = File::open("src/lib/content.txt"); 14 | 15 | let file = match open_result { 16 | Ok(file) => file, 17 | Err(e) => panic!("Problem opening the file: {:?}", e), 18 | }; 19 | 20 | let buf_reader = BufReader::new(file); 21 | 22 | for line in buf_reader.lines() { 23 | 24 | let line = match line { 25 | Ok(content) => content, 26 | Err(e) => panic!("Problem reading the file: {:?}", e), 27 | }; 28 | 29 | let url = parse_line(line); 30 | 31 | match url { 32 | Some(line) => println!("{}", line), 33 | None => continue 34 | } 35 | } 36 | } 37 | 38 | #[test] 39 | fn correct_url() { 40 | assert!(parse_line(String::from("https://example.com")).is_some()) 41 | } 42 | 43 | #[test] 44 | fn no_url() { 45 | assert!(parse_line(String::from("abcdf")).is_none()) 46 | } 47 | -------------------------------------------------------------------------------- /assignments/files-match-result-assignment/template/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 = "option-result-assignment" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /assignments/files-match-result-assignment/template/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "option-result-assignment" 3 | version = "0.1.0" 4 | authors = ["Mirabellensaft "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /assignments/files-match-result-assignment/template/src/data/content.txt: -------------------------------------------------------------------------------- 1 | This file contains a title and list of URLs and empty lines 2 | https://docs.rs/lyon_core/0.8.0/lyon_core/ 3 | 4 | https://docs.rs/gdnative-core/0.7.0/gdnative_core/ 5 | 6 | https://docs.rs/little-endian/1.0.0/little_endian/ 7 | https://docs.rs/grin_keychain/3.0.0/grin_keychain/ 8 | -------------------------------------------------------------------------------- /assignments/files-match-result-assignment/template/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | 3 | fn main() { 4 | 5 | let f = File::open("src/data/content.txt"); 6 | 7 | match f { 8 | // substitute this placeholder for the two possible patterns from the result type 9 | // PATTERN => EXPRESSION, 10 | // PATTERN => EXPRESSION, 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /assignments/leveldb-mdbook/.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | -------------------------------------------------------------------------------- /assignments/leveldb-mdbook/README.md: -------------------------------------------------------------------------------- 1 | # `leveldb-exercise` 2 | 3 | Temporary mdbook for the leveldb exercise. Will probably be transplanted into an mdbook collection of different exercises. 4 | 5 | This is currently not hosted anywhere so please run `mdbook serve` to view the book locally. 6 | -------------------------------------------------------------------------------- /assignments/leveldb-mdbook/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Ferrous Systems"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "FFI exercise" 7 | -------------------------------------------------------------------------------- /assignments/leveldb-mdbook/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "curl -L https://github.com/rust-lang/mdBook/releases/download/v0.4.7/mdbook-v0.4.7-x86_64-unknown-linux-gnu.tar.gz | tar xvz && ./mdbook build" 3 | publish = "book/" 4 | 5 | [[headers]] 6 | for = "/*" 7 | 8 | -------------------------------------------------------------------------------- /assignments/leveldb-mdbook/solution/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "leveldb-rs" 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 | leveldb-sys = "2.0" 10 | libc = "0.2" 11 | tempdir = "0.3" 12 | -------------------------------------------------------------------------------- /assignments/leveldb-mdbook/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Introduction, exercise: open & close](./ffi-1-exercise.md) 4 | - [Solution](./ffi-1-solution.md) 5 | - [Exercise: get & put](./ffi-2-exercise.md) 6 | - [Solution](./ffi-2-solution.md) 7 | - [Exercise: Iterators](./ffi-3-exercise.md) 8 | - [Solution](./ffi-3-solution.md) 9 | - [Full solution](./ffi-full-solution.md) 10 | -------------------------------------------------------------------------------- /assignments/leveldb-mdbook/src/ffi_illustration.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferrous-systems/teaching-material/81806ce816ac550fb27667542d0bdb0ab5c59bc5/assignments/leveldb-mdbook/src/ffi_illustration.jpg -------------------------------------------------------------------------------- /assignments/library-client.adoc: -------------------------------------------------------------------------------- 1 | An FFI based chat client 2 | ------------------------ 3 | 4 | Using a Rust library, implement an FFI based chat client 5 | 6 | In this exercise, you will learn: 7 | * Learn how to write dynamit libraries 8 | * How to ensure proper data and state hand 9 | 10 | 1. Clone the template 11 | ~~~~~~~~~~~~~~~~~~~~~ 12 | 13 | [source,rust] 14 | ---- 15 | $ git clone git@github.com:skade/chat-client.git 16 | ---- 17 | 18 | 2. Reading material 19 | ~~~~~~~~~~~~~~~~~~~ 20 | 21 | http://jakegoulding.com/rust-ffi-omnibus/[The FFI Omnibus] 22 | -------------------------------------------------------------------------------- /assignments/redis-protobuf.adoc: -------------------------------------------------------------------------------- 1 | = Exercise: Redis client with protocol buffers 2 | :icons: font 3 | :source-highlighter: rouge 4 | 5 | In this exercise, we will extend our redis client with protocol buffers functionality. 6 | 7 | * link:../redis-protobuf.html[Presentation slides] 8 | 9 | == Preparation + Setup 10 | 11 | Step 1:: 12 | 13 | * Install the https://grpc.io/docs/protoc-installation/[protoc compiler] (required by `prost-build`). 14 | * Create a binary project called `redis-client-protobuf`: `cargo new --bin redis-client-protobuf` and add your redis client library as a path dependency. 15 | * Copy the https://github.com/ferrous-systems/teaching-material/tree/main/assignments/redis-protobuf[protobuf definitions] to your source directory. 16 | 17 | == Implementation 18 | Step 2:: 19 | + 20 | -- 21 | Generate Rust protobuf code for phone book and configuration, using https://docs.rs/prost-build/0.7.0/prost_build/[prost_build] 22 | 23 | Step 3:: 24 | + 25 | -- 26 | Store and retrieve configuration and phone book entries in Redis. 27 | 28 | Step 4:: 29 | + 30 | -- 31 | Implement a wrapper around `RedisClient` that handles encoding and decoding. 32 | 33 | Bonus:: 34 | + 35 | -- 36 | Optimize your build so that code generation is only run when the protobuf definitions change. -------------------------------------------------------------------------------- /assignments/redis-protobuf/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package phone.config; 4 | 5 | message Config { 6 | enum Mode { 7 | ACTIVE = 0; 8 | DND = 1; 9 | OUT_OF_OFFICE = 2; 10 | } 11 | 12 | string serial_number = 1; 13 | Mode mode = 2; 14 | } 15 | -------------------------------------------------------------------------------- /assignments/redis-protobuf/phonebook.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package phone.phonebook; 4 | 5 | message Entry { 6 | enum Category { 7 | PERSONAL = 0; 8 | WORK = 1; 9 | } 10 | enum Kind { 11 | PERSON = 0; 12 | COMPANY = 1; 13 | } 14 | 15 | string name = 1; 16 | string number = 2; 17 | Category category = 3; 18 | Kind kind = 4; 19 | } 20 | 21 | message PhoneBook { 22 | repeated Entry entries = 1; 23 | } -------------------------------------------------------------------------------- /assignments/semver/parse_file/solution/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 = "parse_file" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /assignments/semver/parse_file/solution/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parse_file" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /assignments/semver/parse_file/solution/releases.txt: -------------------------------------------------------------------------------- 1 | hello-world,0.0.1,0.0.5,1.0.0 2 | semver-training,0.0.1 3 | file-io,0.1.5,1.0.1,2.0x.0,2.0.5 -------------------------------------------------------------------------------- /assignments/semver/parse_file/template/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 = "parse_file" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /assignments/semver/parse_file/template/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parse_file" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /assignments/semver/parse_file/template/releases.txt: -------------------------------------------------------------------------------- 1 | hello-world,0.0.1,0.0.5,1.0.0 2 | semver-training,0.0.1 3 | file-io,0.1.5,1.0.1,2.0.0,2.0.5 -------------------------------------------------------------------------------- /assignments/solutions/actix-semver/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /assignments/solutions/actix-semver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "actix-semver" 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 | semver = { path = "../semver"} 10 | semver_api = { path = "../semver-client-server/semver-api/"} 11 | 12 | actix = "0.10" 13 | actix-web = "3.3.2" 14 | actix-web-actors = "3" 15 | actix-files = "0.3" 16 | actix-codec = "0.3" 17 | 18 | rand = "0.8.4" 19 | bytes = "0.5.3" 20 | byteorder = "1.2" 21 | futures = "0.3" 22 | log = "0.4" 23 | pretty_env_logger = "0.4.0" 24 | serde = { version = "1.0", features = ["derive"] } 25 | serde_json = "1.0" 26 | -------------------------------------------------------------------------------- /assignments/solutions/actix-semver/client.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferrous-systems/teaching-material/81806ce816ac550fb27667542d0bdb0ab5c59bc5/assignments/solutions/actix-semver/client.py -------------------------------------------------------------------------------- /assignments/solutions/actix/chat-websockets/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /assignments/solutions/actix/chat-websockets/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "actix-example" 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 | [[bin]] 9 | name = "server" 10 | path = "src/main.rs" 11 | 12 | [dependencies] 13 | actix = "0.10" 14 | actix-web = "3.3.2" 15 | actix-web-actors = "3" 16 | actix-files = "0.3" 17 | actix-codec = "0.3" 18 | 19 | rand = "0.8.4" 20 | bytes = "0.5.3" 21 | byteorder = "1.2" 22 | futures = "0.3" 23 | log = "0.4" 24 | env_logger = "0.9" 25 | serde = { version = "1.0", features = ["derive"] } 26 | serde_json = "1.0" 27 | -------------------------------------------------------------------------------- /assignments/solutions/actix/chat-websockets/Readme.md: -------------------------------------------------------------------------------- 1 | # Websocket Chat Server 2 | 3 | This is a suggested solution of the assignments to write a HTTP chat server using [`actix-web`](https://github.com/actix/actix-web) and `websockets` with [`actix-web-actors`](https://github.com/actix/actix-web/tree/master/actix-web-actors). 4 | 5 | The assignment can be found here: https://ferrous-systems.github.io/teaching-material/assignments/actix.html 6 | 7 | To start the chat server execute `cargo run`. To connect to the chat server via client, open your browser at http://localhost:8080/. Open multiple tabs & connect to the chat server, play around. 8 | 9 | To enable logs set the `RUST_LOG` environment variable. 10 | 11 | ```shell 12 | RUST_LOG=info cargo run 13 | ``` 14 | -------------------------------------------------------------------------------- /assignments/solutions/async-std-mailbox-connection-limit/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["redisish", "mailbox"] 3 | -------------------------------------------------------------------------------- /assignments/solutions/async-std-mailbox-connection-limit/mailbox/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mailbox" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | redisish = { path = "../redisish" } 9 | async-std = "1" 10 | async-listen = "0.2.1" -------------------------------------------------------------------------------- /assignments/solutions/async-std-mailbox-connection-limit/redisish/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /assignments/solutions/async-std-mailbox-connection-limit/redisish/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redisish" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /assignments/solutions/async-std-mailbox-tracing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["redisish", "mailbox"] 3 | -------------------------------------------------------------------------------- /assignments/solutions/async-std-mailbox-tracing/mailbox/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mailbox" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | redisish = { path = "../redisish" } 9 | async-std = "1" 10 | async-channel = "1" 11 | tracing = "0.1" 12 | tracing-futures = "0.2" 13 | tracing-subscriber = "0.2" -------------------------------------------------------------------------------- /assignments/solutions/async-std-mailbox-tracing/redisish/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /assignments/solutions/async-std-mailbox-tracing/redisish/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redisish" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /assignments/solutions/async-std-mailbox/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["redisish", "mailbox"] 3 | -------------------------------------------------------------------------------- /assignments/solutions/async-std-mailbox/mailbox/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mailbox" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | redisish = { path = "../redisish" } 9 | async-std = "1" 10 | tracing = "0.1" -------------------------------------------------------------------------------- /assignments/solutions/async-std-mailbox/redisish/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /assignments/solutions/async-std-mailbox/redisish/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redisish" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /assignments/solutions/async-std-mailbox/redisish/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[derive(Eq,PartialEq,Debug)] 2 | pub enum Command { 3 | Publish(String), 4 | Retrieve 5 | } 6 | 7 | #[derive(Eq,PartialEq,Debug)] 8 | pub enum Error { 9 | UnknownVerb, 10 | UnexpectedPayload, 11 | MissingPayload, 12 | EmptyMessage, 13 | IncompleteMessage, 14 | } 15 | 16 | pub fn parse(input: &str) -> Result { 17 | let mut input = input; 18 | if let Some(pos) = input.find('\n') { 19 | input = &input[0..pos]; 20 | } else { 21 | return Err(Error::IncompleteMessage) 22 | } 23 | let mut split = input.splitn(2, ' '); 24 | 25 | if let Some(verb) = split.next() { 26 | match verb.trim() { 27 | "RETRIEVE" => { 28 | if split.next() == None { 29 | Ok(Command::Retrieve) 30 | } else { 31 | Err(Error::UnexpectedPayload) 32 | } 33 | } 34 | "PUBLISH" => { 35 | if let Some(payload) = split.next() { 36 | Ok(Command::Publish(payload.trim().into())) 37 | } else { 38 | Err(Error::MissingPayload) 39 | } 40 | } 41 | "" => { 42 | Err(Error::EmptyMessage) 43 | } 44 | _ => { Err(Error::UnknownVerb) } 45 | } 46 | } else { 47 | Err(Error::EmptyMessage) 48 | } 49 | } -------------------------------------------------------------------------------- /assignments/solutions/calc/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "calc" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /assignments/solutions/calc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "calc" 3 | version = "0.1.0" 4 | authors = ["Aleksey Kladov "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /assignments/solutions/connected-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 = "redisish" 7 | version = "0.1.0" 8 | 9 | [[package]] 10 | name = "tcp-echo-server" 11 | version = "0.1.0" 12 | dependencies = [ 13 | "redisish", 14 | ] 15 | -------------------------------------------------------------------------------- /assignments/solutions/connected-mailbox/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["redisish", "mailbox"] -------------------------------------------------------------------------------- /assignments/solutions/connected-mailbox/mailbox/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tcp-echo-server" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | redisish = { path = "../redisish" } -------------------------------------------------------------------------------- /assignments/solutions/connected-mailbox/redisish/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redisish" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /assignments/solutions/durable_file/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "durable_file" 3 | version = "0.1.0" 4 | authors = ["Ferrous Systems "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dev-dependencies] 10 | tempdir = "0.3.7" 11 | -------------------------------------------------------------------------------- /assignments/solutions/fill_in_the_blanks/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 = "fill_in_the_blanks" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /assignments/solutions/fill_in_the_blanks/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fill_in_the_blanks" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /assignments/solutions/fizzbuzz/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "fizzbuzz" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /assignments/solutions/fizzbuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fizzbuzz" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /assignments/solutions/fizzbuzz/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | for i in 1..100 { 3 | println!("{}", fizzbuzz(i)); 4 | } 5 | } 6 | 7 | fn fizzbuzz(i: u32) -> String { 8 | if i % 3 == 0 && i % 5 == 0 { 9 | format!("FizzBuzz") 10 | } else if i % 3 == 0 { 11 | format!("Fizz") 12 | } else if i % 5 == 0 { 13 | format!("Buzz") 14 | } else { 15 | format!("{}", i) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /assignments/solutions/green-yellow/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /assignments/solutions/green-yellow/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "green-yellow" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | rand = "0.8.3" 10 | -------------------------------------------------------------------------------- /assignments/solutions/redis-protobuf/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /assignments/solutions/redis-protobuf/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ex-redis" 3 | version = "0.1.0" 4 | authors = ["Anatol Ulrich "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | anyhow = "1.0.40" 11 | bytes = "1.0.1" 12 | prost = "0.7.0" 13 | redis = "0.20.0" 14 | redis-client = { path = "../redis"} 15 | 16 | [build-dependencies] 17 | prost-build = "0.7.0" 18 | 19 | [profile.dev] 20 | # speed up compilation on macos (Rust 1.51+ only) 21 | split-debuginfo = "unpacked" 22 | -------------------------------------------------------------------------------- /assignments/solutions/redis-protobuf/build.rs: -------------------------------------------------------------------------------- 1 | fn main() -> std::io::Result<()> { 2 | let protos = ["src/phonebook.proto", "src/config.proto"]; 3 | for proto in &protos { 4 | println!("cargo:rerun-if-changed={}", proto); 5 | } 6 | prost_build::compile_protos(&protos, &["src/"])?; 7 | Ok(()) 8 | } 9 | -------------------------------------------------------------------------------- /assignments/solutions/redis-protobuf/src/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package phone.config; 4 | 5 | message Config { 6 | enum Mode { 7 | ACTIVE = 0; 8 | DND = 1; 9 | OUT_OF_OFFICE = 2; 10 | } 11 | 12 | string serial_number = 1; 13 | Mode mode = 2; 14 | } 15 | -------------------------------------------------------------------------------- /assignments/solutions/redis-protobuf/src/phone.rs: -------------------------------------------------------------------------------- 1 | pub mod phonebook { 2 | include!(concat!(env!("OUT_DIR"), "/phone.phonebook.rs")); 3 | } 4 | 5 | pub mod config { 6 | include!(concat!(env!("OUT_DIR"), "/phone.config.rs")); 7 | } 8 | -------------------------------------------------------------------------------- /assignments/solutions/redis-protobuf/src/phonebook.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package phone.phonebook; 4 | 5 | message Entry { 6 | enum Category { 7 | PERSONAL = 0; 8 | WORK = 1; 9 | } 10 | enum Kind { 11 | PERSON = 0; 12 | COMPANY = 1; 13 | } 14 | 15 | string name = 1; 16 | string number = 2; 17 | Category category = 3; 18 | Kind kind = 4; 19 | } 20 | 21 | message PhoneBook { 22 | repeated Entry entries = 1; 23 | } -------------------------------------------------------------------------------- /assignments/solutions/redis/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /assignments/solutions/redis/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redis-client" 3 | version = "0.1.0" 4 | authors = ["Anatol Ulrich "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | anyhow = "1.0.40" 11 | redis = "0.20.0" 12 | structopt = { version = "0.3.21" } 13 | -------------------------------------------------------------------------------- /assignments/solutions/redis/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | pub use redis::Client; 3 | use redis::Connection; 4 | use redis::{Commands, IntoConnectionInfo}; 5 | 6 | pub struct RedisClient { 7 | connection: Connection, 8 | } 9 | 10 | impl RedisClient { 11 | pub fn new(params: T) -> Result { 12 | let client = redis::Client::open(params)?; 13 | Ok(RedisClient { 14 | connection: client.get_connection()?, 15 | }) 16 | } 17 | pub fn set(&mut self, key: &str, data: &[u8]) -> Result<()> { 18 | self.connection.set(key, data)?; 19 | Ok(()) 20 | } 21 | 22 | pub fn get(&mut self, key: &str) -> Result> { 23 | let result = self.connection.get(key)?; 24 | Ok(result) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /assignments/solutions/redisish/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 = "redisish" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /assignments/solutions/redisish/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redisish" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-api/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "semver_api" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | semver = { path = "../../semver"} 10 | serde = { version = "1.0", features = ["derive"]} 11 | serde_json = "1.0" 12 | -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-client-async/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "semver-client" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | semver = {path = "../../semver"} 10 | semver_api = {path = "../semver-api"} 11 | 12 | log = "0.4" 13 | pretty_env_logger = "0.4" 14 | async-std = "1.10.0" 15 | rand = "0.8" 16 | anyhow = "1.0" -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "semver-client" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | semver = {path = "../../semver"} 10 | semver_api = {path = "../semver-api"} 11 | 12 | log = "0.4" 13 | pretty_env_logger = "0.4" 14 | -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server-actix/.gitignore: -------------------------------------------------------------------------------- 1 | ve 2 | /target/* 3 | -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server-actix/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "semver-actix-websockets" 3 | version = "2.0.0" 4 | edition = "2021" 5 | 6 | # simple example with one repo per connection 7 | [[bin]] 8 | name = "simple-server" 9 | path = "src/simple-server.rs" 10 | 11 | # repo shared between multiple instances 12 | [[bin]] 13 | name = "shared-server" 14 | path = "src/shared-server.rs" 15 | 16 | [[bin]] 17 | name = "websocket-client" 18 | path = "src/client.rs" 19 | 20 | [dependencies] 21 | actix = "0.10" 22 | actix-codec = "0.3" 23 | actix-web = "3" 24 | actix-web-actors = "3" 25 | actix-files = "0.3" 26 | awc = "2" 27 | pretty_env_logger = "0.4" 28 | log = "0.4" # 👆 29 | futures = "0.3.1" 30 | bytes = "0.5.3" 31 | 32 | semver = { path = "../../semver"} 33 | semver_api = { path = "../semver-api" } 34 | 35 | serde_json = "1.0" -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server-actix/README.md: -------------------------------------------------------------------------------- 1 | # websocket 2 | 3 | Simple echo websocket server. 4 | 5 | ## Usage 6 | 7 | ### server 8 | 9 | ```bash 10 | cd websockets/websocket 11 | cargo run --bin websocket-server 12 | # Started http server: 127.0.0.1:8080 13 | ``` 14 | 15 | ### web client 16 | 17 | - [http://localhost:8080/index.html](http://localhost:8080/index.html) 18 | 19 | ### rust client 20 | 21 | ```bash 22 | cd websockets/websocket 23 | cargo run --bin websocket-client 24 | ``` 25 | 26 | ### python client 27 | 28 | - ``pip install aiohttp`` 29 | - ``python websocket-client.py`` 30 | 31 | if ubuntu : 32 | 33 | - ``pip3 install aiohttp`` 34 | - ``python3 websocket-client.py`` 35 | -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server-actix/static/actixLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferrous-systems/teaching-material/81806ce816ac550fb27667542d0bdb0ab5c59bc5/assignments/solutions/semver-client-server/semver-server-actix/static/actixLogo.png -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server-actix/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferrous-systems/teaching-material/81806ce816ac550fb27667542d0bdb0ab5c59bc5/assignments/solutions/semver-client-server/semver-server-actix/static/favicon.ico -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server-async-channels/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server-async-channels/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server-async-channels/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "semver-server-async-channels" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | async-std = "1.10" 10 | futures = "0.3" 11 | semver = { path = "../../semver"} 12 | semver_api = { path = "../semver-api" } 13 | log = "0.4" 14 | pretty_env_logger = "0.4" 15 | -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server-async/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server-async/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "semver-server-threaded" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | async-std = "1.10.0" 10 | semver = { path = "../../semver"} 11 | semver_api = { path = "../semver-api" } 12 | -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server-threaded/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server-threaded/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "semver-server-threaded" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | semver = { path = "../../semver"} 10 | semver_api = { path = "../semver-api" } -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /assignments/solutions/semver-client-server/semver-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "semver-server" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | semver = { path = "../../semver"} 10 | semver_api = { path = "../semver-api" } -------------------------------------------------------------------------------- /assignments/solutions/semver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "semver" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | serde = { version = "1.0.130", features = ["derive"] } 10 | serde_json = "1.0.68" 11 | -------------------------------------------------------------------------------- /assignments/solutions/shapes/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shapes" 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 | -------------------------------------------------------------------------------- /assignments/solutions/tcp-client/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "tcp-client" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /assignments/solutions/tcp-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tcp-client" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /assignments/solutions/tcp-client/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io::prelude::*; 2 | use std::net::{Shutdown, TcpStream}; 3 | 4 | fn main() -> std::io::Result<()> { 5 | let arg = std::env::args().nth(1); 6 | 7 | let message = match arg { 8 | Some(msg) => msg, 9 | None => String::from("Hello!"), 10 | }; 11 | // or: 12 | // arg.unwrap_or_default(String::from("Hello!")); 13 | 14 | let mut stream = TcpStream::connect("127.0.0.1:7878")?; 15 | 16 | writeln!(stream, "{}", message)?; 17 | 18 | stream.shutdown(Shutdown::Write)?; 19 | 20 | let mut buffer = String::new(); 21 | 22 | stream.read_to_string(&mut buffer)?; 23 | 24 | println!("{}", buffer); 25 | 26 | Ok(()) 27 | } 28 | -------------------------------------------------------------------------------- /assignments/solutions/tcp-echo-server/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "tcp-echo-server" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /assignments/solutions/tcp-echo-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tcp-echo-server" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /assignments/solutions/tcp-echo-server/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::io::prelude::*; 3 | use std::net::{TcpListener, TcpStream}; 4 | 5 | fn handle_client(mut stream: TcpStream) -> Result<(), io::Error> { 6 | let mut buffer = String::new(); 7 | 8 | stream.read_to_string(&mut buffer)?; 9 | 10 | println!("string: {}", buffer); 11 | 12 | stream.write(buffer.as_bytes())?; 13 | 14 | Ok(()) 15 | } 16 | 17 | fn main() -> io::Result<()> { 18 | let listener = TcpListener::bind("127.0.0.1:7878")?; 19 | 20 | // accept connections and process them serially 21 | for stream in listener.incoming() { 22 | handle_client(stream?)?; 23 | } 24 | Ok(()) 25 | } 26 | -------------------------------------------------------------------------------- /assignments/solutions/terrarium/accepting_json.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | 3 | #[derive(Serialize,Deserialize)] 4 | struct Person { 5 | name: String, 6 | age: u32, 7 | address: Address, 8 | phone_numbers: Vec, 9 | } 10 | 11 | #[derive(Serialize,Deserialize)] 12 | struct Address { 13 | street: String, 14 | city: String 15 | } 16 | 17 | use http_guest::{Request, Response}; 18 | 19 | pub fn user_entrypoint(req: &Request>) -> Response> { 20 | match *req.method() { 21 | http::method::POST => { 22 | let parsed_person = serde_json::from_slice::(req.body()); 23 | 24 | match parsed_person { 25 | Ok(p) => { 26 | Response::builder() 27 | .status(200) 28 | .body(serde_json::to_vec(&p).unwrap()) 29 | .unwrap() 30 | }, 31 | Err(e) => { 32 | Response::builder() 33 | .status(422) 34 | .body(format!("Error occurred: {}", e).into()) 35 | .unwrap() 36 | } 37 | } 38 | } 39 | }, 40 | _ => { 41 | Response::builder().status(405) 42 | .header("allow", "POST") 43 | .body(vec![]).unwrap() 44 | } 45 | } 46 | } 47 | 48 | guest_app!(user_entrypoint); 49 | 50 | -------------------------------------------------------------------------------- /assignments/solutions/terrarium/http_request.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | 3 | use http_guest::{Request, Response, RequestExt}; 4 | 5 | pub fn user_entrypoint(req: &Request>) -> Response> { 6 | 7 | match *req.method() { 8 | http::Method::POST => { 9 | let backend_req = Request::builder() 10 | .method("POST") 11 | .uri(format!("https://httpbin.org/post")) 12 | .header("accept", "application/json") 13 | .body(req.body().clone()) 14 | .unwrap(); 15 | 16 | let pending = backend_req.send_async().unwrap(); 17 | 18 | //.... 19 | 20 | pending.wait().unwrap() 21 | } 22 | _ => { 23 | Response::builder().status(405) 24 | .header("allow", "POST") 25 | .body(vec![]).unwrap() 26 | } 27 | } 28 | 29 | } 30 | 31 | guest_app!(user_entrypoint); 32 | 33 | -------------------------------------------------------------------------------- /assignments/solutions/terrarium/message_storage.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | 3 | use http_guest::{KVStore, Request, Response}; 4 | 5 | pub fn user_entrypoint(kvs: &mut KVStore, req: &Request>) -> Response> { 6 | match *req.method() { 7 | http::Method::POST => { 8 | kvs.insert(req.uri().path(), req.body()); 9 | Response::builder().status(200).body("Stored your message!".into()).unwrap() 10 | }, 11 | http::Method::GET => { 12 | let maybe_msg = kvs.get(req.uri().path()); 13 | 14 | match maybe_msg { 15 | Some(m) => Response::builder().status(200).body(m.into()).unwrap(), 16 | None => Response::builder().status(404).body("No message found".into()).unwrap() 17 | } 18 | } 19 | _ => { 20 | Response::builder().status(405).body("GET or POST only!".into()).unwrap() 21 | } 22 | } 23 | } 24 | 25 | guest_app_kvs!(user_entrypoint); 26 | -------------------------------------------------------------------------------- /assignments/solutions/threaded-mailbox/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "mailbox" 5 | version = "0.1.0" 6 | dependencies = [ 7 | "redisish 0.1.0", 8 | ] 9 | 10 | [[package]] 11 | name = "redisish" 12 | version = "0.1.0" 13 | 14 | -------------------------------------------------------------------------------- /assignments/solutions/threaded-mailbox/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["redisish", "mailbox"] 3 | -------------------------------------------------------------------------------- /assignments/solutions/threaded-mailbox/mailbox/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mailbox" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | redisish = { path = "../redisish" } 9 | -------------------------------------------------------------------------------- /assignments/solutions/threaded-mailbox/redisish/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /assignments/solutions/threaded-mailbox/redisish/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redisish" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /assignments/solutions/tracing-future/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-future" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | async-std = "1" 11 | pin-project-lite = "0.1" -------------------------------------------------------------------------------- /assignments/solutions/tracing-future/examples/main.rs: -------------------------------------------------------------------------------- 1 | use tracing_future::*; 2 | 3 | use async_std::task; 4 | use std::thread; 5 | use std::time; 6 | 7 | fn main() { 8 | task::block_on(async { 9 | let async_sleep = async { 10 | task::sleep(time::Duration::from_millis(100)).await; 11 | }; 12 | 13 | task::spawn(poll_max(async_sleep)).await; 14 | 15 | let sync_sleep = async { 16 | thread::sleep(time::Duration::from_millis(100)); 17 | }; 18 | 19 | task::spawn(poll_max(sync_sleep)).await; 20 | 21 | let async_sleep = async { 22 | task::sleep(time::Duration::from_millis(100)).await; 23 | }; 24 | 25 | task::spawn(deadline(time::Duration::from_millis(10), async_sleep)).await; 26 | }); 27 | } -------------------------------------------------------------------------------- /assignments/tcp-client.adoc: -------------------------------------------------------------------------------- 1 | = Exercise: TCP client 2 | :source-language: rust 3 | 4 | In this exercise, we will implement a simple TCP client. 5 | 6 | You will learn how to: 7 | 8 | * write a simple single-threaded client tool 9 | * connect to your server and send/receive strings 10 | * close parts of a bidirectional stream 11 | 12 | == Task 13 | 14 | 1. Start a TCP connection on port `127.0.0.1:7878` 15 | 2. Send a message over 16 | 3. Close the write end of the connection 17 | 4. Print the response to the console 18 | 19 | == Getting started 20 | 21 | Use this template: 22 | 23 | [source,rust] 24 | ---- 25 | use std::io; 26 | 27 | fn main() -> io::Result<()> { 28 | let arg = std::env::args().nth(1); 29 | 30 | let message = match arg { 31 | Some(msg) => msg, 32 | None => String::from("Default Message"), 33 | }; 34 | 35 | 36 | //... 37 | Ok(()) 38 | } 39 | ---- 40 | 41 | Read the documentation for the `TcpStream`, especially the `connect()` and `shutdown()` methods. 42 | -------------------------------------------------------------------------------- /assignments/terrarium-kv.adoc: -------------------------------------------------------------------------------- 1 | = Exercise: Accepting JSON 2 | :source-language: rust 3 | 4 | In this exercise, we will implement a simple KV app. 5 | 6 | You will learn: 7 | 8 | * How to use Terrariums KV API 9 | * How to react differently based on HTTP method 10 | 11 | == Task 12 | 13 | 1. Create a new Terrarium project 14 | 2. Accept POST requests and store the body using the request path as key 15 | 3. Accept GET requests, retrieving the value using the request path as key 16 | 4. If no data is available, return "no data available" 17 | 5. Optionally, implement DELETE 18 | -------------------------------------------------------------------------------- /examples/ffi_use_c_in_rust/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 = "cc" 7 | version = "1.0.73" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 10 | 11 | [[package]] 12 | name = "ffi_use_c_in_rust" 13 | version = "0.1.0" 14 | dependencies = [ 15 | "cc", 16 | ] 17 | -------------------------------------------------------------------------------- /examples/ffi_use_c_in_rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ffi_use_c_in_rust" 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 | 10 | [build-dependencies] 11 | cc = "1.0" -------------------------------------------------------------------------------- /examples/ffi_use_c_in_rust/build.rs: -------------------------------------------------------------------------------- 1 | use cc; 2 | 3 | fn main() { 4 | cc::Build::new() 5 | .file("src/cool_library.c") 6 | .compile("cool_library"); 7 | } 8 | -------------------------------------------------------------------------------- /examples/ffi_use_c_in_rust/src/cool_library.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint32_t cool_library_function(uint32_t x, uint32_t y) { 4 | return x + y; 5 | } 6 | -------------------------------------------------------------------------------- /examples/ffi_use_c_in_rust/src/main.rs: -------------------------------------------------------------------------------- 1 | extern "C" { 2 | fn cool_library_function(x: u32, y: u32) -> u32; 3 | } 4 | 5 | fn main() { 6 | let result: u32 = unsafe { 7 | cool_library_function(6, 7) 8 | }; 9 | println!("6 + 7 = {}", result); 10 | } 11 | -------------------------------------------------------------------------------- /examples/ffi_use_rust_in_c/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 = "ffi_use_rust_in_c" 7 | version = "1.0.0" 8 | -------------------------------------------------------------------------------- /examples/ffi_use_rust_in_c/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ffi_use_rust_in_c" 3 | version = "1.0.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["lib", "staticlib", "cdylib"] 8 | 9 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 10 | 11 | [dependencies] 12 | -------------------------------------------------------------------------------- /examples/ffi_use_rust_in_c/Makefile: -------------------------------------------------------------------------------- 1 | all: example 2 | 3 | rebuild: clean all 4 | 5 | clean: 6 | rm -rf example ./target 7 | 8 | example: example.c ./target/debug/libffi_use_rust_in_c.a 9 | cc -o example example.c ./target/debug/libffi_use_rust_in_c.a 10 | 11 | ./target/debug/libffi_use_rust_in_c.a: ./src/lib.rs ./Cargo.toml 12 | cargo build 13 | 14 | .PHONY: all clean rebuild 15 | -------------------------------------------------------------------------------- /examples/ffi_use_rust_in_c/example.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "example.h" 4 | 5 | int main(int argc, char **argv) { 6 | magic_adder_t ma = magicadder_new(5); 7 | printf("5 + 6 = %u\n", magicadder_process_value(&ma, 6)); 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /examples/ffi_use_rust_in_c/example.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /// Designed to have the exact same shape as the Rust version 4 | typedef struct magic_adder_t { 5 | uint32_t amount; 6 | } magic_adder_t; 7 | 8 | /// Wraps MagicAdder::new 9 | extern magic_adder_t magicadder_new(uint32_t amount); 10 | 11 | /// Wraps MagicAdder::process_value 12 | extern uint32_t magicadder_process_value(magic_adder_t *self, uint32_t value); 13 | -------------------------------------------------------------------------------- /examples/ffi_use_rust_in_c/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | pub struct MagicAdder { 3 | amount: u32 4 | } 5 | 6 | impl MagicAdder { 7 | pub fn new(amount: u32) -> MagicAdder { 8 | MagicAdder { 9 | amount 10 | } 11 | } 12 | 13 | pub fn process_value(&self, value: u32) -> u32 { 14 | self.amount + value 15 | } 16 | } 17 | 18 | #[no_mangle] 19 | pub extern "C" fn magicadder_new(amount: u32) -> MagicAdder { 20 | MagicAdder::new(amount) 21 | } 22 | 23 | #[no_mangle] 24 | pub extern "C" fn magicadder_process_value(adder: *const MagicAdder, value: u32) -> u32 { 25 | if let Some(ma) = unsafe { adder.as_ref() } { 26 | ma.process_value(value) 27 | } else { 28 | 0 29 | } 30 | } 31 | 32 | #[cfg(test)] 33 | mod tests { 34 | use super::*; 35 | 36 | #[test] 37 | fn it_works() { 38 | let ma = MagicAdder::new(5); 39 | assert_eq!(6, ma.process_value(1)); 40 | assert_eq!(10, ma.process_value(5)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "teaching-material", 3 | "version": "1.0.0", 4 | "description": "Ferrous Systems Teaching Material", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/ferrous-systems/teaching-material.git" 8 | }, 9 | "keywords": [ 10 | "Rust", 11 | "learn Rust" 12 | ], 13 | "author": "Ferrous Systems GmbH (https://ferrous-systems.com)", 14 | "license": "CC-BY-SA-4.0", 15 | "bugs": { 16 | "url": "https://github.com/ferrous-systems/teaching-material/issues" 17 | }, 18 | "homepage": "https://github.com/ferrous-systems/teaching-material#readme", 19 | "dependencies": { 20 | "@mermaid-js/mermaid-cli": "^9.1.4" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /presentations/advanced-generics-bounds/1.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | fn print_everything(to_print: T) { 4 | println!("{:?}", to_print); 5 | } 6 | 7 | fn print_everything2(to_print: T) 8 | where T: Debug 9 | { 10 | println!("{:?}", to_print); 11 | } -------------------------------------------------------------------------------- /presentations/advanced-generics-bounds/2.rs: -------------------------------------------------------------------------------- 1 | struct MyStruct { 2 | inner: T 3 | } -------------------------------------------------------------------------------- /presentations/advanced-generics-bounds/3.rs: -------------------------------------------------------------------------------- 1 | trait Distance { /* ... */ } 2 | 3 | trait Centered { 4 | fn center(&self) -> (i32, i32); 5 | } 6 | 7 | impl Distance for T 8 | where T: Centered, 9 | X: Centered { 10 | } -------------------------------------------------------------------------------- /presentations/advanced-generics-bounds/4.rs: -------------------------------------------------------------------------------- 1 | trait Logger { 2 | fn log(&self, x: X); 3 | } -------------------------------------------------------------------------------- /presentations/advanced-generics-bounds/5.rs: -------------------------------------------------------------------------------- 1 | fn take_unsized(t: &T) { 2 | //... 3 | } -------------------------------------------------------------------------------- /presentations/advanced-generics-bounds/6.rs: -------------------------------------------------------------------------------- 1 | struct Wrapper { 2 | inner: T 3 | } 4 | 5 | impl Wrapper { 6 | fn new(inner: T) -> Wrapper where T: Debug { 7 | Wrapper { inner: inner } 8 | } 9 | 10 | fn inspect(&self) where T: Debug { 11 | println!("{:?}", &self.inner); 12 | } 13 | } -------------------------------------------------------------------------------- /presentations/advanced-generics-bounds/7.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | 3 | fn open_file>(pathlike: P) { 4 | let path = pathlike.as_ref(); 5 | } -------------------------------------------------------------------------------- /presentations/advanced-generics-bounds/8.rs: -------------------------------------------------------------------------------- 1 | trait Log { 2 | fn log(&self, t: T); 3 | } 4 | 5 | impl Log for T where T: Debug { 6 | fn log(&self, t: T) { 7 | println!("Logging: {:?}", t); 8 | } 9 | } -------------------------------------------------------------------------------- /presentations/advanced-generics-bounds/9.rs: -------------------------------------------------------------------------------- 1 | trait Named { 2 | fn name(&self) -> &'static str; 3 | } 4 | trait Person : Named { 5 | fn home_address(&self) -> Address; 6 | } -------------------------------------------------------------------------------- /presentations/async-await-intro/async_main_1.rs: -------------------------------------------------------------------------------- 1 | fn main() -> Result<(), Box> { 2 | let rt = tokio::runtime::Runtime::new()?; 3 | rt.block_on(async { 4 | async_main().await 5 | }) 6 | } 7 | 8 | async fn async_main() -> Result<(), Box> { 9 | // your async code 10 | } 11 | -------------------------------------------------------------------------------- /presentations/async-await-intro/async_main_2.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() -> Result<(), Box> { 3 | // your async code 4 | } 5 | -------------------------------------------------------------------------------- /presentations/async-await-intro/async_stream_read.rs: -------------------------------------------------------------------------------- 1 | let mut lines = async_buffered_text_stream.lines(); 2 | while let Some(line) = lines.next().await { 3 | if let Ok(line) = line { 4 | // line is a valid utf8 `String` 5 | process_line(line); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /presentations/async-await-intro/async_trait.rs: -------------------------------------------------------------------------------- 1 | pub trait TcpListener { 2 | // not possible in Rust yet! 3 | /* async */ fn accept(&self) -> Result<(TcpStream, SocketAddr), Error>; 4 | } 5 | -------------------------------------------------------------------------------- /presentations/async-await-intro/block_on.rs: -------------------------------------------------------------------------------- 1 | use futures::executor::block_on; 2 | 3 | async fn hello_world() { 4 | println!("This is my task!"); 5 | } 6 | 7 | fn main() { 8 | let future = hello_world(); // Nothing is printed, yet 9 | block_on(future); 10 | } 11 | -------------------------------------------------------------------------------- /presentations/async-await-intro/example/async-await-intro/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /presentations/async-await-intro/example/async-await-intro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "async-await-intro" 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 | hyper = { version = "0.14.19", features = ["full"] } 10 | hyper-tls = "0.5.0" 11 | rustls = "0.20.6" 12 | tokio = { version = "1.19.2", features = ["full"] } 13 | -------------------------------------------------------------------------------- /presentations/async-await-intro/fetch_into_string.rs: -------------------------------------------------------------------------------- 1 | async fn fetch_into_string(url: &str) -> Result> { 2 | let url: hyper::Uri = url.parse()?; 3 | 4 | let client = hyper::Client::new(); 5 | let res = client.get(url).await?; 6 | 7 | let bytes = hyper::body::to_bytes(res.into_body()).await?; 8 | Ok(String::from_utf8(bytes.to_vec())?) 9 | } 10 | -------------------------------------------------------------------------------- /presentations/async-await-intro/is_website_up.rs: -------------------------------------------------------------------------------- 1 | async fn is_website_up(url: &str) -> Result> { 2 | let url = url.parse::()?; 3 | 4 | let client = hyper::Client::new(); 5 | let res = client.get(url).await?; 6 | 7 | let status_code = res.status(); 8 | Ok(status_code.is_success()) 9 | } 10 | -------------------------------------------------------------------------------- /presentations/async-await-intro/join.rs: -------------------------------------------------------------------------------- 1 | let check_example = is_website_up("http://example.com"); 2 | let check_forever = is_website_up("http://httpforever.com"); 3 | 4 | let (example_result, forever_result) = join!(check_example, check_forever); 5 | -------------------------------------------------------------------------------- /presentations/async-await-intro/lazy.rs: -------------------------------------------------------------------------------- 1 | async fn call_some_api() {} 2 | 3 | async fn do_interesting_things() { 4 | println!("I'm an async function and I do interesting things"); 5 | call_some_api().await 6 | } 7 | 8 | fn main() { 9 | do_interesting_things(); // <1> 10 | async { 11 | do_interesting_things().await; // <2> 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /presentations/async-await-intro/select.rs: -------------------------------------------------------------------------------- 1 | select! { 2 | example = fetch_into_string("http://example.com") => 3 | println!("Example is faster with body:\n{}", example?), 4 | forever = fetch_into_string("http://httpforever.com") => 5 | println!("HttpForever is faster with body:\n{}", forever?), 6 | } 7 | -------------------------------------------------------------------------------- /presentations/async-await-intro/task_spawn.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() -> Result<(), Box> { 3 | let listener = tokio::net::TcpListener::bind("127.0.0.1:6379").await?; 4 | 5 | loop { 6 | let (socket, _) = listener.accept().await?; 7 | 8 | tokio::spawn(async move { // <1> 9 | process(socket).await; 10 | }); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /presentations/async-await-laziness-in-detail/futures-vs-promises.js: -------------------------------------------------------------------------------- 1 | async function subtask() { 2 | console.log("> > subtask"); // <3> 3 | } 4 | 5 | async function task() { 6 | console.log("> before subtask"); // <2> 7 | await subtask(); 8 | console.log("> after subtask"); // <5> 9 | } 10 | 11 | (async function main() { 12 | console.log("before promise"); // <1> 13 | let promise = task(); 14 | console.log("promise is created"); // <4> 15 | await promise; 16 | console.log("promise is awaited"); // <6> 17 | })(); 18 | -------------------------------------------------------------------------------- /presentations/async-await-laziness-in-detail/futures_vs_promises.rs: -------------------------------------------------------------------------------- 1 | async fn subtask() { 2 | println!("> > subtask"); // <4> 3 | } 4 | 5 | async fn task() { 6 | println!("> Before subtask"); // <3> 7 | subtask().await; 8 | println!("> After subtask"); // <5> 9 | } 10 | 11 | fn main() { 12 | futures::executor::block_on(async { 13 | println!("before future"); // <1> 14 | let future = task(); 15 | println!("future is created"); // <2> 16 | future.await; 17 | println!("future is awaited"); // <6> 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /presentations/async-await/1.rs: -------------------------------------------------------------------------------- 1 | pub trait Future { 2 | type Output; 3 | 4 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; 5 | } 6 | -------------------------------------------------------------------------------- /presentations/async-await/2.rs: -------------------------------------------------------------------------------- 1 | use async_std::io; 2 | 3 | async fn read_from_stdin() -> io::Result<()> { 4 | let stdin = io::stdin(); 5 | 6 | // Read a line from the standard input and display it. 7 | let mut line = String::new(); 8 | stdin.read_line(&mut line).await?; 9 | dbg!(line); 10 | 11 | Ok(()) 12 | } -------------------------------------------------------------------------------- /presentations/async-await/3.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | async fn timeout_on_stdin(duration: Duration) -> io::Result<()> { 4 | io::timeout(duration, read_from_stdin()) 5 | } -------------------------------------------------------------------------------- /presentations/async-await/4.rs: -------------------------------------------------------------------------------- 1 | use async_std::io; 2 | use std::time::Duration; 3 | 4 | async fn timeout_on_stdin(duration: Duration) -> io::Result<()> { 5 | io::timeout(duration, async { 6 | let stdin = io::stdin(); 7 | 8 | // Read a line from the standard input and display it. 9 | let mut line = String::new(); 10 | stdin.read_line(&mut line).await?; 11 | dbg!(line); 12 | 13 | Ok(()) 14 | }) 15 | } -------------------------------------------------------------------------------- /presentations/async-await/5.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use async_std::io; 4 | use async_std::task; 5 | 6 | // ... other function definitions 7 | 8 | fn main() -> io::Result<()> { 9 | let duration = Duration::from_secs(5); 10 | // This async scope times out after 5 seconds. 11 | task::block_on(timeout_on_stdin(duration)) 12 | } 13 | -------------------------------------------------------------------------------- /presentations/basic-types/1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let foo = 3_i64; 3 | let bar = foo as i32; 4 | } -------------------------------------------------------------------------------- /presentations/basic-types/2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let float: f64 = 1.0; 3 | } -------------------------------------------------------------------------------- /presentations/basic-types/3.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let arr: [i32; 4] = [1,2,3,4]; 3 | } -------------------------------------------------------------------------------- /presentations/basic-types/4.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let slice: &[i32] = &[1,2,3,4]; 3 | let subslice = &slice[1..2]; 4 | println!("subslice = {:?}", subslice); 5 | } 6 | -------------------------------------------------------------------------------- /presentations/basic-types/5.rs: -------------------------------------------------------------------------------- 1 | fn main() -> () { 2 | 42; 3 | } -------------------------------------------------------------------------------- /presentations/basic-types/6.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // U+0072 LATIN SMALL LETTER R 3 | let ascii_char = 'r'; 4 | // U+03BC GREEK SMALL LETTER MU 5 | let special_char = 'μ'; 6 | // U+0154 LATIN CAPITAL LETTER R WITH ACUTE 7 | let accented_char = 'Ŕ'; 8 | // U+2622 RADIOACTIVE SIGN 9 | let emoji_char = '\u{2622}'; 10 | // U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F467 11 | let seven_chars_emoji = '👨‍👩‍👧‍👧'; // Error: char must be one codepoint long 12 | } 13 | -------------------------------------------------------------------------------- /presentations/cargo/1.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tcp-mailbox" 3 | version = "0.1.0" 4 | authors = ["Florian Gilcher "] 5 | 6 | [dependencies] 7 | async-std = "1" # would also choose 1.5 8 | clap = "2.2" # would also choose 2.3 9 | -------------------------------------------------------------------------------- /presentations/cargo/2.toml: -------------------------------------------------------------------------------- 1 | [dependencies] 2 | async-std = "1" 3 | 4 | [build-dependencies] 5 | cbindgen = "0.5" 6 | 7 | [dev-dependencies] 8 | quickcheck = "0.9" 9 | -------------------------------------------------------------------------------- /presentations/cargo/3.toml: -------------------------------------------------------------------------------- 1 | [dependencies.async-std] 2 | version = "1" 3 | git = "https://github.com/skade/async-std.git" 4 | branch = "my-new-feature" 5 | -------------------------------------------------------------------------------- /presentations/cargo/4.toml: -------------------------------------------------------------------------------- 1 | [dependencies.async-std] 2 | version = "1" 3 | path = "/my/local/path" 4 | -------------------------------------------------------------------------------- /presentations/cargo/5.toml: -------------------------------------------------------------------------------- 1 | paths = ["/my/local/path", "/another/path"] -------------------------------------------------------------------------------- /presentations/cargo/6.rs: -------------------------------------------------------------------------------- 1 | #[cfg(experimental)] 2 | fn amazing_function() { 3 | 4 | } -------------------------------------------------------------------------------- /presentations/cargo/7.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | default = [] 3 | # Turns on experimental features. 4 | experimental = [] -------------------------------------------------------------------------------- /presentations/cargo/8.toml: -------------------------------------------------------------------------------- 1 | [dependencies.my_lib] 2 | version = "0.1" 3 | features = ["experimental"] -------------------------------------------------------------------------------- /presentations/check-for-errors.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mkdir -p /tmp/r 3 | fd .rs -x rustc -A warnings --crate-type=lib --out-dir=/tmp/r "{}" \; 4 | -------------------------------------------------------------------------------- /presentations/closures/1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let vec = vec![1,2,3]; 3 | let out = vec.iter().map(|x| x * 2).collect::>(); 4 | println!("{:?}", out); 5 | } -------------------------------------------------------------------------------- /presentations/closures/2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let vec = vec![1,2,3]; 3 | let double = |x| { x * 2 }; 4 | let out = vec.iter().map(double).collect::>(); 5 | println!("{:?}", out); 6 | } -------------------------------------------------------------------------------- /presentations/closures/3.rs: -------------------------------------------------------------------------------- 1 | fn call_with_one(some_closure: F) -> i32 2 | where 3 | F: Fn(i32) -> i32, 4 | { 5 | some_closure(1) 6 | } 7 | -------------------------------------------------------------------------------- /presentations/closures/4.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let num = 5; 3 | 4 | let owns_num = move |x: i32| x + num; 5 | } -------------------------------------------------------------------------------- /presentations/closures/slides.adoc: -------------------------------------------------------------------------------- 1 | = Closures 2 | 3 | link:./index.html[Table of Contents] 4 | 5 | == ! 6 | 7 | Rust has closures. Multiple, even. 8 | 9 | * **Advantage:** Highly optimized using only the absolutely necessary runtime resources, often none. 10 | * **Disadvantage:** Knowing the specific closure type is not always easy. 11 | 12 | == Notation 13 | 14 | [source,rust] 15 | ---- 16 | include::./1.rs[] 17 | ---- 18 | 19 | [source,rust] 20 | ---- 21 | include::./2.rs[] 22 | ---- 23 | 24 | == Closure Types 25 | 26 | Moving:: The closure consumes its environment. It can only be called once. 27 | 28 | Mutating:: The closure mutates its environment 29 | 30 | Referencing:: The closure references its environment immutably 31 | 32 | == ! 33 | 34 | `rustc` infers the type automatically, but it is needed for type signatures! 35 | 36 | == Notation of closure arguments 37 | 38 | [source,rust] 39 | ---- 40 | include::./3.rs[] 41 | ---- 42 | 43 | == Moves and Closures 44 | 45 | To resolve ambiguity, closures borrow by default. Moving needs to be requested. 46 | 47 | [source,rust] 48 | ---- 49 | include::./4.rs[] 50 | ---- 51 | -------------------------------------------------------------------------------- /presentations/compound-types/1.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32, 4 | } -------------------------------------------------------------------------------- /presentations/compound-types/2.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32, 4 | } 5 | 6 | fn main() { 7 | let p = Point { x: 1, y: 1 }; 8 | } -------------------------------------------------------------------------------- /presentations/compound-types/3.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32, 4 | } 5 | 6 | fn main() { 7 | let p = Point { x: 1, y: 2 }; 8 | println!("{}", p.x); 9 | println!("{}", p.y); 10 | } -------------------------------------------------------------------------------- /presentations/compound-types/4.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let p = (1, 2); 3 | println!("{}", p.0); 4 | println!("{}", p.1); 5 | } -------------------------------------------------------------------------------- /presentations/compound-types/5.rs: -------------------------------------------------------------------------------- 1 | struct Point(i32,i32); 2 | 3 | fn main() { 4 | let p = Point(1, 2); 5 | println!("{}", p.0); 6 | println!("{}", p.1); 7 | } -------------------------------------------------------------------------------- /presentations/compound-types/6.rs: -------------------------------------------------------------------------------- 1 | enum Direction { 2 | Right, 3 | Left, 4 | Up, 5 | Down, 6 | } 7 | 8 | fn main() { 9 | let direction = Direction::Left; 10 | } -------------------------------------------------------------------------------- /presentations/compound-types/7.rs: -------------------------------------------------------------------------------- 1 | enum Movement { 2 | Right(i32), 3 | Left(i32), 4 | Up(i32), 5 | Down(i32), 6 | } 7 | 8 | fn main() { 9 | let movement = Movement::Left(12); 10 | } -------------------------------------------------------------------------------- /presentations/compound-types/8.rs: -------------------------------------------------------------------------------- 1 | enum Actions { 2 | StickAround, 3 | MoveTo { x: i32, y: i32}, 4 | } 5 | 6 | fn main() { 7 | let action = Actions::MoveTo { x: 0, y: 0 }; 8 | } -------------------------------------------------------------------------------- /presentations/compound-types/9.rs: -------------------------------------------------------------------------------- 1 | fn prints_but_returns_nothing(data: &str) -> () { 2 | println!("passed string: {}", data); 3 | } 4 | -------------------------------------------------------------------------------- /presentations/control-flow/1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if 1 == 2 { // <1> <2> 3 | println!("unlikely"); 4 | } else { 5 | println!("expected"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /presentations/control-flow/10.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let numbers = vec![1, 2, 3]; 3 | // `for item in iterable` creates an iterator by calling `iterable.into_iter()` 4 | // and keeps calling `next() -> Option` on it until it receives `None` 5 | for num in numbers { 6 | println!("{}", num); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /presentations/control-flow/11.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut i = 0; 3 | 4 | while !(i > 100) { 5 | i += 1; 6 | } 7 | 8 | let mut iter = vec![1,2,3].into_iter(); 9 | 10 | while let Some(i) = iter.next() { 11 | println!("number: {}", i); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /presentations/control-flow/11a.rs: -------------------------------------------------------------------------------- 1 | 'outer: for i in 0..10 { 2 | loop { 3 | if i < 5 { 4 | continue 'outer; 5 | } else { 6 | break 'outer; 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /presentations/control-flow/11b.rs: -------------------------------------------------------------------------------- 1 | fn get_number() -> u32 { 2 | return 5; 3 | 4 | 8 5 | } 6 | -------------------------------------------------------------------------------- /presentations/control-flow/12.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::io::Read; 3 | 4 | fn read_file(path: &std::path::Path) -> Result { 5 | let mut f = std::fs::File::open(path)?; 6 | 7 | let mut buffer = String::new(); 8 | f.read_to_string(&mut buffer)?; 9 | 10 | Ok(buffer) 11 | } 12 | -------------------------------------------------------------------------------- /presentations/control-flow/2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let a = 4; 3 | match a % 3 { 4 | 0 => { println!("divisible by 3") }, // <1> 5 | _ => { println!("not divisible by 3") }, // <2> 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /presentations/control-flow/3.rs: -------------------------------------------------------------------------------- 1 | enum Direction { //<1> 2 | North(i32), //<2> 3 | East(i32), 4 | South(i32), 5 | West(i32), 6 | } 7 | 8 | fn going_west(dir: &Direction) -> bool { 9 | match dir { //<3> 10 | Direction::West(_) => true, //<4> 11 | _ => false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /presentations/control-flow/4.rs: -------------------------------------------------------------------------------- 1 | enum Option { 2 | Some(T), 3 | None, 4 | } 5 | 6 | enum Result { 7 | Ok(T), 8 | Err(E), 9 | } 10 | -------------------------------------------------------------------------------- /presentations/control-flow/5.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let will_overflow: Option = 10_u8.checked_add(250); 3 | match will_overflow { 4 | Some(sum) => println!("interesting: {}", sum), 5 | None => eprintln!("addition overflow!"), 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /presentations/control-flow/6.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io; 3 | 4 | fn main() { 5 | let file_open: Result = File::open("Does not exist"); 6 | 7 | match file_open { 8 | Ok(f) => println!("Success!"), 9 | Err(e) => println!("Open failed: {:?}", e), 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /presentations/control-flow/7.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let result: Option = 5_u8.checked_add(5); 3 | 4 | match result { 5 | Some(result) if result % 2 == 0 => println!("5+5 is even!"), 6 | _ => println!("5+5 ... isn't even?"), 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /presentations/control-flow/7_5.rs: -------------------------------------------------------------------------------- 1 | enum Direction { 2 | North(u32), 3 | East(u32), 4 | South(u32), 5 | West(u32), 6 | } 7 | 8 | fn going_south_or_west(dir: &Direction) -> bool { 9 | match dir { 10 | Direction::West(_) | Direction::South(_) => true, 11 | _ => false, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /presentations/control-flow/8.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let maybe_arg = std::env::args().nth(2); 3 | // can't know at compile time how many args are passed to our program 4 | if let Some(arg) = maybe_arg { 5 | println!("Got second command line argument: {}", arg); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /presentations/control-flow/9.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut i = 0; 3 | 4 | loop { 5 | i += 1; 6 | 7 | if i > 100 { break; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /presentations/crates/0.rs: -------------------------------------------------------------------------------- 1 | extern crate serde_json; 2 | 3 | use serde_json::Value; 4 | 5 | fn main() { 6 | let data = r#" { "name": "John Doe", "age": 43, ... } "#; 7 | let v: Value = serde_json::from_str(data)?; 8 | println!( 9 | "Please call {} at the number {}", 10 | v["name"], 11 | v["phones"][0] 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /presentations/crates/1.rs: -------------------------------------------------------------------------------- 1 | use serde_json::{self, Value}; 2 | 3 | fn main() { 4 | let data = r#" { "name": "John Doe", "age": 43, ... } "#; 5 | let v: Value = serde_json::from_str(data)?; 6 | println!( 7 | "Please call {} at the number {}", 8 | v["name"], 9 | v["phones"][0] 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /presentations/crates/2.rs: -------------------------------------------------------------------------------- 1 | use bar::baz; 2 | 3 | fn main() { 4 | baz!(); // I am a macro! 5 | } -------------------------------------------------------------------------------- /presentations/crates/3.rs: -------------------------------------------------------------------------------- 1 | use serde_json as json; 2 | 3 | fn main() { 4 | crate::json::some_function(); 5 | } -------------------------------------------------------------------------------- /presentations/crates/4.toml: -------------------------------------------------------------------------------- 1 | [dependencies] 2 | foo = { git = "svnexpress.com/user/mylib", package = "foo" } 3 | bar = { version = "0.1", package = "actually_its_bar_these_days" } 4 | -------------------------------------------------------------------------------- /presentations/deref-coersions/1.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32 4 | } 5 | 6 | fn main() { 7 | let boxed_p = Box::new(Point { x: 1, y: 2 }); 8 | println!("{}", boxed_p.x); 9 | } -------------------------------------------------------------------------------- /presentations/deref-coersions/2.rs: -------------------------------------------------------------------------------- 1 | impl Deref for Box { 2 | type Target = T; 3 | 4 | fn deref(&self) -> &T { 5 | self.inner 6 | } 7 | } -------------------------------------------------------------------------------- /presentations/deref-coersions/3.rs: -------------------------------------------------------------------------------- 1 | fn print_me(message: &str) { println!("{}", message); } 2 | 3 | fn main() { 4 | print_me("Foo"); 5 | let a_string = String::from("Bar"); 6 | print_me(&a_string); 7 | print_me(a_string.as_str()) 8 | } -------------------------------------------------------------------------------- /presentations/deref-coersions/slides.adoc: -------------------------------------------------------------------------------- 1 | = Deref-Conversions 2 | 3 | link:./index.html[Table of Contents] 4 | 5 | 6 | == Motivation 7 | 8 | Why does the following work? 9 | 10 | [source,rust] 11 | ---- 12 | include::./1.rs[] 13 | ---- 14 | 15 | Box doesn't have a field named "x"! 16 | 17 | == Auto-Dereferencing 18 | 19 | Rust automatically dereferences in certain cases. Like everything else, it must be explicitly requested: 20 | 21 | - Through a call or field access using the `.` operator 22 | - By explicitly dereferencing through `*` 23 | - When borrowing through `&` 24 | - This sometimes leads to the ugly `&*`-Pattern 25 | 26 | == ! 27 | 28 | This makes wrapper types very ergonomic and easy to use! 29 | 30 | == ! 31 | 32 | Dereferencing is described by the `Deref` and `DerefMut`-Traits. 33 | 34 | [source,rust] 35 | ---- 36 | include::./2.rs[] 37 | ---- 38 | 39 | This call is introduced when dereferencing is requested. 40 | 41 | == Important deref behaviours 42 | 43 | - String -> &str 44 | - Vec -> &[T] 45 | 46 | Functions that don't modify the lengths of a String or a Vector should accept a slice instead. The memory layout is chosen so that this is *cost free*. 47 | 48 | == ! 49 | 50 | [source,rust] 51 | ---- 52 | include::./3.rs[] 53 | ---- 54 | -------------------------------------------------------------------------------- /presentations/design-patterns/1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let string = String::from("string slice"); 3 | let string2: String = "string slice".into(); 4 | } -------------------------------------------------------------------------------- /presentations/design-patterns/2.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::{self, Write}; 3 | 4 | enum MyError { 5 | FileWriteError, 6 | } 7 | 8 | impl From for MyError { 9 | fn from(e: io::Error) -> MyError { 10 | MyError::FileWriteError 11 | } 12 | } 13 | 14 | fn write_to_file_using_q() -> Result<(), MyError> { 15 | let mut file = File::create("my_best_friends.txt")?; 16 | file.write_all(b"This is a list of my best friends.")?; 17 | println!("I wrote to the file"); 18 | Ok(()) 19 | } 20 | // This is equivalent to: 21 | fn write_to_file_using_match() -> Result<(), MyError> { 22 | let mut file = File::create("my_best_friends.txt")?; 23 | match file.write_all(b"This is a list of my best friends.") { 24 | Ok(v) => v, 25 | Err(e) => return Err(From::from(e)), 26 | } 27 | println!("I wrote to the file"); 28 | Ok(()) 29 | } 30 | 31 | fn main() {} 32 | -------------------------------------------------------------------------------- /presentations/design-patterns/3.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::path::Path; 3 | use std::path::PathBuf; 4 | 5 | fn main() { 6 | open_file(&"test"); 7 | let path_buf = PathBuf::from("test"); 8 | open_file(&path_buf); 9 | } 10 | 11 | fn open_file>(p: &P) { 12 | let path = p.as_ref(); 13 | let file = File::open(path); 14 | } -------------------------------------------------------------------------------- /presentations/design-patterns/4.rs: -------------------------------------------------------------------------------- 1 | pub struct Stuff { 2 | value: i64, 3 | } 4 | 5 | impl Stuff { 6 | /// constructor by convention 7 | fn new(value: i64) -> Self { 8 | Self { value: value } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /presentations/design-patterns/5.rs: -------------------------------------------------------------------------------- 1 | struct MyString(String); 2 | 3 | impl MyString { 4 | ///... my implementations for MyString 5 | } 6 | -------------------------------------------------------------------------------- /presentations/design-patterns/6.rs: -------------------------------------------------------------------------------- 1 | trait VecExt { 2 | fn magic_number(&self) -> usize; 3 | } 4 | 5 | impl VecExt for Vec { 6 | fn magic_number(&self) -> usize { 7 | 42 8 | } 9 | } 10 | 11 | fn main() { 12 | let v = vec![1, 2, 3, 4, 5]; 13 | println!("Magic Number = {}", v.magic_number()); 14 | } 15 | -------------------------------------------------------------------------------- /presentations/design-patterns/7.rs: -------------------------------------------------------------------------------- 1 | // Get the inner type from Option 2 | let item = returns_option(); 3 | if let Some(item) = item { 4 | println!("{:?}", item); 5 | } 6 | 7 | // Use shadowing to make the variable immutable outside of 8 | // where it needs to be mutable 9 | let mut data = 42; 10 | // change the data 11 | data += 1; 12 | // Shadow using `let` again 13 | let data = data; 14 | // data is immutable from now on -------------------------------------------------------------------------------- /presentations/docinfo-footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /presentations/documentation/1.bash: -------------------------------------------------------------------------------- 1 | rustup doc --std -------------------------------------------------------------------------------- /presentations/documentation/2.rs: -------------------------------------------------------------------------------- 1 | //! Module documentation. (e.g. the 'Examples' part of `std::vec`). 2 | 3 | /// Document functions, structs, traits and values. 4 | /// This documents a function. 5 | fn function_with_documentation() {} 6 | 7 | // This comment will not be shown as documentation. 8 | // The function itself will be. 9 | fn function_without_documentation() {} -------------------------------------------------------------------------------- /presentations/drop-panic-abort/1.rs: -------------------------------------------------------------------------------- 1 | struct LevelDB { 2 | handle: *mut leveldb_database_t 3 | } 4 | 5 | impl Drop for LevelDB { 6 | fn drop(&mut self) { 7 | unsafe { leveldb_close(self.handle) }; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /presentations/drop-panic-abort/2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | panicking_function(); 3 | } 4 | 5 | fn panicking_function() { 6 | panic!("gosh, don't call me!"); 7 | } 8 | -------------------------------------------------------------------------------- /presentations/dynamic-and-static-libs/1.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | #[repr(C)] 3 | pub struct Point { 4 | x: i32, 5 | y: i32 6 | } 7 | 8 | #[no_mangle] 9 | pub extern "C" fn new_point(x: i32, y: i32) -> *mut Point { 10 | let p = Box::new(Point { x: x, y: y }); 11 | Box::into_raw(p) 12 | } 13 | 14 | #[no_mangle] 15 | pub extern "C" fn destroy_point(p: *mut Point) { 16 | unsafe { Box::from_raw(p) }; 17 | } 18 | 19 | #[no_mangle] 20 | pub extern "C" fn inspect_point(p: *mut Point) { 21 | unsafe { 22 | let point: Box = Box::from_raw(p); 23 | point.inspect(); 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /presentations/dynamic-and-static-libs/2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef struct Point { 5 | int32_t x; 6 | int32_t y; 7 | } Point; 8 | 9 | Point* new_point(int32_t x, int32_t y); 10 | 11 | void destroy_point(Point* p); 12 | 13 | void inspect(Point* p); -------------------------------------------------------------------------------- /presentations/dynamic-and-static-libs/3.toml: -------------------------------------------------------------------------------- 1 | [lib] 2 | crate-type = ["cdylib", "staticlib"] -------------------------------------------------------------------------------- /presentations/dynamic-and-static-libs/4.c: -------------------------------------------------------------------------------- 1 | #include "../include/point.h" 2 | 3 | int main (int argc, char const *argv[]) 4 | { 5 | Point* p = new_point(1,1); 6 | inspect_point(p); 7 | p->x = 2; 8 | inspect_point(p); 9 | destroy_point(p); 10 | } -------------------------------------------------------------------------------- /presentations/dynamic-and-static-libs/5.sh: -------------------------------------------------------------------------------- 1 | gcc -L target/debug/ -I include -lc -lm -lSystem -lcore test/test.c -o point -------------------------------------------------------------------------------- /presentations/dynamic-and-static-libs/6.sh: -------------------------------------------------------------------------------- 1 | $ ./point 2 | Point { x: 1, y: 1 } 3 | Point { x: 2, y: 1 } 4 | point(98132,0x7fffb30293c0) malloc: *** error for object 0x7fa635c02980: pointer being freed was not allocated 5 | *** set a breakpoint in malloc_error_break to debug 6 | Abort trap: 6 -------------------------------------------------------------------------------- /presentations/dynamic-and-static-libs/7.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub extern "C" fn inspect_point(p: *mut Point) { 3 | unsafe { 4 | let point: Box = Box::from_raw(p); 5 | point.inspect(); 6 | std::mem::forget(point) 7 | }; 8 | } 9 | 10 | #[no_mangle] 11 | pub extern "C" fn inspect_point(p: &Point) { 12 | p.inspect(); 13 | } 14 | -------------------------------------------------------------------------------- /presentations/dynamic-and-static-libs/slides.adoc: -------------------------------------------------------------------------------- 1 | = Dynamic and static libraries 2 | 3 | link:./index.html[Table of Contents] 4 | 5 | 6 | == ! 7 | 8 | Let's try to use Rust from C. 9 | 10 | == Library 11 | 12 | [source,rust] 13 | ---- 14 | include::./1.rs[] 15 | ---- 16 | 17 | == C-Header (excerpt) 18 | 19 | [source, c] 20 | ---- 21 | include::./2.c[] 22 | ---- 23 | 24 | == Cargo 25 | 26 | [source, toml] 27 | ---- 28 | include::./3.toml[] 29 | ---- 30 | 31 | `cargo build` will now build a static lib instead of an rlib. `cdylib`s are a special kind of dylib that also removes all Rust-specific metadata. 32 | 33 | == Usage 34 | [source, c] 35 | ---- 36 | include::./4.c[] 37 | ---- 38 | 39 | 40 | [source, bash] 41 | ---- 42 | include::./5.sh[] 43 | ---- 44 | 45 | == Execution 46 | 47 | [source, 6.sh] 48 | ---- 49 | include::./6.sh[] 50 | ---- 51 | 52 | == Woops! 53 | 54 | Take good care of ownership! 55 | 56 | [source,rust] 57 | ---- 58 | include::./7.rs[] 59 | ---- 60 | 61 | == Helpers 62 | 63 | - Cheddar - generates C-Headers from Rust-Libs. 64 | -------------------------------------------------------------------------------- /presentations/dynamic-dispatch/1.rs: -------------------------------------------------------------------------------- 1 | enum Operation { 2 | Get, 3 | Set(String), 4 | Count 5 | } 6 | 7 | fn execute(op: Operation) { 8 | match op { 9 | Operation::Get => execute_get(), 10 | Operation::Set(s) => execute_set(s), 11 | Operation::Count => execute_count() 12 | } 13 | } -------------------------------------------------------------------------------- /presentations/dynamic-dispatch/2.rs: -------------------------------------------------------------------------------- 1 | enum Operation { 2 | Get, 3 | Set(String), 4 | Count 5 | } 6 | 7 | impl Operation { 8 | fn execute(&self) { 9 | match &self { 10 | &Operation::Get => execute_get(), 11 | &Operation::Set(s) => execute_set(s), 12 | &Operation::Count => execute_count() 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /presentations/dynamic-dispatch/3.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | use std::any::Any; 3 | 4 | // Logger function for any type that implements Debug. 5 | fn log(value: &T) { 6 | let value_any = value as &dyn Any; 7 | 8 | // try to convert our value to a String. If successful, we want to 9 | // output the String's length as well as its value. If not, it's a 10 | // different type: just print it out unadorned. 11 | match value_any.downcast_ref::() { 12 | Some(as_string) => { 13 | println!("String ({}): {}", as_string.len(), as_string); 14 | } 15 | None => { 16 | println!("{:?}", value); 17 | } 18 | } 19 | } 20 | 21 | fn main() { 22 | log(&String::from("String here")); 23 | log(&1) 24 | } 25 | -------------------------------------------------------------------------------- /presentations/dynamic-dispatch/4.rs: -------------------------------------------------------------------------------- 1 | fn factory() -> Box i32> { 2 | let num = 5; 3 | 4 | Box::new(move |x| x + num) 5 | } 6 | -------------------------------------------------------------------------------- /presentations/error-handling/1.diagram: -------------------------------------------------------------------------------- 1 | +-----+ +-----+ +-----+ 2 | | T,E |-->| U,E |-->| U,X | 3 | +-----+ +-----+ +-----+ -------------------------------------------------------------------------------- /presentations/error-handling/1.rs: -------------------------------------------------------------------------------- 1 | fn this_can_fail(succeeds: bool) -> Result { 2 | if succeeds { 3 | Ok(String::from("Success")) 4 | } else { 5 | Err(String::from("Error")) 6 | } 7 | } 8 | 9 | fn main() { 10 | let outcome = this_can_fail(true); 11 | println!("{:?}", outcome); 12 | } -------------------------------------------------------------------------------- /presentations/error-handling/2.output: -------------------------------------------------------------------------------- 1 | warning: unused `Result` that must be used 2 | --> src/main.rs:10:5 3 | | 4 | 10 | this_can_fail(true); 5 | | ^^^^^^^^^^^^^^^^^^^^ 6 | | 7 | = note: `#[warn(unused_must_use)]` on by default 8 | = note: this `Result` may be an `Err` variant, which should be handled 9 | -------------------------------------------------------------------------------- /presentations/error-handling/2.rs: -------------------------------------------------------------------------------- 1 | fn this_can_fail(succeeds: bool) -> Result { 2 | if succeeds { 3 | Ok(String::from("Success")) 4 | } else { 5 | Err(String::from("Error")) 6 | } 7 | } 8 | 9 | fn main() { 10 | this_can_fail(true); 11 | } -------------------------------------------------------------------------------- /presentations/error-handling/3.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | match this_can_fail(false) { 3 | Ok(val) => println!("Success: {}", val), 4 | Err(err) => println!("Error: {}", err), 5 | } 6 | } -------------------------------------------------------------------------------- /presentations/error-handling/4.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if this_can_fail(false).is_ok() { 3 | println!("It worked!"); 4 | } else { 5 | println!("It didn't work!") 6 | } 7 | } -------------------------------------------------------------------------------- /presentations/error-handling/5.rs: -------------------------------------------------------------------------------- 1 | fn multiple_possible_failures() -> Result { 2 | this_can_fail(true)?; 3 | println!("After 1st potential error."); 4 | this_can_fail(false)?; 5 | println!("After 2nd potential error."); 6 | Ok(String::from("All done.")) 7 | } 8 | 9 | fn main() { 10 | multiple_possible_failures(); 11 | } -------------------------------------------------------------------------------- /presentations/error-handling/6.output: -------------------------------------------------------------------------------- 1 | After 1st potential error. -------------------------------------------------------------------------------- /presentations/error-handling/6.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | fn main() -> Result<(), Box> { 4 | maybe_dangerous()?; 5 | Ok(()) 6 | } 7 | -------------------------------------------------------------------------------- /presentations/error-handling/7.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let some_result = this_can_fail(true); 3 | // Only done if `some_result` is an `Ok` Variant. 4 | let mapped_result = some_result.map(|val| val.len()); 5 | println!("{:?}", mapped_result); 6 | } -------------------------------------------------------------------------------- /presentations/error-handling/8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferrous-systems/teaching-material/81806ce816ac550fb27667542d0bdb0ab5c59bc5/presentations/error-handling/8 -------------------------------------------------------------------------------- /presentations/error-handling/8.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | 3 | fn main() -> Result<(), Box> { 4 | let f = File::open("broken")?; 5 | 6 | let x: i32 = "ABC".parse()?; 7 | 8 | Ok(()) 9 | } 10 | -------------------------------------------------------------------------------- /presentations/ffi/callbacks.rs: -------------------------------------------------------------------------------- 1 | use std::os::raw::c_void; 2 | 3 | pub type FooCallback = extern "C" fn(state: *mut c_void); 4 | 5 | extern "C" { 6 | pub fn libfoo_register_callback(state: *mut c_void, cb: FooCallback); 7 | } 8 | 9 | extern "C" fn my_callback(_state: *mut c_void) { 10 | // Do stuff here 11 | } 12 | 13 | fn main() { 14 | unsafe { libfoo_register_callback(core::ptr::null_mut(), my_callback); } 15 | } 16 | -------------------------------------------------------------------------------- /presentations/ffi/cool_library.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hello.h" 3 | 4 | uint32_t cool_library_function(uint32_t x, uint32_t y) 5 | { 6 | // I know, right? Amazing. 7 | return x + y; 8 | } 9 | -------------------------------------------------------------------------------- /presentations/ffi/cool_library.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /** Do some amazing maths */ 4 | uint32_t cool_library_function(uint32_t x, uint32_t y); -------------------------------------------------------------------------------- /presentations/ffi/cool_library.rs: -------------------------------------------------------------------------------- 1 | use std::os::raw::{c_uint, c_char}; 2 | 3 | extern "C" { 4 | // We state that this function exists, but there's no definition. 5 | // The linker looks for this 'symbol name' in the other objects 6 | fn cool_library_function(x: c_uint, y: c_uint) -> c_uint; 7 | } 8 | -------------------------------------------------------------------------------- /presentations/ffi/load_bindings.rs: -------------------------------------------------------------------------------- 1 | #[allow(non_camel_case_types, non_snake_case, non_upper_case_globals)] 2 | pub mod bindings { 3 | include!(concat!(env!("OUT_DIR"), "/bindings.rs")); 4 | } 5 | -------------------------------------------------------------------------------- /presentations/ffi/naming.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] -------------------------------------------------------------------------------- /presentations/ffi/opaque.rs: -------------------------------------------------------------------------------- 1 | /// This is like a 'struct FoobarContext;' in C 2 | #[repr(C)] 3 | pub struct FoobarContext { _priv: [i32; 0] } 4 | 5 | extern "C" { 6 | fn foobar_init() -> *mut FoobarContext; 7 | fn foobar_do(ctx: *mut FoobarContext, foo: i32); 8 | fn foobar_destroy(ctx: *mut FoobarContext); 9 | } 10 | 11 | /// Use this in your Rust code 12 | pub struct FoobarHandle(*mut FoobarContext); 13 | -------------------------------------------------------------------------------- /presentations/ffi/reg.rs: -------------------------------------------------------------------------------- 1 | fn hello(param1: i32, param2: f64) -> SomeStruct { ... } 2 | -------------------------------------------------------------------------------- /presentations/ffi/rustlib-Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "magic_adder" 3 | version = "1.0.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["lib", "staticlib", "cdylib"] 8 | -------------------------------------------------------------------------------- /presentations/ffi/rustlib-wrapper.h: -------------------------------------------------------------------------------- 1 | /// Designed to have the exact same shape as the Rust version 2 | typedef struct magic_adder_t { 3 | uint32_t amount; 4 | } magic_adder_t; 5 | 6 | /// Wraps MagicAdder::new 7 | magic_adder_t magicadder_new(uint32_t amount); 8 | 9 | /// Wraps MagicAdder::process_value 10 | uint32_t magicadder_process_value(magic_adder_t* self, uint32_t value); 11 | -------------------------------------------------------------------------------- /presentations/ffi/rustlib-wrapper.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | struct MagicAdder { 3 | amount: u32 4 | } 5 | 6 | impl MagicAdder { /* Snip... */ } 7 | 8 | #[no_mangle] 9 | extern "C" fn magicadder_new(amount: u32) -> MagicAdder { 10 | MagicAdder::new(amount) 11 | } 12 | 13 | #[no_mangle] 14 | extern "C" fn magicadder_process_value(adder: *const MagicAdder, value: u32) -> u32 { 15 | if let Some(ma) = unsafe { adder.as_ref() } { 16 | ma.process_value(value) 17 | } else { 18 | 0 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /presentations/ffi/rustlib.rs: -------------------------------------------------------------------------------- 1 | struct MagicAdder { 2 | amount: u32 3 | } 4 | 5 | impl MagicAdder { 6 | fn new(amount: u32) -> MagicAdder { 7 | MagicAdder { 8 | amount 9 | } 10 | } 11 | 12 | fn process_value(&self, value: u32) -> u32 { 13 | self.amount + value 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /presentations/ffi/using_cool_library.rs: -------------------------------------------------------------------------------- 1 | use std::os::raw::c_uint; 2 | 3 | extern "C" { 4 | fn cool_library_function(x: c_uint, y: c_uint) -> c_uint; 5 | } 6 | 7 | fn main() { 8 | let result: u32 = unsafe { 9 | cool_library_function(6, 7) 10 | }; 11 | println!("{} should be 13", result); 12 | } -------------------------------------------------------------------------------- /presentations/functions/1.rs: -------------------------------------------------------------------------------- 1 | fn add(first: i32, second: i32) -> i32 { 2 | first + second 3 | } 4 | -------------------------------------------------------------------------------- /presentations/functions/10.rs: -------------------------------------------------------------------------------- 1 | struct Square(f32); 2 | 3 | impl Square { 4 | fn calc_area(&self) -> f32 { 5 | self.0 * self.0 6 | } 7 | 8 | fn destroy(self) { 9 | println!("I ate the square. It has gone."); 10 | } 11 | } 12 | 13 | fn main() { 14 | let sq = Square(1.0); 15 | println!("Area: {}", sq.calc_area()); 16 | sq.destroy(); 17 | // This line won't compile 18 | // println!("Area: {}", sq.calc_area()); 19 | } 20 | -------------------------------------------------------------------------------- /presentations/functions/2.rs: -------------------------------------------------------------------------------- 1 | fn return_nothing() {} 2 | 3 | fn return_a_random() -> i32 { 4 | 4 // Chosen by dice roll. 5 | } 6 | 7 | fn maybe_return_a_random(should: bool) -> Option { 8 | if should { 9 | Some(4) 10 | } else { 11 | None 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /presentations/functions/3.rs: -------------------------------------------------------------------------------- 1 | fn returns_nothing() { 2 | true; 3 | } 4 | 5 | fn doesnt_compile() -> bool { 6 | true; 7 | } 8 | 9 | fn returns() -> bool { 10 | true 11 | } 12 | -------------------------------------------------------------------------------- /presentations/functions/4.rs: -------------------------------------------------------------------------------- 1 | fn takes_anything(thing: T) -> T { 2 | thing 3 | } 4 | -------------------------------------------------------------------------------- /presentations/functions/5.rs: -------------------------------------------------------------------------------- 1 | fn prints_anything(thing: T) { 2 | println!("{:?}", thing); 3 | } 4 | 5 | fn prints_anything(thing: T) 6 | where 7 | T: Debug, 8 | { 9 | println!("{:?}", thing); 10 | } 11 | -------------------------------------------------------------------------------- /presentations/functions/6.rs: -------------------------------------------------------------------------------- 1 | struct Square(f32); 2 | 3 | fn square_num_sides() -> u32 { 4 | 4 5 | } 6 | 7 | fn square_calc_area(square: &Square) -> f32 { 8 | square.0 * square.0 9 | } 10 | 11 | fn square_double_size(square: &mut Square) { 12 | square.0 *= 2.0; 13 | } 14 | -------------------------------------------------------------------------------- /presentations/functions/7.rs: -------------------------------------------------------------------------------- 1 | struct Square(f32); 2 | 3 | impl Square { 4 | fn num_sides() -> u32 { 5 | 4 6 | } 7 | } 8 | 9 | fn main() { 10 | println!("Num sides: {}", Square::num_sides()); 11 | } 12 | -------------------------------------------------------------------------------- /presentations/functions/8.rs: -------------------------------------------------------------------------------- 1 | struct Square(f32); 2 | 3 | impl Square { 4 | fn calc_area(&self) -> f32 { 5 | self.0 * self.0 6 | } 7 | } 8 | 9 | fn main() { 10 | let sq = Square(1.0); 11 | println!("Area: {}", sq.calc_area()); 12 | } 13 | -------------------------------------------------------------------------------- /presentations/functions/9.rs: -------------------------------------------------------------------------------- 1 | struct Square(f32); 2 | 3 | impl Square { 4 | fn calc_area(&self) -> f32 { 5 | self.0 * self.0 6 | } 7 | 8 | fn double_size(&mut self) { 9 | self.0 *= 2.0; 10 | } 11 | } 12 | 13 | fn main() { 14 | let mut sq = Square(1.0); 15 | println!("Area: {}", sq.calc_area()); 16 | sq.double_size(); 17 | println!("New Area: {}", sq.calc_area()); 18 | } 19 | -------------------------------------------------------------------------------- /presentations/futures/1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // This is a simple future, sort of like a one-time channel. 3 | // You get a (sender, receiver) when you invoke them. 4 | // Sending a value consumes that side of the channel. 5 | let (tx, rx) = oneshot::channel(); 6 | 7 | // This consumes the sender, we can't use it afterwards. 8 | tx.send("Bears").unwrap(); 9 | 10 | // Now we can wait for it to finish 11 | let result = rx.wait() 12 | .unwrap(); 13 | println!("{}", result); 14 | } 15 | 16 | use futures::Future; 17 | use futures::sync::oneshot; -------------------------------------------------------------------------------- /presentations/futures/2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let (tx, rx) = oneshot::channel(); 3 | 4 | thread::spawn(move || { 5 | thread::sleep(Duration::from_millis(500)); 6 | tx.send("Bears").unwrap(); 7 | }); 8 | 9 | let result = rx.wait() 10 | .unwrap(); 11 | println!("{}", result); 12 | } 13 | 14 | use std::thread; 15 | use std::time::Duration; 16 | use futures::Future; 17 | use futures::sync::oneshot; -------------------------------------------------------------------------------- /presentations/futures/3.rs: -------------------------------------------------------------------------------- 1 | const NUM_OF_TASKS: usize = 10; 2 | 3 | fn main() { 4 | let mut rx_set = Vec::new(); 5 | 6 | for index in 0..NUM_OF_TASKS { 7 | let (tx, rx) = futures::oneshot(); 8 | rx_set.push(rx); 9 | 10 | thread::spawn(move || { 11 | println!("{} --> START", index); 12 | sleep_a_little_bit(); 13 | tx.send(index).unwrap(); 14 | println!("{} <-- END", index); 15 | }); 16 | } 17 | 18 | // `join_all` lets us join together the set of futures. 19 | let result = join_all(rx_set) 20 | .wait() 21 | .unwrap(); 22 | 23 | println!("{:?}", result); 24 | } 25 | 26 | use std::thread; 27 | use futures::Future; 28 | use futures::future::join_all; 29 | use std::time::Duration; 30 | use rand::distributions::{Range, IndependentSample}; 31 | 32 | // This function sleeps for a bit, then returns how long it slept. 33 | pub fn sleep_a_little_bit() -> u64 { 34 | let mut generator = rand::thread_rng(); 35 | let possibilities = Range::new(0, 1000); 36 | 37 | let choice = possibilities.ind_sample(&mut generator); 38 | 39 | let a_little_bit = Duration::from_millis(choice); 40 | thread::sleep(a_little_bit); 41 | choice 42 | } -------------------------------------------------------------------------------- /presentations/futures/5.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // Creates a CpuPool with workers equal to the cores on the machine. 3 | let pool = Builder::new().create(); 4 | 5 | let returns_string = pool.spawn_fn(move || -> Result<_, ()> { 6 | Ok("First") 7 | }); 8 | let returns_integer = pool.spawn_fn(move || -> Result<_, ()> { 9 | Ok(2) 10 | }); 11 | 12 | let resulting_string = returns_string.wait().unwrap(); 13 | let resulting_integer = returns_integer.wait().unwrap(); 14 | 15 | println!("{}, {}", resulting_string, resulting_integer); 16 | // Returns `First, 2` 17 | } 18 | 19 | use futures::future::Future; 20 | use futures_cpupool::Builder; -------------------------------------------------------------------------------- /presentations/generics-basics/1.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: Precision, 3 | y: Precision 4 | } 5 | 6 | fn main() { 7 | let point = Point { x: 1_u32, y: 2 }; 8 | let point: Point = Point { x: 1, y: 2 }; 9 | } 10 | -------------------------------------------------------------------------------- /presentations/generics-basics/2.rs: -------------------------------------------------------------------------------- 1 | enum Either { 2 | Left(T), 3 | Right(X), 4 | } 5 | 6 | fn main() { 7 | let alternative: Either = Either::Left(123); 8 | } 9 | 10 | enum Result { 11 | Ok(T), 12 | Err(E), 13 | } 14 | 15 | enum Option { 16 | Some(T), 17 | None, 18 | } 19 | 20 | -------------------------------------------------------------------------------- /presentations/generics-basics/3.rs: -------------------------------------------------------------------------------- 1 | enum Option { 2 | Some(T), 3 | None, 4 | } 5 | 6 | fn main() { 7 | let args = std::env::args; 8 | println!("{:?} {:?}", args().nth(0), args().nth(1)); 9 | } -------------------------------------------------------------------------------- /presentations/generics-basics/4.rs: -------------------------------------------------------------------------------- 1 | enum Result { 2 | Ok(T), 3 | Err(E) 4 | } 5 | 6 | fn main() { 7 | let file = std::fs::File::open("I don't exist!"); 8 | println!("{:?}", file); 9 | } -------------------------------------------------------------------------------- /presentations/generics-basics/5.rs: -------------------------------------------------------------------------------- 1 | Result<(), io::Error> 2 | Result 3 | Result -------------------------------------------------------------------------------- /presentations/generics-basics/6.rs: -------------------------------------------------------------------------------- 1 | fn accept_any_type(arg: T) { 2 | // ... 3 | } 4 | 5 | fn accept_and_return_any_type(arg: T) -> U { 6 | // ... 7 | } 8 | -------------------------------------------------------------------------------- /presentations/generics-basics/slides.adoc: -------------------------------------------------------------------------------- 1 | = Simple Generics 2 | 3 | link:./index.html[Table of Contents] 4 | 5 | == ! 6 | 7 | Generics are fundamental for Rust. 8 | 9 | == Generic Structs 10 | 11 | [source,rust] 12 | ---- 13 | include::./1.rs[] 14 | ---- 15 | 16 | == Type Inference 17 | 18 | Rust finds the types of all variables and generics with sufficient information. 19 | 20 | This only applies *inside* of function bodies. 21 | 22 | Signatures must always be fully specified. 23 | 24 | == Generic Enums 25 | 26 | [.notes] 27 | -- 28 | 29 | - under the hood: the compiler silently copies for all instances of `Either` 30 | -> the compiler does the boilerplate-ing for you! 31 | - similar-ish to C++ templates 32 | -- 33 | 34 | [source,rust] 35 | ---- 36 | include::./2.rs[] 37 | ---- 38 | 39 | == Generic Functions 40 | 41 | [.notes] 42 | -- 43 | 44 | - the pattern is always "name" regardless of whether name is a function name, 45 | parameter name, etc 46 | -- 47 | 48 | Generic Functions have type parameters. 49 | 50 | [source,rust] 51 | ---- 52 | include::./6.rs[] 53 | ---- 54 | 55 | Generic functions are used when computations can be expressed in an abstract way. 56 | 57 | [.notes] 58 | -- 59 | 60 | - possible detour: monomorphization, generic contraints (+ where clauses) 61 | -- -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/1.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | 3 | fn main() { 4 | let f = File::open("test"); 5 | } -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/10.rs: -------------------------------------------------------------------------------- 1 | mod workload; 2 | 3 | fn main() { 4 | workload::work(); 5 | 6 | workload::thing::do_stuff(); 7 | } -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/11.rs: -------------------------------------------------------------------------------- 1 | pub mod workload; 2 | 3 | pub trait Distance { 4 | fn distance(&self, other: Self); 5 | } 6 | 7 | pub fn foo() { 8 | 9 | } -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/12.rs: -------------------------------------------------------------------------------- 1 | pub struct Point { 2 | x: i32, 3 | y: i32 4 | } 5 | 6 | impl Point { 7 | pub fn new() -> Point { 8 | Point { x: 1, y: 2 } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/13.rs: -------------------------------------------------------------------------------- 1 | pub struct Point { 2 | pub x: i32, 3 | pub y: i32 4 | } 5 | -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/14.rs: -------------------------------------------------------------------------------- 1 | pub(crate) fn crate_local() { 2 | 3 | } 4 | 5 | pub(super) fn visible_in_super_module() { 6 | 7 | } -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/2.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | 3 | fn main() { 4 | let f = fs::File::open("test"); 5 | } -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/3.rs: -------------------------------------------------------------------------------- 1 | use std::fs::*; 2 | 3 | fn main() { 4 | let f = File::open("test"); 5 | } -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/4-5.rs: -------------------------------------------------------------------------------- 1 | use std::{fs::File, io::{Read, Write}}; 2 | 3 | fn main() { 4 | let mut buffer = [0; 10]; 5 | 6 | let mut f1 = File::open("foo.txt").unwrap(); 7 | f1.read(&mut buffer).unwrap(); 8 | 9 | let mut f2 = File::create("bar.txt").unwrap(); 10 | f2.write_all(&buffer).unwrap(); 11 | } -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/4.rs: -------------------------------------------------------------------------------- 1 | use std::io::prelude::*; 2 | use std::fs::File; 3 | 4 | fn main() { 5 | let mut f = File::open("foo.txt").unwrap(); 6 | let mut buffer = [0; 10]; 7 | 8 | f.read(&mut buffer).unwrap(); 9 | 10 | println!("The bytes: {:?}", buffer); 11 | } -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/5.rs: -------------------------------------------------------------------------------- 1 | use std::fs as file_system; 2 | 3 | fn main() { 4 | let f = file_system::File::open("test"); 5 | } -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/6.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | use std::fs::File; 3 | 4 | let f = File::open("test"); 5 | } -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/7.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | workload::work(); 3 | } 4 | 5 | mod workload { 6 | pub fn work() { 7 | println!("hard at work!"); 8 | } 9 | } -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/8.rs: -------------------------------------------------------------------------------- 1 | | 2 | |-src 3 | |- main.rs 4 | |- workload.rs -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/9-2.rs: -------------------------------------------------------------------------------- 1 | | 2 | |-src 3 | |- main.rs 4 | |- workload.rs 5 | |- workload/ 6 | |- thing.rs -------------------------------------------------------------------------------- /presentations/imports-modules-and-visibility/9.rs: -------------------------------------------------------------------------------- 1 | | 2 | |-src 3 | |- main.rs 4 | |- workload 5 | |- mod.rs 6 | |- thing.rs -------------------------------------------------------------------------------- /presentations/inner-mutability/1.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Default)] 2 | struct Post { 3 | content: String, 4 | viewed_times: usize, 5 | } 6 | 7 | impl Post { 8 | // `mut` is a problem here! 9 | fn view(&mut self) { 10 | self.viewed_times += 1; 11 | } 12 | } -------------------------------------------------------------------------------- /presentations/inner-mutability/2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let post = Post { 3 | content: String::from("Blah"), 4 | ..Post::default() 5 | }; 6 | (0..5).for_each(|_| post.view()); 7 | println!("{:?}", post); 8 | } 9 | 10 | // From before 11 | 12 | #[derive(Debug, Default)] 13 | struct Post { 14 | content: String, 15 | viewed_times: usize, 16 | } 17 | 18 | impl Post { 19 | // `mut` is a problem here! 20 | fn view(&mut self) { 21 | self.viewed_times += 1; 22 | } 23 | } -------------------------------------------------------------------------------- /presentations/inner-mutability/3.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // We need to make the entire struct mutable! 3 | let mut post = Post { 4 | content: String::from("Blah"), 5 | ..Post::default() 6 | }; 7 | (0..5).for_each(|_| post.view()); 8 | println!("{:?}", post); 9 | } 10 | 11 | // From before 12 | 13 | #[derive(Debug, Default)] 14 | struct Post { 15 | content: String, 16 | viewed_times: usize, 17 | } 18 | 19 | impl Post { 20 | // `mut` is a problem here! 21 | fn view(&mut self) { 22 | self.viewed_times += 1; 23 | } 24 | } -------------------------------------------------------------------------------- /presentations/inner-mutability/4.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let post = Post { 3 | content: String::from("Blah"), 4 | ..Post::default() 5 | }; 6 | (0..5).for_each(|_| post.view()); 7 | println!("{:?}", post); 8 | } 9 | 10 | #[derive(Debug, Default)] 11 | struct Post { 12 | content: String, 13 | viewed_times: Cell, 14 | } 15 | 16 | impl Post { 17 | fn view(&self) { 18 | // Note how we are making a copy, then replacing the original. 19 | let current_views = self.viewed_times.get(); 20 | self.viewed_times.set(current_views + 1); 21 | } 22 | } 23 | 24 | use std::cell::Cell; -------------------------------------------------------------------------------- /presentations/inner-mutability/5.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let post = Post { 3 | content: String::from("Blah"), 4 | ..Post::default() 5 | }; 6 | (0..5).for_each(|_| post.view()); 7 | println!("{:?}", post); 8 | } 9 | 10 | #[derive(Debug, Default)] 11 | struct Post { 12 | content: String, 13 | viewed_times: RefCell, 14 | } 15 | 16 | impl Post { 17 | fn view(&self) { 18 | // Note how we're mutating a value. 19 | *self.viewed_times.borrow_mut() += 1; 20 | } 21 | } 22 | 23 | use std::cell::RefCell; -------------------------------------------------------------------------------- /presentations/installation/1.sh: -------------------------------------------------------------------------------- 1 | # Installation of a toolchain (here: the stable release channel) 2 | $ rustup install stable 3 | 4 | # Selection of a default toolchain 5 | $ rustup default stable 6 | 7 | # Display documentation in browser 8 | $ rustup doc [--std] 9 | 10 | # Override the default toolchain in your directory 11 | $ rustup override set stable 12 | 13 | # List supported targets 14 | $ rustup target list 15 | 16 | # Add and install a target to the toolchain (here: to cross-compile for an ARMv6-M target) 17 | $ rustup target add thumbv6m-none-eabi 18 | -------------------------------------------------------------------------------- /presentations/installation/3.sh: -------------------------------------------------------------------------------- 1 | $ rustc --help -------------------------------------------------------------------------------- /presentations/installation/4.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, World!"); 3 | } -------------------------------------------------------------------------------- /presentations/installation/5a.sh: -------------------------------------------------------------------------------- 1 | $ rustc hello_world.rs 2 | $ ./hello_world 3 | -------------------------------------------------------------------------------- /presentations/installation/5b.sh: -------------------------------------------------------------------------------- 1 | $ rustc hello_world.rs 2 | $ ./hello_world 3 | Hello, World! 4 | -------------------------------------------------------------------------------- /presentations/installation/6.sh: -------------------------------------------------------------------------------- 1 | $ cargo --help -------------------------------------------------------------------------------- /presentations/installation/7.sh: -------------------------------------------------------------------------------- 1 | $ cargo new hello-world 2 | $ cd hello-world 3 | $ cat src/main.rs 4 | fn main() { 5 | println!("Hello, world!"); 6 | } 7 | $ cargo build 8 | Compiling hello-world v0.1.0 (file:///Users/skade/Code/rust/scratchpad/hello-world) 9 | Finished debug [unoptimized + debuginfo] target(s) in 0.35 secs 10 | $ cargo run 11 | Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs 12 | Running `target/debug/hello-world` 13 | Hello, world! 14 | -------------------------------------------------------------------------------- /presentations/installation/8.sh: -------------------------------------------------------------------------------- 1 | $ rustup component add rustfmt 2 | $ rustup component add clippy 3 | $ cargo tree 4 | -------------------------------------------------------------------------------- /presentations/iterators-again/1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let v = vec![1,2,3]; 3 | let i = make_iter(&v); 4 | } 5 | 6 | fn make_iter<'a>(v: &'a Vec) -> impl Iterator { 7 | v.iter() 8 | } -------------------------------------------------------------------------------- /presentations/iterators-again/slides.adoc: -------------------------------------------------------------------------------- 1 | = Iterators Again 2 | 3 | link:./index.html[Table of Contents] 4 | 5 | 6 | == Returning Generic Iterators 7 | 8 | Currently, Rust allows no generic return values. You have to use impl trait here. 9 | 10 | [source,rust] 11 | ---- 12 | include::./1.rs[] 13 | ---- 14 | -------------------------------------------------------------------------------- /presentations/iterators/1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let vec = vec![1,2,3]; 3 | let iter = vec.into_iter(); 4 | 5 | for i in iter { 6 | println!("{}", i); 7 | } 8 | 9 | //println!("{:?}", vec); <1> 10 | } 11 | -------------------------------------------------------------------------------- /presentations/iterators/2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let vec = vec![1,2,3]; 3 | let iter = vec.iter(); 4 | 5 | for i in iter { 6 | println!("{}", i); 7 | } 8 | 9 | println!("{:?}", vec); 10 | } 11 | -------------------------------------------------------------------------------- /presentations/iterators/3.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut vec = vec![1,2,3]; 3 | let iter_mut = vec.iter_mut(); 4 | 5 | for i in iter_mut { 6 | *i += 1 7 | } 8 | 9 | println!("{:?}", vec); 10 | } 11 | -------------------------------------------------------------------------------- /presentations/iterators/4.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let items = vec![0, 1, 2]; 3 | let mut iterator = items.into_iter(); 4 | println!("{:?}", iterator.next()); 5 | println!("{:?}", iterator.next()); 6 | println!("{:?}", iterator.next()); 7 | println!("{:?}", iterator.next()); 8 | } -------------------------------------------------------------------------------- /presentations/iterators/5.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let fizzbuzz = (0..10_000) 3 | .map(|x| match x { 4 | x if x % 15 == 0 => String::from("Fizzbuzz"), 5 | x if x % 3 == 0 => String::from("Fizz"), 6 | x if x % 5 == 0 => String::from("Buzz"), 7 | x => format!("{}", x), 8 | }); 9 | for item in fizzbuzz { 10 | println!("{}", item); 11 | } 12 | } -------------------------------------------------------------------------------- /presentations/iterators/6.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let evens = (0..10_000) 3 | .filter(|x| x % 2 == 0); 4 | for item in evens { 5 | println!("{}", item); 6 | } 7 | } -------------------------------------------------------------------------------- /presentations/libcore-and-libstd/slides.adoc: -------------------------------------------------------------------------------- 1 | = libcore and libstd 2 | 3 | link:./index.html[Table of Contents] 4 | 5 | 6 | == ! 7 | 8 | Rust ships with two base libraries, libcore and libstd. 9 | 10 | == ! 11 | 12 | libcore contains all types necessary to make the language work. 13 | 14 | libcore is allocation free. 15 | 16 | == ! 17 | 18 | libcore is usually not used directly, as its public interface is reexported by libstd. 19 | 20 | == ! 21 | 22 | libstd contains standard functions, for example to interact with the file system. It has a dependency to the platform libc. 23 | -------------------------------------------------------------------------------- /presentations/lifetimes/1.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32, 4 | } 5 | 6 | // error[E0106]: missing lifetime specifier 7 | fn return_point() -> &Point { 8 | let p = Point { x: 1, y: 2 }; 9 | &p 10 | } 11 | 12 | fn main() { 13 | return_point(); 14 | } 15 | -------------------------------------------------------------------------------- /presentations/lifetimes/10.rs: -------------------------------------------------------------------------------- 1 | let mut sink = io::BufWriter::new(io::stdout().lock()); 2 | -------------------------------------------------------------------------------- /presentations/lifetimes/11.rs: -------------------------------------------------------------------------------- 1 | let stdout = io::stdout(); 2 | let mut sink = io::BufWriter::new(stdout.lock()); -------------------------------------------------------------------------------- /presentations/lifetimes/12.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let v = vec![1, 2, 3]; 3 | let i = make_iter(&v); 4 | } 5 | 6 | fn make_iter<'a>(v: &'a Vec) -> Box + 'a> { 7 | Box::new(v.iter()) 8 | } 9 | -------------------------------------------------------------------------------- /presentations/lifetimes/2.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32 4 | } 5 | 6 | fn return_point() -> Box { 7 | let p = Point { x: 1, y: 2 }; 8 | Box::new(p) 9 | } -------------------------------------------------------------------------------- /presentations/lifetimes/3.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32 4 | } 5 | 6 | impl Point { 7 | fn x(&self) -> &i32 { 8 | &self.x 9 | } 10 | 11 | fn y<'point>(&'point self) -> &'point i32 { 12 | &self.y 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /presentations/lifetimes/4.rs: -------------------------------------------------------------------------------- 1 | struct Container { 2 | inner: &T, 3 | } 4 | 5 | impl Container { 6 | fn borrow_inner(&self) -> &T { 7 | self.inner 8 | } 9 | } 10 | 11 | fn inner_drops_before_container() { 12 | let s = "hello".to_string(); 13 | let c = Container { inner: &s }; 14 | drop(s); 15 | } 16 | 17 | fn container_drops_with_active_borrow() { 18 | let s = "hello".to_string(); 19 | let c = Container { inner: &s }; 20 | let borrowed_s = c.borrow_inner(); 21 | drop(c); 22 | } 23 | -------------------------------------------------------------------------------- /presentations/lifetimes/5.rs: -------------------------------------------------------------------------------- 1 | struct Container<'container, T> { 2 | inner: &'container T, 3 | } 4 | -------------------------------------------------------------------------------- /presentations/lifetimes/6.rs: -------------------------------------------------------------------------------- 1 | // slice::split_at 2 | 3 | fn split_at(slice: &[T], mid: usize) -> (&[T], &[T]) { 4 | todo!() 5 | } 6 | 7 | fn split_at_explicit<'a, T>(slice: &'a [T], mid: usize) -> (&'a [T], &'a [T]) { 8 | todo!() 9 | } 10 | -------------------------------------------------------------------------------- /presentations/lifetimes/7.rs: -------------------------------------------------------------------------------- 1 | use std::str::Split; 2 | 3 | struct Tokenizer<'input> { 4 | input: Split<'input, char>, 5 | } 6 | 7 | impl<'input> Tokenizer<'input> { 8 | fn next_token(&mut self) -> Option<&'input str> { 9 | self.input.next() 10 | } 11 | } 12 | 13 | struct Parser<'tokenizer, 'input: 'tokenizer> { 14 | tokenizer: &'tokenizer mut Tokenizer<'input>, 15 | } 16 | 17 | impl<'tokenizer, 'input: 'tokenizer> Parser<'tokenizer, 'input> { 18 | fn next_item(&mut self) -> Option<&'input str> { 19 | self.tokenizer.next_token() 20 | } 21 | } 22 | 23 | fn main() { 24 | let mut tok = Tokenizer { input: "( foo bar )".split(' ') }; 25 | let mut parser = Parser { tokenizer: &mut tok }; 26 | 27 | println!("{:?}", parser.next_item()); 28 | let content = parser.next_item(); 29 | let content2 = parser.next_item(); 30 | println!("{:?}", parser.next_item()); 31 | drop(parser); 32 | 33 | println!("{:?}", content); 34 | println!("{:?}", content2); 35 | 36 | } -------------------------------------------------------------------------------- /presentations/lifetimes/8.rs: -------------------------------------------------------------------------------- 1 | fn inspect<'a, T: std::fmt::Debug + 'a>(t: T) { 2 | println!("{:?}", t); 3 | } 4 | -------------------------------------------------------------------------------- /presentations/lifetimes/9.rs: -------------------------------------------------------------------------------- 1 | fn foo(bar: &str) -> &str { 2 | todo!(); 3 | } 4 | 5 | fn foo_explicit<'a>(bar: &'a str) -> &'a str { 6 | todo!(); 7 | } 8 | -------------------------------------------------------------------------------- /presentations/little-helpers/1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let hello = String::from("Hello World"); 3 | println!("{}", hello); 4 | } -------------------------------------------------------------------------------- /presentations/little-helpers/2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let hello = String::from("Hello World"); 3 | println!("{}", hello); // string display 4 | println!("{:?}", hello); // Debug 5 | } -------------------------------------------------------------------------------- /presentations/little-helpers/3.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32 4 | } 5 | 6 | fn main() { 7 | let hello = String::from("Hello World"); 8 | let vec = vec![1,2,3]; 9 | let point = Point { x: 1, y: 2}; 10 | } -------------------------------------------------------------------------------- /presentations/little-helpers/4.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct Point { 3 | x: i32, 4 | y: i32 5 | } 6 | 7 | fn main() { 8 | let point = Box::new(Point { x: 1, y: 2}); 9 | println!("{:?}", point); 10 | } -------------------------------------------------------------------------------- /presentations/macros/1.rs: -------------------------------------------------------------------------------- 1 | macro_rules! double { 2 | // Input parameters 3 | ($value:expr) 4 | => 5 | // Output 6 | ($value * 2); 7 | } 8 | 9 | fn main() { 10 | let doubled = double!(5); 11 | println!("{}", doubled); 12 | // Alternatives: 13 | double! { 5 }; 14 | double![5]; 15 | } -------------------------------------------------------------------------------- /presentations/macros/2.rs: -------------------------------------------------------------------------------- 1 | macro_rules! implement_foo_for { 2 | [ 3 | // This is a repetition! 4 | $($implement_for:ty,)* 5 | ] => { 6 | // This iterates over the repetition! 7 | $(impl Foo for $implement_for {})* 8 | } 9 | } 10 | 11 | implement_foo_for![u8, u16, u32, u64, usize,]; 12 | implement_foo_for! { i8, i16, i32, i64, isize, } 13 | implement_foo_for!(f32, f64,); 14 | 15 | trait Foo { 16 | fn foo(&self) { 17 | println!("Foo!"); 18 | } 19 | } 20 | 21 | fn main() { 22 | 1_u8.foo(); 23 | 1_u16.foo(); 24 | } -------------------------------------------------------------------------------- /presentations/macros/3.rs: -------------------------------------------------------------------------------- 1 | macro_rules! email { 2 | ($user:expr => $domain:expr) => { 3 | format!("{}@{}", $user, $domain); 4 | } 5 | } 6 | 7 | fn main() { 8 | let address = email!("me" => "example.org"); 9 | println!("{}", address); 10 | } -------------------------------------------------------------------------------- /presentations/match/1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut args = std::env::args(); 3 | 4 | match args.nth(1) { 5 | Some(arg) => { println!("Argument: {}", arg)}, 6 | None => { println!("No Argument") } 7 | } 8 | } -------------------------------------------------------------------------------- /presentations/match/2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut args = std::env::args(); 3 | 4 | if let Some(arg) = args.nth(1) { 5 | println!("Argument: {}", arg); 6 | } 7 | } -------------------------------------------------------------------------------- /presentations/match/3.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let maybe_file = std::fs::File::open("Not there!"); 3 | 4 | match maybe_file { 5 | Ok(f) => { println!("File opened! Debug: {:?}", f) }, 6 | Err(e) => { println!("File not opened!! Error: {:?}", e) } 7 | } 8 | } -------------------------------------------------------------------------------- /presentations/match/4.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let maybe_file = std::fs::File::open("Not there!"); 3 | 4 | match maybe_file { 5 | Err(e) => { println!("Error: {:?}", e) } 6 | _ => {} 7 | } 8 | } -------------------------------------------------------------------------------- /presentations/match/5.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | std::fs::File::open("Not there!"); 3 | } -------------------------------------------------------------------------------- /presentations/match/6.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let number = 4; 3 | 4 | match number { 5 | 0 => println!("Number is 0"), 6 | _ => println!("Number is something else") 7 | } 8 | } -------------------------------------------------------------------------------- /presentations/match/7.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut args = std::env::args(); 3 | 4 | let value = if let Some(arg) = args.nth(1) { 5 | arg 6 | } else { 7 | "default!".to_string() 8 | }; 9 | } -------------------------------------------------------------------------------- /presentations/match/8.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let n = 2400; 3 | match (n % 400, n % 100, n % 4) { 4 | (0, _, _) => true, 5 | (_, 0, _) => false, 6 | (_, _, 0) => true, 7 | _ => false, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /presentations/match/slides.adoc: -------------------------------------------------------------------------------- 1 | = Control Flow with `match` 2 | 3 | link:./index.html[Table of Contents] 4 | 5 | 6 | == ! 7 | 8 | To check variants of enums, `match` is used. 9 | 10 | == ! 11 | 12 | [source,rust] 13 | ---- 14 | include::./1.rs[] 15 | ---- 16 | 17 | == Alternative: if-let 18 | 19 | [source,rust] 20 | ---- 21 | include::./2.rs[] 22 | ---- 23 | 24 | == ! 25 | 26 | [source,rust] 27 | ---- 28 | include::./3.rs[] 29 | ---- 30 | 31 | == ! 32 | 33 | Matches must cover all variants! 34 | 35 | == Ignoring variants 36 | 37 | [source,rust] 38 | ---- 39 | include::./4.rs[] 40 | ---- 41 | 42 | == ! 43 | 44 | Results carry a special marker: they must not be ignored! 45 | 46 | 47 | [source,rust] 48 | ---- 49 | include::./5.rs[] 50 | ---- 51 | 52 | Solution: match or pass on. 53 | 54 | == ! 55 | 56 | `match` does not only work on enums: 57 | 58 | [source,rust] 59 | ---- 60 | include::./6.rs[] 61 | ---- 62 | 63 | == ! 64 | 65 | `match` and `if` expressions: 66 | 67 | [source,rust] 68 | ---- 69 | include::./7.rs[] 70 | ---- 71 | 72 | == ! 73 | 74 | `match` can be used on multiple expressions! 75 | 76 | [source,rust] 77 | ---- 78 | include::./8.rs[] 79 | ---- 80 | 81 | **Remember**: `match` arms are evaluated sequentially - first correct choice is chosen. -------------------------------------------------------------------------------- /presentations/mutability/1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let answer = 42; 3 | answer = 32; 4 | } -------------------------------------------------------------------------------- /presentations/mutability/2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut answer = 42; 3 | answer = 32; 4 | } -------------------------------------------------------------------------------- /presentations/mutability/slides.adoc: -------------------------------------------------------------------------------- 1 | = Mutability 2 | 3 | link:./index.html[Table of Contents] 4 | 5 | == ! 6 | 7 | Modern programming languages differ in their attitude towards data mutability. 8 | 9 | Where does Rust land? 10 | 11 | == An Example 12 | 13 | [source,rust] 14 | ---- 15 | include::./1.rs[] 16 | ---- 17 | 18 | == Correct 19 | 20 | [source,rust] 21 | ---- 22 | include::./2.rs[] 23 | ---- 24 | 25 | == ! 26 | 27 | In Rust data mutability must be declared. 28 | 29 | Mutability is always apparent from reading the code. 30 | 31 | == ! 32 | 33 | Mutability is fundamental to Rust and is a common consideration. 34 | 35 | == ! 36 | 37 | Mutability is a property of variables and bindings, not of the bound data! 38 | -------------------------------------------------------------------------------- /presentations/overview/1.rs: -------------------------------------------------------------------------------- 1 | use std::io; // <1> 2 | use std::io::prelude::*; 3 | use std::fs::File; 4 | 5 | fn main() -> Result<(), io::Error> { // <2> 6 | let open_file = File::open("test"); // <3> 7 | 8 | let mut file = match open_file { // <4> 9 | Ok(file) => file, 10 | Err(e) => return Err(e) 11 | }; 12 | 13 | let mut buffer = String::new(); // <5> 14 | file.read_to_string(&mut buffer)?; // <6> 15 | println!("{}", buffer); 16 | 17 | Ok(()) // <7> 18 | } 19 | -------------------------------------------------------------------------------- /presentations/ownership-borrowing-in-brief/1.diagram: -------------------------------------------------------------------------------- 1 | main pacman 2 | +----------+ 3 | | | 4 | | dot |---+ 5 | | | | 6 | +----------+ | +----------+ 7 | | | | 8 | +----| dot | 9 | | | 10 | +----------+ 11 | 12 | 🗑 -------------------------------------------------------------------------------- /presentations/ownership-borrowing-in-brief/1.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Write; 3 | use std::io; 4 | 5 | fn main() -> io::Result<()> { 6 | let file_create = File::create("test"); // <1> 7 | 8 | let mut file = match file_create { // <2> 9 | Ok(f) => f, // <3> 10 | Err(e) => panic!("File create failed: {}", e), 11 | }; 12 | 13 | file.write_all(b"Hello World!") 14 | } // <4> 15 | -------------------------------------------------------------------------------- /presentations/ownership-borrowing-in-brief/2.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Write; 3 | use std::io; 4 | 5 | fn main() -> io::Result<()> { 6 | let file_create = File::create("test"); 7 | 8 | let file = match file_create { 9 | Ok(f) => f, 10 | Err(e) => panic!("File create failed: {}", e), 11 | }; 12 | 13 | write_and_close(file) // <1> 14 | } 15 | 16 | fn write_and_close(mut file: File) -> io::Result<()> { // <1> 17 | file.write_all(b"Hello World!") 18 | 19 | // <2> 20 | } 21 | -------------------------------------------------------------------------------- /presentations/ownership-borrowing-in-brief/3.error: -------------------------------------------------------------------------------- 1 | 8 | let file = match file_create { 2 | | ---- move occurs because `file` has type `std::fs::File`, which does not implement the `Copy` trait 3 | ... 4 | 13 | write_and_close(file); 5 | | ---- value moved here 6 | 14 | write_and_close(file) 7 | | ^^^^ value used here after move 8 | 9 | -------------------------------------------------------------------------------- /presentations/ownership-borrowing-in-brief/3.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Write; 3 | use std::io; 4 | 5 | fn main() -> io::Result<()> { 6 | let file_create = File::create("test"); 7 | 8 | let file = match file_create { 9 | Ok(f) => f, 10 | Err(e) => panic!("File create failed: {}", e), 11 | }; 12 | 13 | write_and_close(file); 14 | write_and_close(file) // <1> 15 | } 16 | 17 | fn write_and_close(mut file: File) -> io::Result<()> { 18 | file.write_all(b"Hello World!") 19 | } 20 | -------------------------------------------------------------------------------- /presentations/ownership-borrowing-in-brief/4.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Write; 3 | use std::io; 4 | 5 | fn main() -> io::Result<()> { 6 | let file_create = File::create("test"); 7 | 8 | let mut file = match file_create { 9 | Ok(f) => f, 10 | Err(e) => panic!("File create failed: {}", e), 11 | }; 12 | 13 | print_filelen(&file)?; 14 | file.write_all(b"Hello World!")?; 15 | print_filelen(&file) 16 | } 17 | 18 | fn print_filelen(f: &File) -> io::Result<()> { 19 | println!("len: {:?}", f.metadata()?.len()); 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /presentations/ownership-borrowing-in-brief/5.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Write; 3 | use std::io; 4 | 5 | fn main() -> io::Result<()> { 6 | let file_create = File::create("test"); 7 | 8 | let mut file = match file_create { 9 | Ok(f) => f, 10 | Err(e) => panic!("File create failed: {}", e), 11 | }; 12 | 13 | print_filelen(&file)?; 14 | write_to_file(&mut file); 15 | print_filelen(&file) 16 | } 17 | 18 | fn print_filelen(f: &File) -> io::Result<()> { 19 | println!("len: {:?}", f.metadata()?.len()); 20 | Ok(()) 21 | } 22 | 23 | fn write_to_file(f: &mut File) -> io::Result<()> { 24 | f.write_all(b"Hello World!") 25 | } 26 | -------------------------------------------------------------------------------- /presentations/ownership-borrowing-in-brief/6.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | struct Dot { 3 | x: i32, 4 | y: i32 5 | } 6 | 7 | fn main() { 8 | let dot = Dot { x: 1, y: 2 }; 9 | pacman(dot.clone()); 10 | pacman(dot); 11 | } 12 | 13 | fn pacman(dot: Dot) { 14 | println!("Eating {:?}", dot); 15 | } -------------------------------------------------------------------------------- /presentations/ownership-borrowing-in-brief/7.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Copy)] 2 | struct Dot { 3 | x: i32, 4 | y: i32 5 | } 6 | 7 | fn main() { 8 | let dot = Dot { x: 1, y: 2 }; 9 | pacman(dot); 10 | pacman(dot); 11 | } 12 | 13 | fn pacman(dot: Dot) { 14 | println!("Eating {:?}", dot); 15 | } -------------------------------------------------------------------------------- /presentations/ownership-borrowing-in-brief/8.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | 3 | fn main() { 4 | let file = File::open("test").unwrap(); 5 | let buffer = read_from(&file); 6 | drop(file); 7 | // do something long 8 | } -------------------------------------------------------------------------------- /presentations/ownership-borrowing-in-brief/9.rs: -------------------------------------------------------------------------------- 1 | #[inline] 2 | fn drop(_: T) { 3 | // take ownership, drop out of scope 4 | } -------------------------------------------------------------------------------- /presentations/proptest/1.rs: -------------------------------------------------------------------------------- 1 | // this property is false, but perhaps 2 | // not unreasonable to expect to be true 3 | proptest! { 4 | #[test] 5 | fn mult_and_div(ref a in any::()) { 6 | let result = (a * 5) / 5; 7 | assert_eq!(result, a); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /presentations/proptest/2.txt: -------------------------------------------------------------------------------- 1 | $ cargo test 2 | test mult_and_div ... FAILED 3 | Test failed: attempt to multiply with overflow; 4 | minimal failing input: ref a = 3689348814741910324 5 | test result: FAILED. 0 passed; 1 failed 6 | -------------------------------------------------------------------------------- /presentations/proptest/3.txt: -------------------------------------------------------------------------------- 1 | $ cat proptest-regressions/main.txt 2 | # Seeds for failure cases proptest has 3 | # generated. It is automatically read 4 | # and these particular cases re-run before 5 | # any novel cases are generated. 6 | 7 | # shrinks to ref a = 3689348814741910324 8 | xs 4050946508 1278147119 4151624343 875310407 9 | -------------------------------------------------------------------------------- /presentations/proptest/4.rs: -------------------------------------------------------------------------------- 1 | proptest! { 2 | #[test] 3 | fn compress_roundtrip(ref s in ".*") { 4 | let result = decompress(compress(s)); 5 | assert_eq!(result, s); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /presentations/proptest/5.rs: -------------------------------------------------------------------------------- 1 | proptest! { 2 | #[test] 3 | fn parses_all_valid_dates( 4 | ref s in "[0-9]{4}-[0-9]{2}-[0-9]{2}" 5 | ) { 6 | parse_date(s).unwrap(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /presentations/proptest/6.rs: -------------------------------------------------------------------------------- 1 | proptest! { 2 | #[test] 3 | fn doesnt_crash( 4 | bit in 0usize..1_000_000, 5 | page_sz_exponent in 0usize..30 6 | ) { 7 | let page_sz = 1 << page_sz_exponent; 8 | let mut bits = Bitfield::new(page_sz); 9 | assert_eq!(bits.set(bit, true), Change::Changed); 10 | assert_eq!(bits.get(bit), true); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /presentations/redis-protobuf/slides.adoc: -------------------------------------------------------------------------------- 1 | = Redis-protobuf exercise 2 | 3 | link:./index.html[Table of Contents] 4 | 5 | 6 | == Cargo build scripts 7 | 8 | Some projects require additional steps to run before they can be built, e.g. for code generation. Cargo supports this by means of a `build.rs` file. 9 | 10 | == Cargo build scripts (cont.) 11 | 12 | * `build.rs` is itself written in Rust. It resides in the root directory of your package, *not* in `src/`. 13 | * it can have its own list of dependencies via `[build-dependencies]` 14 | * input is communicated via environment variables 15 | * output files should be written to `OUT_DIR` 16 | * Cargo behavior can be controlled by writing commands to stdout. 17 | 18 | == Cargo build scripts (cont.) 19 | 20 | Generated code is typically then included in another Rust source file: 21 | 22 | [source,rust] 23 | ---- 24 | pub mod generated { 25 | include!(concat!(env!("OUT_DIR"), "/generated.rs")); 26 | } 27 | ---- 28 | 29 | == Protocol buffers in Rust 30 | 31 | Several crates exist - we're going to use https://github.com/danburkert/prost[prost] here. 32 | 33 | == Prost usage 34 | 35 | By using `prost::Message` you get encode & decode functionality. 36 | [source,rust] 37 | ---- 38 | use prost::Message; 39 | // ... 40 | let mut buf = Vec::new(3); 41 | a_proto_object.encode(&mut buf)?; 42 | 43 | let another_proto_object = TheProtoObject::decode(a_vec.as_slice())?; 44 | ---- -------------------------------------------------------------------------------- /presentations/send-and-sync/1.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | 3 | #[derive(Debug)] 4 | struct Thing; 5 | 6 | // Can send between threads! 7 | fn main() { 8 | let thing = Thing; 9 | 10 | thread::spawn(move || { 11 | println!("{:?}", thing); 12 | }).join().unwrap(); 13 | } -------------------------------------------------------------------------------- /presentations/send-and-sync/2.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | use std::thread; 3 | 4 | // Does not work! 5 | fn main() { 6 | let only_one_thread = Rc::new(true); 7 | 8 | thread::spawn(move || { 9 | println!("{:?}", only_one_thread); 10 | }).join().unwrap(); 11 | } -------------------------------------------------------------------------------- /presentations/send-and-sync/3.output: -------------------------------------------------------------------------------- 1 | error[E0277]: the trait bound `std::rc::Rc: std::marker::Send` is not satisfied 2 | --> :7:5 3 | | 4 | 7 | thread::spawn(move || { 5 | | ^^^^^^^^^^^^^ the trait `std::marker::Send` is not implemented for `std::rc::Rc` -------------------------------------------------------------------------------- /presentations/send-and-sync/4.rs: -------------------------------------------------------------------------------- 1 | struct Thing(*mut String); 2 | 3 | unsafe impl Send for Thing {} 4 | unsafe impl Sync for Thing {} -------------------------------------------------------------------------------- /presentations/send-and-sync/5.rs: -------------------------------------------------------------------------------- 1 | unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {} -------------------------------------------------------------------------------- /presentations/send-and-sync/6.rs: -------------------------------------------------------------------------------- 1 | unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {} -------------------------------------------------------------------------------- /presentations/serde/1.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | 3 | #[derive(Debug, Serialize, Deserialize)] 4 | struct Move { 5 | id: usize, 6 | direction: Direction, 7 | } 8 | 9 | #[derive(Debug, Serialize, Deserialize)] 10 | enum Direction { North, South, East, West } 11 | 12 | fn main() {} -------------------------------------------------------------------------------- /presentations/serde/2.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | 3 | use Direction::*; 4 | 5 | fn main() { 6 | let action = Move { id: 1, direction: West }; 7 | let payload = serde_json::to_string(&action); 8 | println!("{:?}", payload); 9 | } 10 | 11 | #[derive(Debug, Serialize, Deserialize)] 12 | struct Move { 13 | id: usize, 14 | direction: Direction, 15 | } 16 | 17 | #[derive(Debug, Serialize, Deserialize)] 18 | enum Direction { North, South, East, West } -------------------------------------------------------------------------------- /presentations/serde/3.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let payload = "{\"id\":1,\"direction\":\"West\"}"; 3 | let action = serde_json::from_str::(&payload); 4 | println!("{:?}", action); 5 | } 6 | 7 | #[derive(Debug, Serialize, Deserialize)] 8 | struct Move { 9 | id: usize, 10 | direction: Direction, 11 | } 12 | 13 | #[derive(Debug, Serialize, Deserialize)] 14 | enum Direction { North, South, East, West } 15 | -------------------------------------------------------------------------------- /presentations/serde/4.rs: -------------------------------------------------------------------------------- 1 | use serde_transcode::transcode; 2 | 3 | fn main() { 4 | let payload = "{\"id\":1,\"direction\":\"West\"}"; 5 | let mut buffer = String::new(); 6 | { 7 | let mut ser = toml::Serializer::new(&mut buffer); 8 | let mut de = serde_json::Deserializer::from_str(&payload); 9 | transcode(&mut de, &mut ser) 10 | .unwrap(); 11 | } 12 | println!("{:?}", buffer); 13 | } -------------------------------------------------------------------------------- /presentations/serde/5.rs: -------------------------------------------------------------------------------- 1 | #[serde(deny_unknown_fields)] // Be extra strict 2 | struct Move { 3 | #[serde(default)] // Call usize::default() 4 | id: usize, 5 | #[serde(rename = "dir")] // Use a different name 6 | direction: Direction, 7 | } -------------------------------------------------------------------------------- /presentations/serde/slides.adoc: -------------------------------------------------------------------------------- 1 | = `serde` 2 | 3 | link:./index.html[Table of Contents] 4 | 5 | 6 | == **Ser**ialization and **De**serialization 7 | 8 | https://serde.rs/[https://serde.rs/] 9 | 10 | == `Serialize` & `Deserialize` 11 | 12 | To make a Rust structure (de)serializable: 13 | 14 | [source,rust] 15 | ---- 16 | include::./1.rs[] 17 | ---- 18 | 19 | == Formats 20 | 21 | Serde supports a number of formats, such as: 22 | 23 | * JSON 24 | * CBOR 25 | * YAML 26 | * TOML 27 | * BSON 28 | * MessagePack 29 | * ... More! 30 | 31 | Did you enjoy that acronym salad? 32 | 33 | == `Serialize` 34 | 35 | To JSON: 36 | 37 | [source,rust] 38 | ---- 39 | include::./2.rs[] 40 | ---- 41 | 42 | == `Deserialize` 43 | 44 | From JSON: 45 | 46 | [source,rust] 47 | ---- 48 | include::./3.rs[] 49 | ---- 50 | 51 | == Transcode 52 | 53 | [source,rust] 54 | ---- 55 | include::./4.rs[] 56 | ---- 57 | 58 | == Attributes 59 | 60 | `serde` has a large number of attributes you can utilize: 61 | 62 | [source,rust] 63 | ---- 64 | include::./5.rs[] 65 | ---- 66 | 67 | https://serde.rs/attributes.html[https://serde.rs/attributes.html] 68 | -------------------------------------------------------------------------------- /presentations/slides.css: -------------------------------------------------------------------------------- 1 | .reveal a { 2 | text-decoration: underline; 3 | } 4 | .reveal pre code { 5 | max-height: 800px; 6 | } 7 | .line-through { 8 | text-decoration: line-through; 9 | } 10 | .reveal .hljs-keyword { 11 | font-weight: bold; 12 | } 13 | .reveal .hljs-symbol { 14 | color: #20999D; 15 | background: none; 16 | font-style: italic; 17 | } 18 | 19 | .reveal pre code { 20 | padding: 20px; 21 | border: 1px solid #745d48; 22 | font-size: 1.4em; 23 | line-height: 1.4em; 24 | white-space: pre-wrap; 25 | } 26 | 27 | .open-in-playground { 28 | background: #a42; 29 | font-size: 125%; 30 | color: white; 31 | font-weight: 700; 32 | cursor: pointer; 33 | } 34 | -------------------------------------------------------------------------------- /presentations/smart-pointers/1.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | struct Point { 4 | x: i32, 5 | y: i32, 6 | } 7 | 8 | fn main() { 9 | let rced_point = Rc::new(Point { x: 1, y: 1}); 10 | let first_handle = rced_point.clone(); 11 | let second_handle = rced_point.clone(); 12 | } -------------------------------------------------------------------------------- /presentations/smart-pointers/2.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | struct Point { 4 | x: i32, 5 | y: i32, 6 | } 7 | 8 | fn main() { 9 | let rced_point = Rc::new(Point { x: 1, y: 1}); 10 | let first_handle = rced_point.clone(); 11 | let weak = Rc::downgrade(&first_handle); 12 | } -------------------------------------------------------------------------------- /presentations/stack-and-heap/1.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32 4 | } 5 | 6 | fn main() { 7 | let point = Point { x: 1, y: 1}; 8 | } -------------------------------------------------------------------------------- /presentations/stack-and-heap/2.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32 4 | } 5 | 6 | fn main() { 7 | let point = Point { x: 1, y: 1}; 8 | let point_on_heap = Box::new(point); 9 | } -------------------------------------------------------------------------------- /presentations/stack-and-heap/3.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct Point { 3 | x: i32, 4 | y: i32 5 | } 6 | 7 | fn main() { 8 | let point = Point { x: 1, y: 1}; 9 | let point_on_heap = Box::new(point); 10 | print_point(&point_on_heap); 11 | } 12 | 13 | fn print_point(p: &Point) { 14 | println!("{:?}", p); 15 | } -------------------------------------------------------------------------------- /presentations/stack-and-heap/slides.adoc: -------------------------------------------------------------------------------- 1 | = Stack and Heap 2 | 3 | link:./index.html[Table of Contents] 4 | 5 | 6 | == ! 7 | 8 | Rust defaults to allocation on the stack 9 | 10 | == Stack Allocation 11 | 12 | [source,rust] 13 | ---- 14 | include::./1.rs[] 15 | ---- 16 | 17 | == Box 18 | 19 | Heap allocation is represented by the type `Box`. 20 | 21 | [source,rust] 22 | ---- 23 | include::./2.rs[] 24 | ---- 25 | 26 | == Ownership and Borrowing 27 | 28 | `Box` is owned, but you can borrow the contained values. 29 | 30 | [source,rust] 31 | ---- 32 | include::./3.rs[] 33 | ---- 34 | 35 | == Other heap allocations 36 | 37 | Other types also allocate on the heap, most notably `Vec` and `String`. 38 | 39 | == Placement in 40 | 41 | It is currently *not* possible to allocate values at a self-chosen location. The missing feature is called "placement in". 42 | 43 | https://internals.rust-lang.org/t/lang-team-minutes-feature-status-report-placement-in-and-box/4646[Detailed discussion here] 44 | 45 | == ! 46 | 47 | In most cases, LLVM already optimizes the stack allocation and the subsequent move to the heap to a direct heap allocation. 48 | -------------------------------------------------------------------------------- /presentations/standard-types/1.rs: -------------------------------------------------------------------------------- 1 | enum Option { 2 | Some(T), 3 | None, 4 | } -------------------------------------------------------------------------------- /presentations/standard-types/10.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | fn main() { 4 | let mut kv_store = HashMap::new(); 5 | kv_store.insert("key", true); 6 | println!("{}", kv_store.get("key")); 7 | } -------------------------------------------------------------------------------- /presentations/standard-types/11.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | fn main() { 4 | let mut kv_store = HashMap::new(); 5 | let mut value = kv_store.entry("key").or_insert(true); 6 | *value = false; 7 | } -------------------------------------------------------------------------------- /presentations/standard-types/2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let values = vec![1, 2, 3]; 3 | println!("{:?}", values.get(0)); // Some(1) 4 | println!("{:?}", values.get(4)); // None 5 | } -------------------------------------------------------------------------------- /presentations/standard-types/3.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let nothing: Option = None; 3 | nothing.unwrap(); 4 | } -------------------------------------------------------------------------------- /presentations/standard-types/4.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let maybe_a_value = Some(1); 3 | match maybe_a_value { 4 | Some(v) => println!("{}", v), 5 | None => println!("None"), 6 | } 7 | } -------------------------------------------------------------------------------- /presentations/standard-types/5.rs: -------------------------------------------------------------------------------- 1 | enum Result { 2 | Ok(T), 3 | Err(E), 4 | } -------------------------------------------------------------------------------- /presentations/standard-types/6.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Err(e) = File::open("nein") { 3 | println!("{:?}", e); 4 | } 5 | } -------------------------------------------------------------------------------- /presentations/standard-types/7.rs: -------------------------------------------------------------------------------- 1 | struct Vec { 2 | items: T, 3 | length: usize, 4 | capacity: usize, 5 | } 6 | -------------------------------------------------------------------------------- /presentations/standard-types/8.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let explicit_type = Vec::::new(); 3 | let mut implicit_type = Vec::new(); 4 | implicit_type.push(1); 5 | let macro_created = vec![1, 2, 3]; 6 | } -------------------------------------------------------------------------------- /presentations/standard-types/9.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let items = vec![1, 2, 3]; 3 | let ref_to_items: &[usize] = &items; 4 | } -------------------------------------------------------------------------------- /presentations/std-lib-tour/1.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | fn main() { 4 | let mut map: HashMap<&str, u32> = HashMap::new(); 5 | map.entry("foo").or_insert(1); 6 | map.entry("bar").or_insert_with(|| { 7 | let mut value = 1; 8 | value += 1; 9 | value 10 | }); 11 | println!("{:?}", map); 12 | } -------------------------------------------------------------------------------- /presentations/std-lib-tour/2.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | struct HttpRequest { 4 | // Eventually returns this type. 5 | response_value: PhantomData, 6 | } 7 | 8 | fn main() {} -------------------------------------------------------------------------------- /presentations/std-lib-tour/3.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | fn main() { 4 | Command::new("ls") 5 | .args(&["-l", "-a"]) 6 | .spawn() 7 | .expect("ls command failed to start"); 8 | } -------------------------------------------------------------------------------- /presentations/std-lib-tour/4.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Mutex; 2 | 3 | fn main() { 4 | 5 | let mut mutex = Mutex::new(0); 6 | 7 | // Use a new scope to force a drop. 8 | { 9 | let mut val = mutex.get_mut().unwrap(); 10 | *val += 1; 11 | } 12 | 13 | println!("{}", *mutex.lock().unwrap()); 14 | } -------------------------------------------------------------------------------- /presentations/std-lib-tour/5.rs: -------------------------------------------------------------------------------- 1 | use std::io::{Read, Write}; 2 | 3 | fn main() { 4 | // File, Socket, Vector, ... 5 | let mut buffer: Vec = vec![]; 6 | 7 | buffer.write(b"some bytes").unwrap(); 8 | 9 | let mut read_in = String::new(); 10 | buffer.as_slice().read_to_string(&mut read_in).unwrap(); 11 | 12 | println!("{}", read_in); 13 | } -------------------------------------------------------------------------------- /presentations/std-lib-tour/6.rs: -------------------------------------------------------------------------------- 1 | use std::fs::{File, canonicalize}; 2 | use std::io::Write; 3 | 4 | fn main() { 5 | let mut file = File::create("foo.txt").unwrap(); 6 | file.write_all(b"Hello, world!").unwrap(); 7 | 8 | let path = canonicalize("foo.txt").unwrap(); 9 | 10 | let components: Vec<_> = path.components().collect(); 11 | println!("{:?}", components); 12 | } -------------------------------------------------------------------------------- /presentations/strings/1.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // &'static str 3 | let this = "Hello"; 4 | // String 5 | let that: String = String::from("Hello"); 6 | // &str 7 | let other = that.as_str(); 8 | } 9 | -------------------------------------------------------------------------------- /presentations/strings/2.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let part_one = String::from("Hello "); 3 | let part_two = String::from("there "); 4 | let whole = part_one + &part_two + "world!"; 5 | println!("{}", whole); 6 | } -------------------------------------------------------------------------------- /presentations/strings/3.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let words = "Cow says moo"; 3 | let each: Vec<_> = words.split(" ").collect(); 4 | println!("{:?}", each); 5 | } -------------------------------------------------------------------------------- /presentations/strings/4.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let animal = String::from("Cow"); 3 | let sound = String::from("moo"); 4 | let words = [&animal, " says ", &sound].concat(); 5 | println!("{:?}", words); 6 | } -------------------------------------------------------------------------------- /presentations/strings/5.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let words = "Cow says moo"; 3 | let replaced = words.replace("moo", "roar"); 4 | println!("{}", replaced); 5 | } -------------------------------------------------------------------------------- /presentations/strings/6.rs: -------------------------------------------------------------------------------- 1 | fn accept_either(thing: S) -> String 2 | where S: AsRef { 3 | String::from("foo") + thing.as_ref() 4 | } 5 | 6 | fn main() { 7 | println!("{}", accept_either("blah")); 8 | println!("{}", accept_either(String::from("blah"))); 9 | } -------------------------------------------------------------------------------- /presentations/strings/7.rs: -------------------------------------------------------------------------------- 1 | fn main () { 2 | let json = r##" 3 | { 4 | "name": "Rust Analyzer", 5 | "brandColor": "#5bbad5" 6 | } 7 | "##; 8 | assert_eq!(r"\n", "\\n"); 9 | } 10 | -------------------------------------------------------------------------------- /presentations/strings/8.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let byte_string: &[u8] = b"allows ASCII and \xF0\x9F\x98\x80 only"; 3 | println!("Can Debug fmt but not Display fmt: {:?}", byte_string); 4 | if let Ok(string) = std::str::from_utf8(byte_string) { 5 | println!("Now can Display '{}'", string); 6 | } 7 | } -------------------------------------------------------------------------------- /presentations/testing/1.rs: -------------------------------------------------------------------------------- 1 | enum Direction { North, South, East, West } 2 | 3 | fn is_north(dir: Direction) -> bool { 4 | match dir { 5 | Direction::North => true, 6 | _ => false, 7 | } 8 | } 9 | 10 | #[test] 11 | fn is_north_works() { 12 | assert!(is_north(Direction::North) == true); 13 | assert!(is_north(Direction::South) == false); 14 | } -------------------------------------------------------------------------------- /presentations/testing/2.bash: -------------------------------------------------------------------------------- 1 | $ cargo test 2 | running 1 test 3 | test is_north_works ... ok 4 | 5 | test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured -------------------------------------------------------------------------------- /presentations/testing/3.rs: -------------------------------------------------------------------------------- 1 | enum Direction { North, South, East, West } 2 | 3 | fn is_north(dir: Direction) -> bool { 4 | match dir { 5 | Direction::North => true, 6 | _ => false, 7 | } 8 | } 9 | 10 | #[cfg(test)] 11 | mod tests { 12 | use super::{is_north, Direction}; 13 | 14 | #[test] 15 | fn is_north_works() { 16 | assert!(is_north(Direction::North) == true); 17 | assert!(is_north(Direction::South) == false); 18 | } 19 | } -------------------------------------------------------------------------------- /presentations/testing/4.bash: -------------------------------------------------------------------------------- 1 | $ cargo test 2 | running 1 test 3 | test tests::is_north_works ... ok 4 | 5 | test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured -------------------------------------------------------------------------------- /presentations/testing/5.bash: -------------------------------------------------------------------------------- 1 | $ cargo test 2 | running 0 tests 3 | 4 | test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured 5 | 6 | Doc-tests example 7 | 8 | running 1 test 9 | test Direction_0 ... ok 10 | 11 | test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured -------------------------------------------------------------------------------- /presentations/testing/6.rs: -------------------------------------------------------------------------------- 1 | use example::{is_north, Direction}; 2 | 3 | #[test] 4 | fn is_north_works() { 5 | assert!(is_north(Direction::North) == true); // <1> 6 | assert!(is_north(Direction::South) == false); 7 | } 8 | -------------------------------------------------------------------------------- /presentations/testing/7.bash: -------------------------------------------------------------------------------- 1 | $ cargo test 2 | running 1 test 3 | test is_north_works ... ok 4 | 5 | test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured 6 | 7 | Running target/debug/deps/example-9f39afa5d2a1c6bf 8 | 9 | running 0 tests 10 | 11 | test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured 12 | 13 | Doc-tests example 14 | 15 | running 0 tests 16 | 17 | test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured -------------------------------------------------------------------------------- /presentations/traits/1.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct Point { 3 | x: i32, 4 | y: i32, 5 | } 6 | 7 | impl Point { 8 | fn new(x: i32, y: i32) -> Point { 9 | Point { x: x, y: y } 10 | } 11 | } 12 | 13 | fn main() { 14 | let my_point = Point::new(1, 2); 15 | println!("My point being: {:?}", my_point); 16 | } 17 | -------------------------------------------------------------------------------- /presentations/traits/2.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct Point { 3 | x: i32, 4 | y: i32, 5 | } 6 | 7 | impl Point { 8 | fn new(x: i32, y: i32) -> Point { 9 | Point { x: x, y: y } 10 | } 11 | 12 | fn from_pair(pair: (i32, i32)) -> Point { 13 | Point { 14 | x: pair.0, 15 | y: pair.1, 16 | } 17 | } 18 | 19 | fn into_pair(self) -> (i32, i32) { 20 | (self.x, self.y) 21 | } 22 | 23 | fn inspect(&self) { 24 | println!("Current point value: {:?}", self); 25 | } 26 | 27 | fn move_to(&mut self, x: i32, y: i32) { 28 | self.x = x; 29 | self.y = y; 30 | } 31 | 32 | fn x(&self) -> &i32 { 33 | &self.x 34 | } 35 | 36 | fn x_mut(&mut self) -> &mut i32 { 37 | &mut self.x 38 | } 39 | 40 | fn y(&self) -> &i32 { 41 | &self.y 42 | } 43 | 44 | fn y_mut(&mut self) -> &mut i32 { 45 | &mut self.y 46 | } 47 | } 48 | 49 | fn main() { 50 | let mut my_point = Point::new(1, 2); 51 | my_point.inspect(); 52 | my_point.move_to(2, 3); 53 | my_point.inspect(); 54 | 55 | let x = my_point.x_mut(); 56 | *x = 5; 57 | 58 | my_point.inspect(); 59 | } 60 | -------------------------------------------------------------------------------- /presentations/traits/3.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32 4 | } 5 | 6 | impl Point { 7 | fn new(x: i32, y: i32) -> Self { 8 | Point { x: x, y: y } 9 | } 10 | } -------------------------------------------------------------------------------- /presentations/traits/4.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32 4 | } 5 | 6 | trait Distance { 7 | fn distance(&self, other: &Self) -> f64; 8 | } 9 | 10 | impl Distance for Point { 11 | fn distance(&self, other: &Point) -> f64 { 12 | (((other.x - self.x).pow(2) + (other.y - self.y).pow(2)) as f64).sqrt() 13 | } 14 | } 15 | 16 | fn main() { 17 | let p1 = Point { x: 1, y: 1 }; 18 | let p2 = Point { x: 2, y: 2 }; 19 | println!("{}", p1.distance(&p2)); 20 | } -------------------------------------------------------------------------------- /presentations/traits/5.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32 4 | } 5 | 6 | trait Distance { 7 | fn distance(&self, other: &OtherShape) -> f64; 8 | } 9 | 10 | impl Distance for Point { 11 | fn distance(&self, other: &Point) -> f64 { 12 | (((other.x - self.x).pow(2) + (other.y - self.y).pow(2)) as f64).sqrt() 13 | } 14 | } 15 | 16 | fn main() { 17 | let p1 = Point { x: 1, y: 1 }; 18 | let p2 = Point { x: 2, y: 2 }; 19 | println!("{}", p1.distance(&p2)); 20 | } -------------------------------------------------------------------------------- /presentations/traits/6.rs: -------------------------------------------------------------------------------- 1 | struct Point { 2 | x: i32, 3 | y: i32 4 | } 5 | 6 | trait Distance { 7 | fn distance(&self, other: &OtherShape) -> f64; 8 | } 9 | 10 | impl Distance for Point { 11 | fn distance(&self, other: &Point) -> f64 { 12 | (((other.x - self.x).pow(2) + (other.y - self.y).pow(2)) as f64).sqrt() 13 | } 14 | } 15 | 16 | fn main() { 17 | let p1 = Point { x: 1, y: 1 }; 18 | let p2 = Point { x: 2, y: 2 }; 19 | println!("{}", >::distance(&p1, &p2)); 20 | } 21 | -------------------------------------------------------------------------------- /presentations/traits/7.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct Point { 3 | x: i32, 4 | y: i32 5 | } 6 | 7 | trait MyAddition { 8 | type Output; 9 | 10 | fn add(&self, other: &Other) -> Self::Output; 11 | } 12 | 13 | impl MyAddition for Point { 14 | type Output = Point; 15 | 16 | fn add(&self, other: &Point) -> Point { 17 | Point { x: self.x + other.x, y: self.y + other.y } 18 | } 19 | } 20 | 21 | fn main() { 22 | let p1 = Point { x: 1, y: 2 }; 23 | let p2 = Point { x: 1, y: 2 }; 24 | println!("{:?}", p1.add(&p2)) 25 | } -------------------------------------------------------------------------------- /presentations/unsafe/1.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | fn main() { 4 | let pointer_to_int = &mut 1; 5 | let raw = pointer_to_int as *mut i32; 6 | unsafe { deref_pointer(raw) }; 7 | } 8 | 9 | unsafe fn deref_pointer(p: *mut T) { 10 | println!("{:?}", *p) 11 | } 12 | -------------------------------------------------------------------------------- /presentations/unsafe/2.rs: -------------------------------------------------------------------------------- 1 | #[inline] 2 | fn split_at_mut(&mut self, mid: isize) -> (&mut [T], &mut [T]) { 3 | let len = self.len(); 4 | let ptr = self.as_mut_ptr(); 5 | 6 | unsafe { 7 | assert!(mid <= len); 8 | 9 | (from_raw_parts_mut(ptr, mid), 10 | from_raw_parts_mut(ptr.offset(mid), len - mid)) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /presentations/unsafe/vscode-settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.semanticTokenColorCustomizations": { 3 | "rules": { 4 | "*.unsafe:rust": "#ff00ff" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /presentations/wasm/2.bash: -------------------------------------------------------------------------------- 1 | $ rustup target install wasm32-unknown-unknown 2 | $ rustup target install wasm32-wasi 3 | -------------------------------------------------------------------------------- /presentations/wasm/3.bash: -------------------------------------------------------------------------------- 1 | curl https://wasmtime.dev/install.sh -sSf | bash 2 | -------------------------------------------------------------------------------- /presentations/wasm/4.bash: -------------------------------------------------------------------------------- 1 | $ cargo new hello-world 2 | $ cargo build --target wasm32-wasi 3 | $ wasmtime target/wasm32-wasi/debug/main.wasm 4 | -------------------------------------------------------------------------------- /presentations/working-with-nightly/1.bash: -------------------------------------------------------------------------------- 1 | cd /nightly_project 2 | rustup override set nightly -------------------------------------------------------------------------------- /presentations/working-with-nightly/2.rs: -------------------------------------------------------------------------------- 1 | #![feature(asm, no_std)] -------------------------------------------------------------------------------- /presentations/working-with-nightly/3.rs: -------------------------------------------------------------------------------- 1 | #![plugin(some_plugin)] -------------------------------------------------------------------------------- /rake: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | bundle exec rake $@ -------------------------------------------------------------------------------- /semver-codealong/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /semver-codealong/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "semver" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /semver-codealong/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "semver" 3 | version = "0.1.0" 4 | authors = ["Anatol Ulrich "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/01 hello Rust.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // NOTE start with cargo 3 | // $ cargo new 4 | // $ cargo run 5 | // $ cargo clean 6 | // $ cargo run -v 7 | 8 | // $EDITOR Cargo.toml, go through file 9 | 10 | println!("Hello, world!"); 11 | } 12 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/02 println, numbers.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // NOTE overflow, 32 bit, etc 3 | // TODO granularity? 4 | let an_int = 123; 5 | let a_big_int = 1_000_000_000_000; 6 | let a_float = 3.14; 7 | let a_string = "Hello, string!"; 8 | println!( 9 | "these are a few of my favorite things: {}, {}, {}, {}", 10 | an_int, a_big_int, a_float, a_string 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/03 return, if, call.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let result = say_hi("hello"); 3 | if result { 4 | println!("it was hello!"); 5 | } 6 | } 7 | 8 | fn say_hi(s: &str) -> bool { 9 | println!("I got a string: {}", s); 10 | if s == "hello" { 11 | let v: Vec<_> = vec![1]; 12 | // NOTE mention that semicolon here is an error 13 | true 14 | } else { 15 | false 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/04 structs.rs: -------------------------------------------------------------------------------- 1 | struct SemVer { 2 | major: u16, 3 | minor: u16, 4 | patch: u16, 5 | } 6 | 7 | fn main() { 8 | // NOTE use RA "fill in fields" 9 | // NOTE mention allow_unused ("attributes") 10 | // NOTE mention primitive types 11 | // NOTE no constructor 12 | // NOTE all fields are required, no uninit mem 13 | // TODO expand/more notes on memory safety and/or refer to SLIDE deck 14 | let version = SemVer { 15 | major: 1, 16 | minor: 2, 17 | patch: 7, 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/05 structs II - inference.rs: -------------------------------------------------------------------------------- 1 | // NOTE let participants recreate struct 2 | struct SemVer { 3 | major: u16, 4 | minor: u16, 5 | patch: u16, 6 | } 7 | 8 | fn main() { 9 | // NOTE show how type changes automatically 10 | // NOTE two kinds of type annotation for primitives (on variable, or on the literal) 11 | // NOTE no default/uninit memory -- compiler error when not all fields specified 12 | // LATER b"strings" 13 | 14 | let major_number = 1; 15 | let minor = 2; 16 | 17 | let _version = SemVer { 18 | major: major_number, 19 | minor: minor, 20 | patch: 7, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/06 structs III - constructors.rs: -------------------------------------------------------------------------------- 1 | struct SemVer { 2 | major: u16, 3 | minor: u16, 4 | patch: u16, 5 | } 6 | 7 | impl SemVer { 8 | // NOTE purely convention 9 | fn new(major: u16, minor: u16, patch: u16) -> SemVer { 10 | SemVer { 11 | major, 12 | minor, 13 | patch, 14 | } 15 | } 16 | } 17 | fn main() { 18 | let major_number = 1; 19 | let minor = 2; 20 | 21 | // NOTE return type of constructor: SemVer or Self 22 | let _version = SemVer::new(major_number, minor, 5); 23 | } 24 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/07 structs IV - derive Debug.rs: -------------------------------------------------------------------------------- 1 | // NOTE many things can be derived, we'll see more later 2 | // NOTE traits can be derived or manually implemented 3 | // NOTE keep "trait" really short here - let's say this is an 4 | // "aspect of functionality", similar to "interface" in other langs 5 | #[derive(Debug)] 6 | struct SemVer { 7 | major: u16, 8 | minor: u16, 9 | patch: u16, 10 | } 11 | 12 | fn main() { 13 | let version = SemVer { 14 | major: 1, 15 | minor: 2, 16 | patch: 7, 17 | }; 18 | 19 | // NOTE go back to 02 println (with primitives) 20 | // - primitives and field access treated the same 21 | println!( 22 | "we are at version {}.{}.{}", 23 | version.major, version.minor, version.patch 24 | ); 25 | 26 | // NOTE maybe also mention {:?} 27 | println!("we are at version {:?}", version); 28 | 29 | // LATER impl Display 30 | } 31 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/08 structs V - impl block.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct SemVer { 3 | major: u16, 4 | minor: u16, 5 | patch: u16, 6 | } 7 | 8 | impl SemVer { 9 | // NOTE talk about &ref later in more detail 10 | // NOTE also about consuming self 11 | fn info(&self) { 12 | println!( 13 | "I am at version {}.{}.{}", 14 | self.major, self.minor, self.patch 15 | ); 16 | } 17 | } 18 | 19 | fn main() { 20 | let version = SemVer { 21 | major: 1, 22 | minor: 2, 23 | patch: 7, 24 | }; 25 | 26 | println!("we are at version {:?}", version); 27 | 28 | // NOTE first explain Debug, then vvvv this 29 | println!( 30 | "we are at version {}.{}.{}", 31 | version.major, version.minor, version.patch 32 | ); 33 | 34 | version.info(); 35 | 36 | // LATER impl Display 37 | } 38 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/08a_enum_and_match.rs: -------------------------------------------------------------------------------- 1 | struct SemVer { 2 | major: u16, 3 | minor: u16, 4 | patch: u16, 5 | } 6 | 7 | #[derive(PartialEq, Eq)] 8 | enum Maturity { 9 | Alpha, 10 | Beta, 11 | Stable, 12 | } 13 | 14 | impl SemVer { 15 | fn maturity(&self) -> Maturity { 16 | if self.major == 0 { 17 | if self.minor == 0 { 18 | Maturity::Alpha 19 | } else { 20 | Maturity::Beta 21 | } 22 | } else { 23 | Maturity::Stable 24 | } 25 | } 26 | } 27 | 28 | fn main() { 29 | let version = SemVer { 30 | major: 1, 31 | minor: 2, 32 | patch: 7, 33 | }; 34 | 35 | if version.maturity() == Maturity::Stable { 36 | println!("looks stable to me!"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/09 mutability.rs: -------------------------------------------------------------------------------- 1 | struct SemVer { 2 | major: u16, 3 | minor: u16, 4 | patch: u16, 5 | } 6 | 7 | fn main() { 8 | let version = SemVer { 9 | major: 1, 10 | minor: 2, 11 | patch: 7, 12 | }; 13 | 14 | // TODO add BROKEN tag? 15 | // NOTE code breaks intentionally, show broken version first, 16 | // then fix 17 | // NOTE this is to showcase the helpfulness of compiler errors 18 | version.patch = 8; 19 | version.patch += 1; 20 | } 21 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/10 ownership.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct SemVer { 3 | major: u16, 4 | minor: u16, 5 | patch: u16, 6 | } 7 | 8 | fn main() { 9 | let version = SemVer { 10 | major: 1, 11 | minor: 2, 12 | patch: 7, 13 | }; 14 | 15 | print_version(version); 16 | } 17 | 18 | fn print_version(version: SemVer) { 19 | println!("we are at version {:?}", version); 20 | } 21 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/11 ownership II.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct SemVer { 3 | major: u16, 4 | minor: u16, 5 | patch: u16, 6 | } 7 | 8 | fn main() { 9 | let version = SemVer { 10 | major: 1, 11 | minor: 2, 12 | patch: 7, 13 | }; 14 | 15 | print_version(version); 16 | // NOTE ownership, consume 17 | // NOTE stack vs heap (TODO: big jump!) 18 | // LINK https://doc.rust-lang.org/book/ch04-03-slices.html 19 | // TODO depending on participants' previous lang experience, 20 | // maybe branch out to "just quickly cover" vs "all the nitty gritty" 21 | // TODO expand, expand, expand 22 | 23 | // BROKEN why does this break? 24 | print_version(version); 25 | 26 | // NOTE Copy, Clone, hand object back and forth (possible - but unusual) 27 | } 28 | 29 | fn print_version(version: SemVer) { 30 | println!("we are at version {:?}", version); 31 | } 32 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/12 references.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct SemVer { 3 | major: u16, 4 | minor: u16, 5 | patch: u16, 6 | } 7 | 8 | fn main() { 9 | let version = SemVer { 10 | major: 1, 11 | minor: 2, 12 | patch: 7, 13 | }; 14 | 15 | print_version(&version); 16 | increment_version(&version); 17 | print_version(&version); 18 | } 19 | 20 | fn print_version(version: &SemVer) { 21 | println!("we are at version {:?}", version); 22 | } 23 | 24 | fn increment_version(version: &SemVer) { 25 | // BROKEN 26 | // NOTE immutable vs mutable refs 27 | // TERMINOLOGY shared vs exclusive more exact, but 28 | // sticking with (im)mutable for beginners - just briefly mention 29 | // shared/exclusive 30 | version.patch += 1; 31 | } 32 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/13 borrowing.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct SemVer { 3 | major: u16, 4 | minor: u16, 5 | patch: u16, 6 | } 7 | 8 | fn main() { 9 | let mut version = SemVer { 10 | major: 1, 11 | minor: 2, 12 | patch: 7, 13 | }; 14 | 15 | // NOTE introduce borrow visualization here 16 | // LINK https://github.com/rustviz/rustviz 17 | let version_ref = &mut version; 18 | print_version(&version); 19 | increment_version(version_ref); 20 | print_version(&version); 21 | } 22 | 23 | fn print_version(version: &SemVer) { 24 | println!("we are at version {:?}", version); 25 | } 26 | 27 | fn increment_version(version: &mut SemVer) { 28 | version.patch += 1; 29 | } 30 | 31 | // EXERCISE (group) 32 | // - fn inc_major(&mut SemVer) 33 | // - fn inc_major(&mut self) 34 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/14 tuples, collections.rs: -------------------------------------------------------------------------------- 1 | // !UNFINISHED 2 | // IMPL 3 | // - fn destructure (introduce tuples first) 4 | 5 | #[derive(Debug)] 6 | struct SemVer { 7 | major: u16, 8 | minor: u16, 9 | patch: u16, 10 | } 11 | 12 | // TODO too much at once here 13 | impl From<[u16; 3]> for SemVer { 14 | fn from(arr: [u16; 3]) -> Self { 15 | SemVer { 16 | major: arr[0], 17 | minor: arr[1], 18 | patch: arr[2], 19 | } 20 | } 21 | } 22 | 23 | fn main() { 24 | // NOTE first show arrays 25 | } 26 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/15 iterators.rs: -------------------------------------------------------------------------------- 1 | // UNFINISHED 2 | // (duh) 3 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/16 strings.rs: -------------------------------------------------------------------------------- 1 | struct SemVer { 2 | major: u16, 3 | minor: u16, 4 | patch: u16, 5 | } 6 | 7 | // TODO too much at once 8 | impl From<&str> for SemVer { 9 | fn from(s: &str) -> Self { 10 | let parts = s 11 | .split(".") 12 | .filter_map(|b| b.parse().ok()) 13 | .collect::>(); 14 | SemVer { 15 | major: parts[0], 16 | minor: parts[1], 17 | patch: parts[2], 18 | } 19 | } 20 | } 21 | 22 | fn main() { 23 | let sv: SemVer = "1.2.3".into(); 24 | } 25 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/17 From String.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferrous-systems/teaching-material/81806ce816ac550fb27667542d0bdb0ab5c59bc5/semver-codealong/src/bin/17 From String.rs -------------------------------------------------------------------------------- /semver-codealong/src/bin/xx default, phantom.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | #[derive(Debug, Default)] 3 | struct S { 4 | i: i32, 5 | p: PhantomData, 6 | } 7 | fn main() { 8 | println!("Hello, world!"); 9 | let s: S = S { 10 | i: 5, 11 | ..Default::default() 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/xx_documentation.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferrous-systems/teaching-material/81806ce816ac550fb27667542d0bdb0ab5c59bc5/semver-codealong/src/bin/xx_documentation.rs -------------------------------------------------------------------------------- /semver-codealong/src/bin/xx_enum_and_match.rs: -------------------------------------------------------------------------------- 1 | struct SemVer { 2 | major: u16, 3 | minor: u16, 4 | patch: u16, 5 | } 6 | 7 | #[derive(PartialEq, Eq)] 8 | enum Maturity { 9 | Alpha, 10 | Beta, 11 | Stable, 12 | } 13 | 14 | impl SemVer { 15 | fn maturity(&self) -> Maturity { 16 | if self.major == 0 { 17 | if self.minor == 0 { 18 | Maturity::Alpha 19 | } else { 20 | Maturity::Beta 21 | } 22 | } else { 23 | Maturity::Stable 24 | } 25 | } 26 | } 27 | 28 | fn main() { 29 | let version = SemVer { 30 | major: 1, 31 | minor: 2, 32 | patch: 7, 33 | }; 34 | 35 | if version.maturity() == Maturity::Stable { 36 | println!("looks stable to me!"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/xx_impl_display.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | #[derive(Debug)] 4 | struct SemVer { 5 | major: u16, 6 | minor: u16, 7 | patch: u16, 8 | } 9 | 10 | impl Display for SemVer { 11 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 12 | write!(f, "{}.{}.{}", self.major, self.minor, self.patch) 13 | } 14 | } 15 | 16 | fn main() { 17 | let version = SemVer { 18 | major: 1, 19 | minor: 2, 20 | patch: 7, 21 | }; 22 | 23 | println!("we are at version {:?}", version); 24 | println!("we are at version {}", version); 25 | } 26 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/xx_lifetimes.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Default)] 2 | struct SemVer { 3 | major: u16, 4 | minor: u16, 5 | patch: u16, 6 | } 7 | 8 | struct Crate<'c> { 9 | name: String, 10 | release_history: Vec<&'c SemVer>, 11 | } 12 | 13 | fn main() { 14 | let version = SemVer::default(); 15 | 16 | let release_history = vec![&version]; 17 | 18 | let c = Crate { 19 | name: "hello".to_string(), 20 | release_history, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /semver-codealong/src/bin/xx_modules.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferrous-systems/teaching-material/81806ce816ac550fb27667542d0bdb0ab5c59bc5/semver-codealong/src/bin/xx_modules.rs -------------------------------------------------------------------------------- /semver-codealong/src/bin/xx_test.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferrous-systems/teaching-material/81806ce816ac550fb27667542d0bdb0ab5c59bc5/semver-codealong/src/bin/xx_test.rs --------------------------------------------------------------------------------