├── .bundle └── config ├── .gitignore ├── Gemfile ├── LICENSE ├── LICENSE-CODE ├── Makefile ├── README.md ├── book ├── book.adoc ├── chapters │ ├── chapter-0-introduction.adoc │ ├── chapter-1-rustup.adoc │ ├── chapter-10-traits.adoc │ ├── chapter-11-module-system.adoc │ ├── chapter-12-strings-part2.adoc │ ├── chapter-13-result-and-option.adoc │ ├── chapter-14-managing-errors.adoc │ ├── chapter-15-closures.adoc │ ├── chapter-16-lifetimes-and-references.adoc │ ├── chapter-17-arrays-loops-and-iterators.adoc │ ├── chapter-18-async.adoc │ ├── chapter-19-starting-a-project.adoc │ ├── chapter-2-cargo.adoc │ ├── chapter-20-cli-args-and-logging.adoc │ ├── chapter-21-building-and-running-webassembly.adoc │ ├── chapter-22-using-json.adoc │ ├── chapter-23-arc-rc-mutex-and-rwlock.adoc │ ├── chapter-24-crates-and-tools.adoc │ ├── chapter-3-vscode.adoc │ ├── chapter-4-hello-world.adoc │ ├── chapter-5-ownership.adoc │ ├── chapter-6-strings-part1.adoc │ ├── chapter-7-syntax-and-language.adoc │ ├── chapter-8-types-hashmaps-and-structs.adoc │ ├── chapter-9-structs-and-behavior.adoc │ └── preface.adoc └── images │ ├── cliff of comprehension.png │ ├── cover.png │ ├── cover.svg │ ├── devtools-gc.png │ ├── node-to-rust-vscode-settings.png │ ├── vs-code-conversion-error.png │ ├── vs-code-crates.gif │ ├── vs-code-debugging.png │ ├── vs-code-impl-error.png │ ├── vs-code-impl-error2.png │ ├── vs-code-inlay-hints.png │ ├── vs-code-ownership.png │ ├── vs-code-private-module.png │ ├── vs-code-quick-code-impl-display.png │ ├── vs-code-quick-code-implement-members.png │ └── vs-code-quick-code-import.png ├── from-javascript-to-rust.epub ├── from-javascript-to-rust.pdf └── src ├── Cargo.lock ├── Cargo.toml ├── crates ├── day-10 │ └── traits │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── day-11 │ ├── modules │ │ ├── Cargo.toml │ │ └── src │ │ │ └── nested-submodules.rs │ └── traffic-light │ │ ├── Cargo.toml │ │ └── src │ │ ├── light.rs │ │ ├── light │ │ ├── house_light.rs │ │ └── traffic_light.rs │ │ └── main.rs ├── day-12 │ ├── impl-asref-str │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── impl-tostring │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── day-13 │ ├── option │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── question-mark │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── result │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── day-14 │ ├── boxed-errors │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── custom-error-type │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── error-chain │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── from-into │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── snafu │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── thiserror │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── day-15 │ └── closures │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── day-16 │ ├── elision │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── static-bounds │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── static │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── type-differences │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── impl-borrowed.rs │ │ │ └── impl-owned.rs │ └── unsafe-pointers │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── day-17 │ ├── arrays │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── iterators │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── names │ │ ├── Cargo.toml │ │ └── src │ │ ├── main.rs │ │ └── names.json ├── day-18 │ └── async │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ ├── async-blocks.rs │ │ ├── error.rs │ │ ├── fs.rs │ │ ├── lazy.rs │ │ ├── send-sync.rs │ │ └── simple.rs ├── day-19 │ └── project │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── crates │ │ ├── cli │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ │ └── my-lib │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── day-20 │ └── project │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── crates │ │ ├── cli │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ │ └── my-lib │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── day-21 │ ├── project │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── crates │ │ │ ├── cli │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── main.rs │ │ │ └── my-lib │ │ │ ├── .gitignore │ │ │ ├── Cargo.toml │ │ │ ├── src │ │ │ ├── error.rs │ │ │ └── lib.rs │ │ │ └── tests │ │ │ └── test.wasm │ └── wapc-guest │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── Makefile │ │ ├── build │ │ └── wapc_guest.wasm │ │ ├── codegen.yaml │ │ ├── schema.widl │ │ └── src │ │ ├── generated.rs │ │ └── lib.rs ├── day-22 │ ├── project │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── blog.hbs │ │ ├── blog.json │ │ ├── blog.wasm │ │ ├── crates │ │ │ ├── cli │ │ │ │ ├── Cargo.toml │ │ │ │ └── src │ │ │ │ │ └── main.rs │ │ │ └── my-lib │ │ │ │ ├── .gitignore │ │ │ │ ├── Cargo.toml │ │ │ │ ├── src │ │ │ │ ├── error.rs │ │ │ │ └── lib.rs │ │ │ │ └── tests │ │ │ │ └── test.wasm │ │ └── hello.json │ ├── serde │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── wapc-guest │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── Makefile │ │ ├── build │ │ └── wapc_guest.wasm │ │ ├── codegen.yaml │ │ ├── schema.widl │ │ └── src │ │ ├── generated.rs │ │ └── lib.rs ├── day-23 │ └── rc-arc │ │ ├── Cargo.toml │ │ └── src │ │ ├── arc.rs │ │ ├── async.rs │ │ ├── rc.rs │ │ ├── references.rs │ │ └── rwlock.rs ├── day-4 │ ├── hello-world │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── strings-wtf-1 │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── strings-wtf-2 │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── day-5 │ ├── borrowing │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ │ ├── borrow.rs │ │ │ └── mutable-borrow.rs │ └── let-vs-const │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ ├── reassigning-rebind.rs │ │ ├── reassigning-wrong-type.rs │ │ └── reassigning.rs ├── day-6 │ └── loads-of-strs │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ ├── 200-empty-prints.rs │ │ ├── 200-prints.rs │ │ ├── 200-unique-prints.rs │ │ └── one-print.rs ├── day-7 │ └── syntax │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── day-8 │ ├── maps │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── structs │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs └── day-9 │ └── structs │ ├── Cargo.toml │ └── src │ └── main.rs └── javascript ├── day-10 ├── package-lock.json ├── package.json └── src │ └── mixins.js ├── day-15 ├── package-lock.json ├── package.json ├── src │ └── closures.ts └── tsconfig.json ├── day-17 ├── package-lock.json ├── package.json ├── src │ ├── arrays.ts │ └── iterators.ts └── tsconfig.json ├── day-5 ├── let-vs-const │ ├── package.json │ └── reassigning.js └── references │ ├── index.js │ └── package.json ├── day-8 ├── package-lock.json ├── package.json ├── src │ ├── maps.ts │ └── structs.ts └── tsconfig.json └── day-9 ├── package-lock.json ├── package.json ├── src └── structs.ts └── tsconfig.json /.bundle/config: -------------------------------------------------------------------------------- 1 | --- 2 | BUNDLE_PATH: "vendor/bundle" 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | **/*/.DS_Store 3 | **/*/node_modules 4 | vendor 5 | .bundle 6 | Gemfile.lock 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "asciidoctor" 4 | gem "asciidoctor-pdf" 5 | gem "rouge" 6 | gem "asciidoctor-epub3", "~> 1.5" 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Enforce bash as the shell for consistency 2 | SHELL := bash 3 | # Use bash strict mode 4 | .SHELLFLAGS := -eu -o pipefail -c 5 | MAKEFLAGS += --warn-undefined-variables 6 | MAKEFLAGS += --no-builtin-rules 7 | 8 | .PHONY: book 9 | book: 10 | bundle exec asciidoctor-pdf -a source-highlighter=rouge book/book.adoc --o from-javascript-to-rust.pdf 11 | 12 | .PHONY: book-epub 13 | book-epub: 14 | bundle exec asciidoctor-epub3 -a source-highlighter=rouge book/book.adoc --o from-javascript-to-rust.epub 15 | 16 | .PHONY: deps 17 | deps: 18 | bundle install 19 | 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # From JavaScript to Rust ebook 2 | 3 | This repository houses an ebook-ified version of the 24+ post series started on [vino.dev](https://vino.dev/blog/node-to-rust-day-1-rustup/). 4 | 5 | ## How to build 6 | 7 | The ebook is built using [asciidoctor](https://docs.asciidoctor.org/) and requires ruby >2.3. 8 | 9 | Install the ruby dependencies via `make deps` 10 | 11 | ```console 12 | $ make deps 13 | ``` 14 | 15 | Build a PDF via the command `make book` 16 | 17 | ```console 18 | $ make book 19 | ``` 20 | 21 | ## Running code and projects 22 | 23 | All code are housed in the `src/` directory. 24 | 25 | ### Day 4 26 | 27 | - `cargo run -p day-4-hello-world` 28 | - `cargo run -p day-4-strings-wtf-1` - intentionally does not compile. 29 | - `cargo run -p day-4-strings-wtf-2` - intentionally does not compile. 30 | 31 | ### Day 5 32 | 33 | #### Reassigning 34 | 35 | - JS: `node javascript/day-5/let-vs-const/reassigning.js` 36 | - Rust: `cargo run -p day-5-let-vs-const --bin reassigning` 37 | - `cargo run -p day-5-let-vs-const --bin reassigning-wrong-type` - intentionally does not compile 38 | 39 | #### Borrowing 40 | 41 | - `cargo run -p day-5-borrowing --bin borrow` 42 | - `cargo run -p day-5-borrowing --bin mutable-borrow` - intentionally does not compile 43 | 44 | ### Day 6 45 | 46 | - `cargo run -p day-6-loads-of-strs --bin 200-unique-prints` 47 | - `cargo run -p day-6-loads-of-strs --bin 200-prints` 48 | - `cargo run -p day-6-loads-of-strs --bin 200-empty-prints` 49 | - `cargo run -p day-6-loads-of-strs --bin one-print` 50 | 51 | ### Day 7 52 | 53 | #### Syntax 54 | 55 | - `cargo run -p day-7-syntax` 56 | 57 | ### Day 8 58 | 59 | #### Maps 60 | 61 | - `ts-node javascript/day-8/src/maps.ts` 62 | - `cargo run -p day-8-maps` 63 | 64 | #### Structs 65 | 66 | - `ts-node javascript/day-8/src/structs.ts` 67 | - `cargo run -p day-8-structs` 68 | 69 | ### Day 9 70 | 71 | ### Day 10 72 | 73 | ### Day 11 74 | 75 | #### Modules 76 | 77 | - `cargo run -p day-11-modules --bin nested-submodules` 78 | - `cargo run -p day-11-traffic-light` 79 | 80 | ### Day 12 81 | 82 | - `cargo run -p day-12-impl-tostring` 83 | - `cargo run -p day-12-impl-asref-str` 84 | 85 | ### Day 13 86 | 87 | - `cargo run -p day-13-option` 88 | - `cargo run -p day-13-result` 89 | - `cargo run -p day-13-question-mark` 90 | 91 | ### Day 14 92 | 93 | #### From/Into 94 | 95 | - `cargo run -p day-14-from-into` 96 | 97 | #### Errors 98 | 99 | These examples require setting an environment variable. How to do that in your environment might look different. 100 | 101 | - `MARKDOWN=README.md cargo run -p day-14-boxed-errors` 102 | - `MARKDOWN=README.md cargo run -p day-14-custom-error-type` 103 | - `MARKDOWN=README.md cargo run -p day-14-thiserror` 104 | - `MARKDOWN=README.md cargo run -p day-14-error-chain` 105 | - `MARKDOWN=README.md cargo run -p day-14-snafu` 106 | 107 | ### Day 16 108 | 109 | #### Closures 110 | 111 | - `cargo run -p day-15-closures` 112 | 113 | ### Day 16 114 | 115 | #### Type differences 116 | 117 | - `cargo run -p day-16-type-differences --bin impl-owned` 118 | - `cargo run -p day-16-type-differences --bin impl-borrowed` 119 | 120 | #### `'static` 121 | 122 | - `cargo run -p day-16-static` - intentionally does not compile 123 | - `cargo run -p day-16-static-bounds` - intentionally does not compile 124 | 125 | #### Lifetime elision 126 | 127 | - `cargo run -p day-16-elision` 128 | 129 | #### Unsafe pointers 130 | 131 | - `cargo run -p day-16-unsafe-pointers` 132 | 133 | ### Day 17 134 | 135 | #### Arrays 136 | 137 | - `cargo run -p day-17-arrays` 138 | - `ts-node javascript/day-17/src/arrays.ts` 139 | 140 | #### Iterators 141 | 142 | - `cargo run -p day-17-iterators` 143 | - `ts-node javascript/day-17/src/iterators.ts` 144 | 145 | #### Names example 146 | 147 | - `cargo run -p day-17-names` 148 | 149 | ### Day 18 150 | 151 | - `cargo run -p day-18-async --bin send-sync` 152 | - `cargo run -p day-18-async --bin simple` 153 | - `cargo run -p day-18-async --bin lazy` 154 | - `cargo run -p day-18-async --bin fs` 155 | - `cargo run -p day-18-async --bin async-blocks` 156 | 157 | ### Day 19 158 | 159 | First you must cd into `crates/day-19/project` 160 | 161 | - `cargo test` 162 | - `cargo run -p cli` 163 | 164 | ### Day 20 165 | 166 | First you must cd into `crates/day-20/project` 167 | 168 | - `RUST_LOG=cli=debug cargo run -p cli` 169 | 170 | ### Day 21 171 | 172 | #### waPC runner 173 | 174 | First you must cd into `crates/day-21/project` 175 | 176 | - `cargo run -p cli -- crates/my-lib/tests/test.wasm hello "Potter"` 177 | 178 | #### waPC guest (hello) 179 | 180 | First you must cd into `crates/day-21/wapc-guest` 181 | 182 | - Build with `make` 183 | 184 | ### Day 22 185 | 186 | #### Serde 187 | 188 | - `cargo run -p day-22-serde` 189 | 190 | #### waPC runner 191 | 192 | First you must cd into `crates/day-22/project` 193 | 194 | - `cargo run -p cli -- crates/my-lib/tests/test.wasm hello hello.json` 195 | - `cargo run -p cli -- ./blog.wasm render ./blog.json` 196 | 197 | #### waPC guest (blog) 198 | 199 | First you must cd into `crates/day-22/wapc-guest` 200 | 201 | - Build with `make` 202 | 203 | ### Day 23 204 | 205 | - `cargo run -p day-23-rc-arc --bin references` 206 | - `cargo run -p day-23-rc-arc --bin rc` 207 | - `cargo run -p day-23-rc-arc --bin arc` 208 | - `cargo run -p day-23-rc-arc --bin rwlock` 209 | - `cargo run -p day-23-rc-arc --bin async` - intentionally does not compile 210 | 211 | ## License 212 | 213 | Book: Creative Commons BY-NC 4.0 214 | Code: Creative Commons BY 4.0 215 | -------------------------------------------------------------------------------- /book/book.adoc: -------------------------------------------------------------------------------- 1 | :author: Jarrod Overson 2 | :email: jsoverson@gmail.com 3 | :revnumber: v0.1 4 | :revdate: 02.22.2022 5 | :notitle: 6 | :doctype: book 7 | :chapter-label: 8 | :toc: left 9 | :toclevels: 2 10 | :sectnums: |,all| 11 | :toc-title: Table of Contents 12 | :front-cover-image: image::images/cover.png[leveloffset=0] 13 | :description: Learn Rust by mapping what you already know from JavaScript and node.js to their counterparts in the Rust ecosystem 14 | 15 | = Go From JavaScript to Rust 16 | 17 | include::./chapters/preface.adoc[leveloffset=1] 18 | include::./chapters/chapter-0-introduction.adoc[leveloffset=1] 19 | include::./chapters/chapter-1-rustup.adoc[leveloffset=1] 20 | include::./chapters/chapter-2-cargo.adoc[leveloffset=1] 21 | include::./chapters/chapter-3-vscode.adoc[leveloffset=1] 22 | include::./chapters/chapter-4-hello-world.adoc[leveloffset=1] 23 | include::./chapters/chapter-5-ownership.adoc[leveloffset=1] 24 | include::./chapters/chapter-6-strings-part1.adoc[leveloffset=1] 25 | include::./chapters/chapter-7-syntax-and-language.adoc[leveloffset=1] 26 | include::./chapters/chapter-8-types-hashmaps-and-structs.adoc[leveloffset=1] 27 | include::./chapters/chapter-9-structs-and-behavior.adoc[leveloffset=1] 28 | include::./chapters/chapter-10-traits.adoc[leveloffset=1] 29 | include::./chapters/chapter-11-module-system.adoc[leveloffset=1] 30 | include::./chapters/chapter-12-strings-part2.adoc[leveloffset=1] 31 | include::./chapters/chapter-13-result-and-option.adoc[leveloffset=1] 32 | include::./chapters/chapter-14-managing-errors.adoc[leveloffset=1] 33 | include::./chapters/chapter-15-closures.adoc[leveloffset=1] 34 | include::./chapters/chapter-16-lifetimes-and-references.adoc[leveloffset=1] 35 | include::./chapters/chapter-17-arrays-loops-and-iterators.adoc[leveloffset=1] 36 | include::./chapters/chapter-18-async.adoc[leveloffset=1] 37 | include::./chapters/chapter-19-starting-a-project.adoc[leveloffset=1] 38 | include::./chapters/chapter-20-cli-args-and-logging.adoc[leveloffset=1] 39 | include::./chapters/chapter-21-building-and-running-webassembly.adoc[leveloffset=1] 40 | include::./chapters/chapter-22-using-json.adoc[leveloffset=1] 41 | include::./chapters/chapter-23-arc-rc-mutex-and-rwlock.adoc[leveloffset=1] 42 | include::./chapters/chapter-24-crates-and-tools.adoc[leveloffset=1] 43 | -------------------------------------------------------------------------------- /book/chapters/chapter-0-introduction.adoc: -------------------------------------------------------------------------------- 1 | = Introduction 2 | 3 | == A guide to Rust from a node.js developer's perspective. 4 | 5 | Each chapter will take concepts you know in JavaScript and node.js and translate them to their Rust counterparts. The first chapters start with the basics, like getting set up with Rust via a tool similar to `nvm` (`rustup`), using the package manager (`cargo`), and setting up VS Code. Later chapters go over language gotchas, how to perform common JavaScript tasks in Rust, and we'll finish up by touching on solid dependencies to start adding to your projects. 6 | 7 | == Wait, why does anyone need to learn anything but JavaScript? 8 | 9 | I _love_ JavaScript. I've been coding JavaScript it since I first saw it in Netscape. I've written more lines of JavaScript than any other language. I'm a fan, but I know where the language falls short. It's fast, but not that fast. It's easy to write, but easy to screw up. Large projects become unwieldy fast. TypeScript helps scale JavaScript but it adds its own complexity and still doesn't make anything faster. Server-side JavaScript relies on node.js which is common but not ubiquitous. If you want to distribute something self-contained, there aren't great answers. 10 | 11 | When you start stretching passed what JavaScript is best at, it's helpful to have another language to turn to. 12 | 13 | == Why Rust? 14 | 15 | You could use C, C{pp}, C#, Go, Java, Kotlin, Haskell or a hundred others. Rust is notoriously difficult even for system programmers to get into. Why bother with Rust? Think about your languages as tools in your toolbox. When you fill your toolbox, you don't want 10 tools that solve similar problems. You want tools that complement each other and give you the ability to fix everything an anything. You already have JavaScript, a developer super-tool. It's a high level language that's good enough to run just about everything everywhere. If you're picking up a new language, you might as well go to the extreme and pick a no-compromise, low-level powerhouse. 16 | 17 | Also, WebAssembly. 18 | 19 | Rust's tooling and support for WebAssembly is better than everything else out there. You can rewrite CPU-heavy JavaScript logic into Rust and run it as WebAssembly. Which basically makes you a superhero. With JavaScript and Rust, there's nothing you can't handle. 20 | 21 | == How to use this book 22 | 23 | This book is not a deep, comprehensive Rust tutorial. It's meant to bootstrap experienced programmers into Rust. We'll take common node.js workflows and idiomatic JavaScript and TypeScript and map them to their Rust counterparts. This book balances technical accuracy with readability. It errs on the side of "gets the point across" vs being 100% correct. When something is glossed over, we'll add links for those looking to dive deeper. 24 | -------------------------------------------------------------------------------- /book/chapters/chapter-1-rustup.adoc: -------------------------------------------------------------------------------- 1 | = Installing rust with `rustup` 2 | 3 | https://github.com/nvm-sh/nvm[nvm] (or https://github.com/coreybutler/nvm-windows[nvm-windows]) are indispensible tools. They manage seamlessly installing and switching between versions of node.js on the same system. 4 | 5 | The equivalent in Rust's world is https://rustup.rs/[rustup]. 6 | 7 | Rustup manages your Rust installation as well as additonal targets (like WebAssembly) and core tools like `cargo` (Rust's `npm`), `clippy` (Rust's `eslint`), `rustfmt` (Rust's `prettier`). 8 | 9 | After installing `rustup`, run it without any subcommands and explore what it has to offer. 10 | 11 | [source,text] 12 | ---- 13 | $ rustup 14 | rustup 1.24.3 (ce5817a94 2021-05-31) 15 | The Rust toolchain installer 16 | 17 | USAGE: 18 | rustup [FLAGS] [+toolchain] 19 | 20 | FLAGS: 21 | -v, --verbose Enable verbose output 22 | -q, --quiet Disable progress output 23 | -h, --help Prints help information 24 | -V, --version Prints version information 25 | 26 | ARGS: 27 | <+toolchain> release channel (e.g. +stable) or custom toolchain to set override 28 | 29 | SUBCOMMANDS: 30 | show Show the active and installed toolchains or profiles 31 | update Update Rust toolchains and rustup 32 | check Check for updates to Rust toolchains and rustup 33 | default Set the default toolchain 34 | toolchain Modify or query the installed toolchains 35 | target Modify a toolchain's supported targets 36 | component Modify a toolchain's installed components 37 | override Modify directory toolchain overrides 38 | run Run a command with an environment configured for a given toolchain 39 | which Display which binary will be run for a given command 40 | doc Open the documentation for the current toolchain 41 | man View the man page for a given command 42 | self Modify the rustup installation 43 | set Alter rustup settings 44 | completions Generate tab-completion scripts for your shell 45 | help Prints this message or the help of the given subcommand(s) 46 | 47 | DISCUSSION: 48 | Rustup installs The Rust Programming Language from the official 49 | release channels, enabling you to easily switch between stable, 50 | beta, and nightly compilers and keep them updated. It makes 51 | cross-compiling simpler with binary builds of the standard library 52 | for common platforms. 53 | 54 | If you are new to Rust consider running `rustup doc --book` to 55 | learn Rust. 56 | ---- 57 | 58 | `rustup show` will show you what is currently installed. 59 | 60 | `rustup completions` will help you enable CLI autocompletion for tools like `rustup` and `cargo`. 61 | 62 | `rustup component` lets you add additonal components. 63 | 64 | `rustup update` will update you to the latest version. 65 | 66 | `rustup install stable|nightly|1.57` will install a specific version or the latest stable/nightly versions. 67 | 68 | By default, rustup will install the latest version of `rust` and `cargo` and you should be ready to go right away. Give it a shot with. 69 | 70 | [source,sh] 71 | ---- 72 | $ rustc --version 73 | rustc 1.57.0 (59eed8a2a 2021-11-01) 74 | 75 | $ cargo --version 76 | cargo 1.56.0 (4ed5d137b 2021-10-04) 77 | ---- 78 | 79 | If it doesn't work, you may need to restart your shell to update your PATH. 80 | 81 | == `rust-toolchain.toml` 82 | 83 | Specifying your toolchain with rustup is easy enough. As you get deeper, you may get into configurations where different projects require different toolchains or Rust versions. That's where `rust-toolchain.toml` comes into play. Specify your project's required toolchain, targets, and supporting tools here so that `cargo` and `rustup` can work automagically, e.g. 84 | 85 | `toml {title = "rust-toolchain.toml"} 86 | [toolchain] 87 | channel = "1.56.0" 88 | components = [ "rustfmt", "clippy" ] 89 | ` 90 | 91 | == Next steps 92 | 93 | Next up we'll take a look at `cargo`, Rust's `npm` and the additional tools that will help reach parity with common workflows: link:./chapter-2-cargo.adoc[Chapter 2: From npm to cargo]. 94 | -------------------------------------------------------------------------------- /book/chapters/chapter-12-strings-part2.adoc: -------------------------------------------------------------------------------- 1 | = Strings, Part 2 2 | 3 | == Introduction 4 | 5 | Now that you're getting confident, you are probably itching to start your own projects. You know how to write some basic Rust. You know how to structure code. You're done with contrived examples with traffic lights. As you play around and start writing your API, you'll inevitably write some function that needs an owned `String`. That's easy. We've done that before. Then it hits you... 6 | 7 | Your API, dotted with functions like below: 8 | 9 | [source,rust] 10 | ---- 11 | fn my_beautiful_function(arg1: String, arg2: String, arg3: String) { 12 | /* ... */ 13 | } 14 | ---- 15 | 16 | forces your users to write code like this 17 | 18 | [source,rust] 19 | ---- 20 | my_beautiful_function( 21 | "first".to_owned(), 22 | "second".to_owned(), 23 | "third".to_owned() 24 | ); 25 | ---- 26 | 27 | It's so ugly. I just couldn't believe it at first. All I wanted was to create a satisfying API that could take a `String` as well as string literals. I didn't want to make my users do things like add `.to_owned()` all over the place. It's madness. It's hideous. 28 | 29 | I spent a long time tracking down what to do. This is my story. 30 | 31 | == Should I use `&str` or `String` for my function arguments? 32 | 33 | The first question you need to ask is: "Do I need to own or borrow the passed value?" 34 | 35 | For those of you still wrapping your head around owning and borrowing, think of this question as: "Do I need my own version of this value or do I just need to look at its data and move on?" 36 | 37 | === When you're borrowing the value 38 | 39 | If you _don't_ need your own version, then accept a reference. The main question then becomes "Should I use `&str` or ``&String``" and the answer is almost always `&str`. Why? Well look at the function below. 40 | 41 | [source,rust] 42 | ---- 43 | fn print_str(msg: &str) { 44 | println!("{}", msg); 45 | } 46 | ---- 47 | 48 | You can pass a string literal directly, a `&str` assigned to a variable, and you can pass a reference to a `&String` which works automagically. 49 | 50 | [source,rust] 51 | ---- 52 | fn main() { 53 | let string_slice = "String slice assigned to variable"; 54 | let real_string = "Genuine String".to_owned(); 55 | print_str(string_slice); 56 | print_str("Literal slice"); 57 | print_str(&real_string); 58 | } 59 | ---- 60 | 61 | Why? Because the trait https://github.com/Rust-lang/Rust/blob/88e5ae2dd3cf4a0bbb5af69ef70e80d5dc7b462c/library/alloc/src/str.rs#L198[`Borrow` is implemented for `String`]. Anywhere you need a borrowed `str`, you can use a borrowed `String` without any hassle. The reverse is not true. If you change the function signature to accept a `&String` and try to pass a `&str`, you'll get a compile error. 62 | 63 | === When you need an owned value 64 | 65 | If you need an owned value then you need a `String` but there are a couple things to consider. 66 | 67 | . It is cumbersome to manually convert loads of ``&str``s to `String`. This is a genuine problem when you want to expose a satisfying, easy to use API. The example in the introduction is contrived but it is exactly what you'll deal with frequently. 68 | . You should let the users of your API decide how to create owned values for you. In other words, you shouldn't simply accept ``&str``s everywhere and convert them yourself. The user may have better ways of getting you the data. 69 | 70 | Here's where you want to think about your API. Are you looking to own a string that comes from _wherever_? Or do you expect your functions to be called with a mix of string literals and/or ``String``s? 71 | 72 | If it's the former, then you're not really looking for a `&str` _or_ a `String`. You're looking for something that has a `.to_string()` method. That is, you're looking for something that implements `ToString`. Types that implement `ToString` are common, you get it for free by implementing `Display`. 73 | 74 | If it's the latter, then you're looking for the common ground between a `String` and `&str`, which we found clues to in the section above. 75 | 76 | ==== For functions that accept potentially generated strings 77 | 78 | For a function that accepts arbitrary strings from anywhere -- generated or non -- you can accept arguments that implement `ToString`. 79 | 80 | [source,rust] 81 | ---- 82 | use std::str::FromStr; // Imported to use Ipv4Addr::from_str 83 | 84 | fn main() { 85 | let ip_address = std::net::Ipv4Addr::from_str("127.0.0.1").unwrap(); 86 | let string_proper = "String proper".to_owned(); 87 | let string_slice = "string slice"; 88 | needs_string(string_slice); 89 | needs_string("Literal string"); 90 | needs_string(string_proper); 91 | needs_string(ip_address); 92 | } 93 | 94 | fn needs_string(almost_string: T) { 95 | let real_string = almost_string.to_string(); 96 | println!("{}", real_string); 97 | } 98 | ---- 99 | 100 | We talked about `impl [trait]` vs `dyn [trait]` in the last chapter but now I through in new syntax above. This is Rust's generic syntax. The function `needs_string` above could have been written like this: 101 | 102 | [source,rust] 103 | ---- 104 | fn needs_string(almost_string: impl ToString) { 105 | let real_string = almost_string.to_string(); 106 | println!("{}", real_string); 107 | } 108 | ---- 109 | 110 | Nothing would need to change in the code. What's the difference? Very little. `impl [trait]` in argument position is less powerful than generic syntax. Rust also has a `where` keyword which you can use to make the same thing yet another way: 111 | 112 | [source,rust] 113 | ---- 114 | fn needs_string(string: T) 115 | where 116 | T: ToString, 117 | { 118 | println!("{}", string); 119 | } 120 | ---- 121 | 122 | There's zero difference between the `where` syntax and the `` syntax. Adding the separate `where` clause is for readability. 123 | 124 | ==== For functions that expect a mix of string literals and ``String``s 125 | 126 | If you didn't read this section, you wouldn't lose much. Using the `ToString` method covers a lot of cases. You do however open your users up to the same concerns we described with using `.to_string()` to convert `&str` to `String` in link:./chapter-6-strings-part1.adoc[Chapter 6: Strings, Part 1]. Many structs implement `Display`. A user could pass a lot of objects to the function above without the compiler complaining. Additionally, implementations of `.to_string()` may not always be cheap. Your users don't necessarily know the internals of your code. You might be doing a lot of extra work for no good reason. 127 | 128 | Since we already learned that a `&String` can take the place of a `&str`, we can generalize our inputs to anything that can be borrowed like a `str`. 129 | 130 | You _could_ use anything that implements `Borrow` and the below would work. However, you should accept anything that implements `AsRef` instead. What's the difference? Borrow assumes more and can fail, `AsRef` assumes little and explicitly *must not fail*. There are more differences but they don't matter for our usage here. 131 | 132 | The below is extremely similar to the above but notice that our `ip_address` is no longer a valid argument. Just because it has a printable string form doesn't mean it can be trivially taken as a `str` reference. 133 | 134 | [source,rust] 135 | ---- 136 | use std::str::FromStr; // Imported to use Ipv4Addr::from_str 137 | 138 | fn main() { 139 | let ip_address = std::net::Ipv4Addr::from_str("127.0.0.1").unwrap(); 140 | let string_slice = "string slice"; 141 | let string_proper = "String proper".to_owned(); 142 | needs_string(string_slice); 143 | needs_string("Literal string"); 144 | needs_string(string_proper); 145 | // needs_string(ip_address); // Fails now 146 | } 147 | 148 | fn needs_string>(almost_string: T) { 149 | let real_string = almost_string.as_ref().to_owned(); 150 | println!("{}", real_string); 151 | } 152 | ---- 153 | 154 | === Additional reading 155 | 156 | * https://doc.rust-lang.org/book/ch10-00-generics.html[The Rust Book: ch 10] 157 | * https://doc.rust-lang.org/rust-by-example/generics.html[Rust by Example: Generics] 158 | * https://doc.rust-lang.org/reference/items/generics.html[The Rust Reference: Generic Parameters] 159 | 160 | == Wrap-up 161 | 162 | Strings used to seem so simple. We were so naive. I bet every time you dive back into node.js your eyes are going to tear up with joy. Eventually you'll have the same feeling with Rust. You'll appreciate how protective Rust is and how fast everything runs. Rust and JavaScript truly are a beautiful pair. 163 | 164 | Next up we'll dive into error handling, the `Option` enum, and the `Result` enum. -------------------------------------------------------------------------------- /book/chapters/chapter-2-cargo.adoc: -------------------------------------------------------------------------------- 1 | = From npm to cargo 2 | 3 | == Introduction 4 | 5 | `cargo` is Rust's package manager and operates similarly to `npm` from node's universe. Cargo downloads dependiencs from https://crates.io[crates.io] by default. You can register an account and publish modules just as you would on https://npmjs.com[npmjs.com]. With some minor mapping you can translate almost everything you're used to in node to Rust. 6 | 7 | == `npm` to `cargo` mapping 8 | 9 | [discrete] 10 | ==== Project settings file 11 | 12 | In node.js you have `package.json`. In Rust you have `Cargo.toml`. 13 | 14 | Cargo's manifest format is https://toml.io/en/[toml] rather than the JSON you're used to with npm's package.json. Cargo uses the `Cargo.toml` file to know what dependencies to download, how to run tests, and how to build your projects (https://doc.rust-lang.org/cargo/reference/manifest.html[among other things]). 15 | 16 | [discrete] 17 | ==== Bootstrapping new projects 18 | 19 | In node.js it's `npm init`. In Rust you have `cargo init` and `cargo new` 20 | 21 | `cargo init` will initialize the current directory. `cargo new` initializes projects in a new directory. 22 | 23 | [discrete] 24 | ==== Installing dependencies 25 | 26 | In node.js it's `npm install [dep]`. In Rust you can use `cargo add [dep]` if you install https://github.com/killercup/cargo-edit[`cargo-edit`] first. Note: *_not_* cargo-add, just in case you come across it. 27 | 28 | $ cargo install cargo-edit 29 | 30 | This gives you four new commands: `add`, `rm`, `upgrade`, and `set-version` 31 | 32 | [discrete] 33 | ==== Installing tools globally 34 | 35 | In node.js it's `npm install --global`. In Rust you have `cargo install`. 36 | 37 | Downloading, building, and placing executables in cargo's bin directory is handled with `cargo install`. If you installed rust via `rustup` then these are placed in a local user directory (usually `~/.cargo/bin`). You don't need to `sudo cargo install` anything. 38 | 39 | [discrete] 40 | ==== Running tests 41 | 42 | In node.js it's `npm test`. In Rust you have `cargo test`. 43 | 44 | Cargo automates the running of unit tests, integration tests, and document tests through the `cargo test` command. There's a lot to Rust testing that we'll get to in later chapters. 45 | 46 | [discrete] 47 | ==== Publishing modules 48 | 49 | In node.js it's `npm publish`. In Rust you have `cargo publish`. 50 | 51 | Easy peasy. You'll need to have an account on https://crates.io[crates.io] and set up the authentication details but cargo will help you there. 52 | 53 | [discrete] 54 | ==== Running tasks 55 | 56 | In node.js it's `npm run xxx`. In Rust, it depends... You have commands for common tasks but the rest is up to you. 57 | 58 | In node.js you might use `npm run start` to run your server or executable. In Rust you would use `cargo run`. You can even use `cargo run --example xxx` to automatically run example code. 59 | 60 | In node.js you might use `npm run benchmarks` to profile your code. In Rust you have `cargo bench`. 61 | 62 | In node.js you might use `npm run build` to run webpack, tsc, or whatever. In Rust you have `cargo build`. 63 | 64 | In node.js you might use `npm run clean` to remove temporary or generated files. In Rust you have `cargo clean` which will wipe away your build folder (`target`, by default). 65 | 66 | In node.js you might use `npm run docs` to generate documentation. In Rust you have `cargo doc`. 67 | 68 | For code generation or pre-build steps, cargo supports https://doc.rust-lang.org/cargo/reference/build-scripts.html[build scripts] which run before the main build. 69 | 70 | A lot of your use cases are covered by default, but for anything else you have to fend for yourself. 71 | 72 | ``npm``'s built-in task runner is one of the reasons why you rarely see ``Makefile``s in JavaScript projects. In the Rust ecosystem, you're not as lucky. Makefiles are still common but https://github.com/casey/just[`just`] is an attractive option that is gaining adoption. It irons out a lot of the wonkiness of ``Makefile``s while keeping a similar syntax. 73 | 74 | Install `just` via 75 | 76 | $ cargo install just 77 | 78 | Other alternatives include `cargo-make` and `cargo-cmd`. I liked `cargo make` at first but its builtin tasks became just as annoying as ``make``'s. I've become skilled writing ``Makefile``s but I wish I spent that time learning `just` so take a lesson from me and start there. If you do go the `Makefile` route, check out https://gist.github.com/isaacs/62a2d1825d04437c6f08[isaacs's tutorial] and read https://tech.davis-hansson.com/p/make/[_Your makefiles are wrong_]. 79 | 80 | === Workspaces & monorepos 81 | 82 | Both package managers use a workspace concept to help you work with multiple small modules in a large project. In Rust, you create a `Cargo.toml` file in the root directory with a `[workspace]` entry that describes what's included and excluded in the workspace. It could be as simple as 83 | 84 | [source,toml] 85 | ---- 86 | [workspace] 87 | members = [ 88 | "crates/*" 89 | ] 90 | ---- 91 | 92 | Workspace members that depend on each other can then just point to the local directory as their dependency, e.g. 93 | 94 | [source,toml] 95 | ---- 96 | [dependencies] 97 | other-project = { path = "../other-project" } 98 | ---- 99 | 100 | Check `cargo-workspaces` in the next section for a tool to help manage cargo workspaces. 101 | 102 | === Additional tools 103 | 104 | ==== `cargo-edit` 105 | 106 | If you skimmed the above portion, make sure you don't miss out on `cargo-edit` which adds `cargo add` and `cargo rm` (among others) to help manage dependencies on the command line. 107 | 108 | Install `cargo-edit` via 109 | 110 | $ cargo install cargo-edit 111 | 112 | ==== `cargo-workspaces` 113 | 114 | `cargo workspaces` (or `cargo ws`) simplifies creating and managing workspaces and their members. It was inspired by node's `lerna` and picks up where `cargo` leaves off. One of its most valuable features is automating the publish of a workspace's members, replacing local dependencies with the published versions. 115 | 116 | Install `cargo-workspaces` via 117 | 118 | $ cargo install cargo-workspaces 119 | 120 | *_*note*_*: *workspaces* is plural. Don't install cargo-workspace expecting the same functionality. 121 | 122 | ==== `cargo-expand` 123 | 124 | Macros in Rust are so common that 100% of the logic in your first Hello World app will be wrapped up into one. They're great at hand waving away code you don't want to write repeatedly but they can make code hard to follow and troubleshoot. `cargo expand` helps pull back the curtain. 125 | 126 | `cargo-expand` needs a nightly toolchain installed which you can get by running 127 | 128 | ---- 129 | rustup install nightly 130 | ---- 131 | 132 | Install `cargo-expand` via 133 | 134 | $ cargo install cargo-expand 135 | 136 | Once installed, you can run `cargo expand [item]` to print out the fully generated source that rustc compiles. 137 | 138 | NOTE: `cargo expand` takes a *named item*, not a file path. Running `cargo expand main` doesn't expand `src/main.rs`, it expands the `main()` function in your project's root. With a common layout, to expand a module found in a file like `src/some_module/another.rs`, you'd run `cargo expand some_module::another`. Don't worry, we'll go over the module system in a few days. 139 | 140 | If you ran the `cargo new` command above to test it out, this is what your `src/main.rs` probably looks like. 141 | 142 | [source,rust] 143 | ---- 144 | fn main() { 145 | println!("Hello, world!"); 146 | } 147 | ---- 148 | 149 | `println!()` is a macro. Use `cargo expand` to see what code it generates. 150 | 151 | $ cargo expand main 152 | fn main() { 153 | { 154 | ::std::io::_print(::core::fmt::Arguments::new_v1( 155 | &["Hello, world!\n"], 156 | &match () { 157 | () => [], 158 | }, 159 | )); 160 | }; 161 | } 162 | 163 | ==== `tomlq` 164 | 165 | While not a `cargo xxx` command, it's useful for querying data in `.toml` files like `Cargo.toml`. It's a less featureful sibling to the amazing `jq`. It's not critical, but it's worth knowing about. 166 | 167 | == Wrap-up 168 | 169 | The `npm` → `cargo` mapping is straightforward when you add `cargo-edit` and accept the lack of a standard task runner. In the next chapter we'll go over how to get your environment working with Visual Studio Code: link:./chapter-3-vscode.adoc[Chapter 3: Setting up VS Code]. 170 | -------------------------------------------------------------------------------- /book/chapters/chapter-24-crates-and-tools.adoc: -------------------------------------------------------------------------------- 1 | = Crates & Valuable Tools 2 | 3 | == Introduction 4 | 5 | Hopefully you've become comfortable enough with Rust that you want to continue your journey. Rust is hard to get into but it's worth it. I've found that I can build _massive_ projects with a fraction of the unit tests I'm used to writing. Rust handles so many error cases at the compilation stage. Writing Rust is like pair programming with a grumpy old developer who catches _everything_. 6 | 7 | Now you need to start building up your suite of core dependencies, the crates you rely on repeatedly and become part of your personal toolbox. These are a few of the crates in mine. 8 | 9 | == Crates 10 | 11 | === Data 12 | 13 | * https://serde.rs[serde] - Data serialization ecosystem. 14 | * https://docs.serde.rs/serde_json/[serde_json] - JSON parsing and stringification. 15 | * https://docs.rs/parking_lot/latest/parking_lot/index.html[parking_lot] - Better Rust `Mutex` and `RwLock`. 16 | * https://docs.rs/once_cell/latest/once_cell/index.html[once_cell] - When you think you want global variables. 17 | 18 | === Error handling 19 | 20 | * https://docs.rs/thiserror/latest/thiserror/[thiserror] - Easy custom errors. 21 | * https://docs.rs/anyhow/latest/anyhow/[anyhow] - Easy generic errors. 22 | 23 | === Logging 24 | 25 | * https://docs.rs/log/latest/log/[log] - Logging facade that abstracts logging usage away from the logger implementation. 26 | * https://docs.rs/env_logger/latest/env_logger/[env_logger] - Easy console logging controlled by an environment variable. 27 | * https://docs.rs/test-log/latest/test_log/[test-log] - Get `env_logger`-style output in your tests without worrying about initializing a logger. 28 | * https://github.com/seanmonstar/pretty-env-logger[pretty-env-logger] - `env_logger`, but _prettier_. 29 | * https://github.com/tokio-rs/tracing[tracing] - a drop-in replacement for `log` and `env_logger` with expanded capabilities and first-class async support. 30 | 31 | === CLI 32 | 33 | * https://docs.rs/structopt/latest/structopt/[structopt] - CLI arguments from configuration. 34 | * https://docs.rs/clap/latest/clap/[clap] - CLI arguments from code. 35 | 36 | === Async/concurrency 37 | 38 | * https://docs.rs/tokio/latest/tokio/[tokio] - Async runtime. 39 | * https://docs.rs/tokio-stream/latest/tokio_stream/[tokio-stream] - Stream utilities for Tokio. 40 | * https://docs.rs/async-trait/latest/async_trait/[async-trait] - For when you try to make traits with async methods. 41 | * https://docs.rs/crossbeam/latest/crossbeam/[crossbeam] - bidirectional communication channels and more. 42 | 43 | === Web 44 | 45 | * https://rocket.rs[rocket] - An HTTP server with a great developer experience. 46 | * https://github.com/seanmonstar/reqwest[reqwest] - an easy-to-use HTTP client. 47 | * https://github.com/hyperium/hyper[hyper] - a fast and correct HTTP implementation. 48 | 49 | === Functionality you expected in the standard library 50 | 51 | * https://docs.rs/rand/latest/rand/[rand] - random number generator and related tools. 52 | * https://docs.rs/regex/latest/regex/[regex] - Regular expressions. 53 | * https://docs.rs/base64/latest/base64/[base64] - Base64 implementation. 54 | * https://docs.rs/http/latest/http/[http] - A general purpose library of common HTTP types. 55 | 56 | === Misc & tools 57 | 58 | * https://docs.rs/uuid/latest/uuid/[uuid] - UUID implementation. 59 | * https://docs.rs/itertools/latest/itertools/[itertools] - Additional iterator functions and macros. 60 | * https://docs.rs/maplit/latest/maplit/[maplit] - `hashmap!{}` macro like `vec![]` 61 | * https://docs.rs/cfg-if/latest/cfg_if/[cfg-if] - Macros to simplify mutually exclusive conditional compilation `#[cfg]` attributes. 62 | * https://github.com/casey/just[`just`] - a better `make`. 63 | 64 | == Additional reading 65 | 66 | * https://cheats.rs[Rust Language Cheatsheet] 67 | * https://github.com/rust-unofficial/awesome-rust[Awesome Rust list] 68 | * https://rust-unofficial.github.io/patterns/[Rust Design Patterns] 69 | * https://dtolnay.github.io/rust-quiz/[Rust Quiz] 70 | 71 | == Wrap-up 72 | 73 | During this book I learned that Rust has a curse. Once you learn "The Rust Way" of doing things, you get amnesia. You forget how to program any other way. This curse leads to documentation and examples that naturally skirt around problems 99% of new developers will experience in practice. I found myself unable to replicate several errors that were major roadblocks in my early Rust journey. 74 | 75 | The Rust curse is why it's critical that *_you_* are part of the Rust community. *_You_* are the only one that can help. You have a fresh perspective and run into real new-user problems. When you get stuck, reduce your code down to a minimally reproducible example and save it. When you eventually fix it, write about what you changed! If you don't like writing, can't figure something out, or are unsure about your fix, send it to link:mailto:jarrod@vino.dev[me]. I would be honored to take your experience and write about it. 76 | -------------------------------------------------------------------------------- /book/chapters/chapter-3-vscode.adoc: -------------------------------------------------------------------------------- 1 | = Setting up Visual Studio Code 2 | 3 | == Introduction 4 | 5 | https://code.visualstudio.com/[Visual Studio Code] dominated the JavaScript ecosystem almost on arrival. If you haven't yet given it a shot, you should. You won't find the breadth of plugins with Rust as you do with JavaScript, but it's growing rapidly. The most important pieces are there with features like: 6 | 7 | * code completion/intellisense 8 | * inline warnings 9 | * debugger 10 | * automatic refactor actions 11 | * automatic documentation tooltips 12 | * jump to definition, implementation, type, et al 13 | 14 | == Core language setup 15 | 16 | There are two primary plugins, *rust* (https://marketplace.visualstudio.com/items?itemName=rust-lang.rust[rust-lang.rust]) and *rust-analyzer* (https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer[matklad.rust-analyzer]). They promise similar features but I could never get the *rust* plugin to work reliably. *Rust-analyzer* has been great from day one. 17 | 18 | WARNING: The *rust* (https://marketplace.visualstudio.com/items?itemName=rust-lang.rust[rust-lang.rust]) and *rust-analyzer* (https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer[matklad.rust-analyzer]) plugins don't work well together. If you are exploring both, make sure you disable one to get a fair view of the other. 19 | 20 | To install *rust-analyzer*, search for it in the extensions pane or press `Ctrl+Shift+P` then enter: 21 | 22 | [source,sh] 23 | ---- 24 | ext install matklad.rust-analyzer 25 | ---- 26 | 27 | Once you're installed and rust-analyzer has downloaded everything it needs, you should be good to go. Note: you must be in a properly structured Rust project for rust-analyzer to work. You can't open just any `.rs` file and expect full IDE functionality, which brings us to... 28 | 29 | === If things don't feel like they're working... 30 | 31 | If you create a new file in a Rust project, e.g. `my_module.rs`, you'll notice that VS Code & rust-analyzer do _something_ but seem to be broken. They do complain about incorrect syntax, but they don't autocomplete anything and don't issue warnings about obviously incorrect code. That's because Rust projects ('crates') rely on a formal structure stemming from the root. That is to say, files can't get checked unless they are imported all the way down to a root source file (e.g. a `main.rs` or `lib.rs`). We'll get into the module system in a later chapter. You can alleviate this now by including your module via a line like `mod my_module`. 32 | 33 | === Notable rust-analyzer settings 34 | 35 | You can edit your settings via a UI or as JSON by opening the command palette with `Ctrl+Shift+P`, typing `settings` and selecting which you want. See the https://code.visualstudio.com/docs/getstarted/settings[VS Code documentation] for more info. 36 | 37 | image::./images/node-to-rust-vscode-settings.png[VS Code settings in the command palette] 38 | 39 | The UI is a great way to explore settings, while JSON is more convenient for rapid editing and sharing. The settings below assume JSON. 40 | 41 | ==== Additional linting 42 | 43 | By default, rust-analyzer runs `cargo check` on save to gather project errors and warnings. `cargo check` essentially just compiles your project looking for errors. If you want more, then you're looking for `clippy`. Clippy is like the ESlint of the Rust universe. Get clippy via `rustup component add clippy` (you may notice you have it already). 44 | 45 | You can run `cargo clippy` yourself or set rust-analyzer to run `clippy` on save to get loads of additional warnings and lints. Keep in mind that this takes additional resources and can be a bit slower, but it's worth it. I found `clippy` indispensible when learning Rust. It frequently highlights patterns that could be better replaced with more idiomatic or performant Rust. 46 | 47 | [source,json] 48 | ---- 49 | { 50 | "rust-analyzer.checkOnSave.command": "clippy" 51 | } 52 | ---- 53 | 54 | ==== Inlay hints can be disabled 55 | 56 | For me, rust-analyzer's inlay hints add too much noise. I turn them off. 57 | 58 | image::./images/vs-code-inlay-hints.png[Inlay hints] 59 | 60 | It's a matter of preference. Just know that it's configurable if you look at your source and think "whoa, what is going on." The first setting here disables everything, but you can disable individual hints with lines that follow. 61 | 62 | [source,json] 63 | ---- 64 | { 65 | "rust-analyzer.inlayHints.enable": false, 66 | "rust-analyzer.inlayHints.chainingHints": false, 67 | "rust-analyzer.inlayHints.parameterHints": false 68 | } 69 | ---- 70 | 71 | ==== Prompt before downloading updates 72 | 73 | Rust-analyzer keeps itself up to date automatically, but I like controlling that behavior in my applications. Sometimes I'm on a flight's WiFi, a mobile hotspot, or some other shaky internet and it's nice to have the control. You can control this by changing the setting below. 74 | 75 | [source,json] 76 | ---- 77 | { 78 | "rust-analyzer.updates.askBeforeDownload": true 79 | } 80 | ---- 81 | 82 | == Additional extensions 83 | 84 | === https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb[vscode-lldb] 85 | 86 | You'll need to install https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb[vadimcn.vscode-lldb] before you can meaningfully debug Rust applications. 87 | 88 | image::./images/vs-code-debugging.png[Debugging] 89 | 90 | Install with `Ctrl+Shift+P` then: 91 | 92 | [source,sh] 93 | ---- 94 | ext install vadimcn.vscode-lldb 95 | ---- 96 | 97 | === https://marketplace.visualstudio.com/items?itemName=bungcip.better-toml[better-toml] 98 | 99 | https://marketplace.visualstudio.com/items?itemName=bungcip.better-toml[bungcip.better-toml] adds syntax highlighting for TOML files 100 | 101 | Install with `Ctrl+Shift+P` then: 102 | 103 | [source,sh] 104 | ---- 105 | ext install bungcip.better-toml 106 | ---- 107 | 108 | === https://marketplace.visualstudio.com/items?itemName=serayuzgur.crates[crates] 109 | 110 | https://marketplace.visualstudio.com/items?itemName=serayuzgur.crates[serayuzgur.crates] shows you the latest versions of your dependencies and gives you quick access to update them. 111 | 112 | image./images/blog/node-to-rust/vs-code-crates.gif[Inline crate versions] 113 | 114 | Install with `Ctrl+Shift+P` then: 115 | 116 | [source,sh] 117 | ---- 118 | ext install serayuzgur.crates 119 | ---- 120 | 121 | === https://marketplace.visualstudio.com/items?itemName=belfz.search-crates-io[search-crates-io] 122 | 123 | https://marketplace.visualstudio.com/items?itemName=belfz.search-crates-io[belfz.search-crates-io] attempts to autocomplete dependencies as you write them in your Cargo.toml. I say "attempt" because it doesn't always work, though when it does I appreciate it. 124 | 125 | Install with `Ctrl+Shift+P` then: 126 | 127 | [source,sh] 128 | ---- 129 | ext install belfz.search-crates-io 130 | ---- 131 | 132 | == Wrap-up 133 | 134 | Programming is more than text and an IDE should be more than a text editor. Your IDE should help you stay in flow as much as possible and put exactly what you need at your fingertips. If you have any other tips for how to make VS Code more Rust-friendly, please share them! 135 | -------------------------------------------------------------------------------- /book/chapters/chapter-4-hello-world.adoc: -------------------------------------------------------------------------------- 1 | = Hello World (and your first two WTFs) 2 | 3 | == Introduction 4 | 5 | If you've never worked with a language that compiles down to native binaries, you're going to have fun with Rust. Yeah, it's easy to distribute executables within your chosen community, no matter if its node.js, Python, Ruby, PHP, Java, or something else. It gets crusty fast when you have to explain to outsiders. Think about the last time you enjoyed installing the latest version of Java to run a jar or had to deal with Python's virtual environments to run some random tool you wish was in JavaScript. 6 | 7 | With Rust, you can distribute executable binaries like the big kids. Sure you may need to cross-compile it for other architectures and operating systems, but https://rust-lang.github.io/rustup/cross-compilation.html[Rust has got you there, too]. 8 | 9 | === Code 10 | 11 | The code generated by the commands in this chapter can be found at https://github.com/vinodotdev/node-to-rust[vinodotdev/node-to-rust] 12 | 13 | === Hello world 14 | 15 | Start your first executable project by using `cargo new` with the name of your project like this 16 | 17 | ---- 18 | cargo new my-app 19 | ---- 20 | 21 | By default, `cargo new` uses a template for binary applications. That's what we want today, but keep in mind you can also do `cargo new --lib` to bootstrap a library. 22 | 23 | After you execute the command, you'll have the following directory structure: 24 | 25 | ---- 26 | my-app/ 27 | ├── .git 28 | ├── .gitignore 29 | ├── Cargo.toml 30 | └── src 31 | └── main.rs 32 | ---- 33 | 34 | NOTE: if you had a version of Rust installed before recently, the `edition` key in `Cargo.toml` is probably set to `2018`. `2021` has since gone stable and is what this book assumes. Editions are kind of like ECMAScript versions. The differences between `2018` and `2021` aren't huge, but it's worth calling out. 35 | 36 | Even before you take a look at the source, run your new project with `cargo run`. 37 | 38 | ---- 39 | » cargo run 40 | Compiling my-app v0.1.0 (./my-app) 41 | Finished dev [unoptimized + debuginfo] target(s) in 0.89s 42 | Running `target/debug/my-app` 43 | Hello, world! 44 | ---- 45 | 46 | `cargo run` builds your app with `cargo build` and executes the specified (or default, in this case) binary. After running this, your binary's already made and you can find it at `./target/debug/my-app`. Go, run it directly. It feels good. 47 | 48 | If you want to build your app without running it, use `cargo build`. Cargo builds with the `dev` (debug) profile by default which is usually faster. It will retain debug information at the expense of file size and performance. When you are ready to release, you'd build with `cargo build --release` and you'd find your binary in `./target/release/my-app`. 49 | 50 | === Now to the Rust 51 | 52 | Take a look at `src/main.rs` and mentally process this wild new language: 53 | 54 | [source,rust] 55 | ---- 56 | fn main() { 57 | println!("Hello, world!"); 58 | } 59 | ---- 60 | 61 | Well that's not so bad, right? 62 | 63 | The `main()` function is required in standalone executables. It's the entrypoint to your CLI app. 64 | 65 | `println!()` is a macro that generates code to print your arguments to STDOUT. If you've never dealt with macros before, they're like inline transpilers that generate code during compilation. We'll get to macros later. 66 | 67 | `"Hello, world!"` is a string _slice_ which is where things start getting real rusty. Strings are the first major hurdle for new Rust users and we'll tackle those in a later chapter, but let's walk through some of the first WTFs here to set the stage. 68 | 69 | == Strings WTF #1 70 | 71 | First, assign "Hello, world!" to a variable using `let` and try to print it. Yep, Rust uses `let` and `const` keywords just like JavaScript, though where you want to use `const` just about everywhere in JavaScript, you want to use `let` in most Rust. 72 | 73 | [source,rust] 74 | ---- 75 | fn main() { 76 | let greeting = "Hello, world!"; 77 | println!(greeting); 78 | } 79 | ---- 80 | 81 | If you set up VS Code like we did in an earlier day, you'll already see an error. Run it anyway with `cargo run`. 82 | 83 | [source,rust] 84 | ---- 85 | $ cargo run 86 | Compiling day-4-strings-wtf-1 v0.0.0 (/path/node-to-rust/crates/day-4/strings-wtf-1) 87 | error: format argument must be a string literal 88 | --> crates/day-4/strings-wtf-1/src/main.rs:3:12 89 | | 90 | 3 | println!(greeting); 91 | | ^^^^^^^^ 92 | | 93 | help: you might be missing a string literal to format with 94 | | 95 | 3 | println!("{}", greeting); 96 | | +++++ 97 | 98 | error: could not compile `day-4-strings-wtf-1` due to previous error 99 | ---- 100 | 101 | If you expected this to work, you'd be normal. In most languages a string is a string. Not in Rust. Do pay attention to the error message though. Rust's error messages are _leagues_ beyond the error messages you're probably used to. This message not only describes the problem, but shows you exactly where it occurs *_AND_* tells you exactly what you need to do to fix it. `println!()` requires a string literal as the first argument and supports a formatting syntax for replacing portions with variables. Change your program to the following to get back on track. 102 | 103 | [source,rust] 104 | ---- 105 | fn main() { 106 | let greeting = "Hello, world!"; 107 | println!("{}", greeting); 108 | } 109 | ---- 110 | 111 | == Strings WTF #2 112 | 113 | As a seasoned programmer, you know how write reusable code and are probably itching to abstract this complex logic into a reusable function. Take your newfound knowledge of `println!()` formatting syntax and write this beauty below. 114 | 115 | [source,rust] 116 | ---- 117 | fn main() { 118 | greet("World"); 119 | } 120 | 121 | fn greet(target: String) { 122 | println!("Hello, {}", target); 123 | } 124 | ---- 125 | 126 | Intuitively, this looks fine. But when you run it... 127 | 128 | [source,sh] 129 | ---- 130 | $ cargo run 131 | Compiling day-4-strings-wtf-2 v0.0.0 (/path/node-to-rust/crates/day-4/strings-wtf-2) 132 | error[E0308]: mismatched types 133 | --> crates/day-4/strings-wtf-2/src/main.rs:2:9 134 | | 135 | 2 | greet("World"); 136 | | ^^^^^^^- help: try using a conversion method: .to_string() 137 | | | 138 | | expected struct `String`, found `&str` 139 | 140 | For more information about this error, try `rustc --explain E0308`. 141 | error: could not compile `day-4-strings-wtf-2` due to previous error 142 | ---- 143 | 144 | While ``rustc``'s error messages do hint at how to get you back up and running, it does little to explain WTF is really going on... 145 | 146 | == Wrap-up 147 | 148 | Wrapping your head around strings in Rust is important. I know it's a tease to go through stuff like this without an immediate answer, but we'll get to it ASAP. First though, we need to talk about what "ownership" means in Rust in link:./chapter-5-ownership.adoc[Chapter 5: Borrowing & Ownership]. 149 | 150 | These questions are why I started this book. Now would be a good time to start searching the web for answers on Rust strings so you have some perspective on things when you come back. If you need a starter, check these out 151 | 152 | * https://doc.rust-lang.org/stable/rust-by-example/std/str.html[Strings in the Rust docs] 153 | * https://www.justanotherdot.com/posts/why-are-there-two-types-of-strings-in-Rust.html[Why Are There Two Types of Strings In Rust?] 154 | * https://blog.mgattozzi.dev/how-do-i-str-string/[How do I convert a &str to a String in Rust?] 155 | * https://www.youtube.com/watch?v=ClPrjjHmo2Y[Rust String vs str slices] 156 | * https://www.ameyalokare.com/rust/2017/10/12/rust-str-vs-String.html[Rust: str vs String] 157 | * https://blog.thoughtram.io/string-vs-str-in-rust/[String vs &str in Rust] 158 | -------------------------------------------------------------------------------- /book/chapters/chapter-7-syntax-and-language.adoc: -------------------------------------------------------------------------------- 1 | = Language Part 1: Syntax & Differences 2 | 3 | == Introduction 4 | 5 | All languages have a productivity baseline. That point where you know enough to be confident. After you reach the baseline, mastery is a matter of learning best practices, remembering what's in standard libraries, and expanding your bag of tricks with experience. 6 | 7 | Python has a low productivity baseline. The language is easy to grasp and it's a popular one to learn because of it. JavaScript's baseline is a little higher because of the async hurdle. Typed languages start higher by default due to their additional context. 8 | 9 | Rust's productivity baseline is more of a productivity roller coaster. Once you think you've figured it out, you peel back the curtain and realize you actually know nothing. 10 | 11 | We're still well below the first baseline but congrats to you for getting this far. This section will fill in some of the blanks and skirt you passed some hair pulling episodes where you scream things like "I just want to make an array!!@!" 12 | 13 | === Notable differences in Rust 14 | 15 | ==== Rust programming style 16 | 17 | The Rust style differs from JavaScript only slightly. 18 | 19 | Variables, functions, and modules are in snake case (e.g. `time_in_millis`) vs camel case (e.g. `timeInMillis`) as in JavaScript. 20 | 21 | Structs (a cross between JavaScript objects and classes) are in Pascal case (e.g. `CpuModel`) just like similar structures would be in JavaScript. 22 | 23 | Constants are similarly in capital snake case (e.g. `GLOBAL_TIMEOUT`). 24 | 25 | ==== Unambiguous parantheses are optional 26 | 27 | [source,rust] 28 | ---- 29 | if (x > y) { /* */ } 30 | 31 | while (x > y) { /* */ } 32 | ---- 33 | 34 | Can be written as 35 | 36 | [source,rust] 37 | ---- 38 | if x > y { /* */ } 39 | 40 | while x > y { /* */ } 41 | ---- 42 | 43 | This style is preferred and linters will warn you of it. 44 | 45 | ==== Almost everything is an expression 46 | 47 | Almost everything complete chunk of code returns a value. Obviously `4 * 2` returns a value (`8`), but so does `if true { 1 } else { 0 }` which returns `1`. 48 | 49 | That means you can assign the result of blocks of code to variables or use them as return values, e.g. 50 | 51 | [source,rust] 52 | ---- 53 | fn main() { 54 | let apples = 6; 55 | let message = if apples > 10 { 56 | "Lots of apples" 57 | } else if apples > 4 { 58 | "A few apples" 59 | } else { 60 | "Not many apples at all" 61 | }; 62 | 63 | println!("{}", message) // prints "A few apples" 64 | } 65 | ---- 66 | 67 | Notice how the lines with the strings don't end in a semi-colon. What happens if you add one? What happens if you add a semi-colon to all three? 68 | 69 | Spoiler alert: both questions lead to code that won't compile for different reasons. They produce error messages you'll come across frequently. Don't rob yourself the joy of seeing them first hand. It's _exhilirating_. Or just read on. 70 | 71 | ==== The unit type (`()`) 72 | 73 | Rust has no concept of `null` or `undefined` like JavaScript. That sounds great but it's not like those existed for no reason. They mean something. They mean _nothing_, albeit different kinds of nothing. As such, Rust still needs types that can represent _nothing_. 74 | 75 | Try adding a semi-colon the first string above so the `if {} else if {} else {}` looks like this: 76 | 77 | [source,rust] 78 | ---- 79 | let message = if apples > 10 { 80 | "Lots of apples"; // ⬅ Notice the rogue semi-colon 81 | } else if apples > 4 { 82 | "A few apples" 83 | } else { 84 | "Not many apples at all" 85 | }; 86 | ---- 87 | 88 | Rust won't compile, giving you the error "``if`` and `else` have incompatible types." The full output is below. 89 | 90 | [source,output] 91 | ---- 92 | error[E0308]: `if` and `else` have incompatible types 93 | --> crates/day-7/syntax/src/main.rs:13:12 94 | | 95 | 11 | let message = if apples > 10 { 96 | | ___________________- 97 | 12 | | "Lots of apples"; 98 | | | ----------------- 99 | | | | | 100 | | | | help: consider removing this semicolon 101 | | | expected because of this 102 | 13 | | } else if apples > 4 { 103 | | |____________^ 104 | 14 | || "A few apples" 105 | 15 | || } else { 106 | 16 | || "Not many apples at all" 107 | 17 | || }; 108 | | || ^ 109 | | ||_____| 110 | | |______`if` and `else` have incompatible types 111 | | expected `()`, found `&str` 112 | ---- 113 | 114 | The helper text tells you that rust "expected `()`, found `&str`." It also mentions (helpfully) that you might consider removing the semicolon. That'll work, but what's going on and what is `()`? 115 | 116 | `()` is called the https://doc.rust-lang.org/std/primitive.unit.html[unit type]. It essentially means "no value." An expression that ends with a semi-colon returns _no value_, or `()`. Rust sees that the `if {}` part of the conditional returns nothing -- or `()` -- and expects every other part of the conditional to return a value of the same type, or `()`. When we leave off the semi-colon, the result of that first block is the return value of the expression `"Lots of apples"` which is (naturally) `"Lots of apples"`. 117 | 118 | This brings us to... 119 | 120 | ==== Implicit returns 121 | 122 | We saw how a block can return a value above. Functions are no different. The last line of execution (the "tail") will be used as the return value for a function. You'll frequently see functions that don't have explicit `return` statements, e.g. 123 | 124 | [source,rust] 125 | ---- 126 | fn add_numbers(left: i64, right: i64) -> i64 { 127 | left + right // ⬅ Notice no semi-colon 128 | } 129 | ---- 130 | 131 | Which is equivalent to: 132 | 133 | [source,rust] 134 | ---- 135 | fn add_numbers(left: i64, right: i64) -> i64 { 136 | return left + right; 137 | } 138 | ---- 139 | 140 | If you specify a return type (the `+-> i64+` above) and accidentally use a semi-colon on your last line, you'll see an error like we saw in the section above: 141 | 142 | [source,output] 143 | ---- 144 | | 145 | 5 | fn add_numbers(left: i64, right: i64) -> i64 { 146 | | ----------- ^^^ expected `i64`, found `()` 147 | | | 148 | | implicitly returns `()` as its body has no tail or `return` expression 149 | 6 | left + right; 150 | | - help: consider removing this semicolon 151 | ---- 152 | 153 | It will take some getting used to, but you do get used to it. Whenever you see an error complaining about `()`, it's often because you either need to add or remove a semi-colon (or return type) somewhere. 154 | 155 | ==== Arrays 156 | 157 | Rust has arrays. If you use them like you want to however, you're going to have an experience just like you did with strings. I won't go into arrays and slices because there is plenty written on the subject (e.g. https://doc.rust-lang.org/book/ch04-03-slices.html[Rust Book: Ch 4.3] and https://doc.rust-lang.org/rust-by-example/primitives/array.html[Rust by Example: Ch 2.3]). 158 | 159 | The short of Rust arrays is: they must have a known length with all elements initialized. 160 | 161 | This won't work. 162 | 163 | [source,rust] 164 | ---- 165 | let mut numbers = [1, 2, 3, 4, 5]; 166 | numbers.push(7); 167 | println!("{:?}", numbers); 168 | ---- 169 | 170 | The reason it's not worth going into is because you're probably not looking for arrays. 171 | 172 | What you're looking for is https://doc.rust-lang.org/std/vec/struct.Vec.html[`Vec`] or https://doc.rust-lang.org/std/collections/struct.VecDeque.html[`VecDeque`]. `Vec` is to JavaScript arrays what `String` is to JavaScript strings. ``Vec``'s can grow and shrink at the end. `VecDeque` can grow or shrink from either direction. 173 | 174 | NOTE: `VecDeque` is pronounced vec-deck. Deque stands for "Double ended queue." 175 | 176 | Arrays and iterators will have their own section in this guide, but know that there's an easy-to-use macro that gives you a `Vec` with similar syntax you're used to. 177 | 178 | [source,rust] 179 | ---- 180 | let mut numbers = vec![1, 2, 3, 4, 5]; // ⬅ Notice the vec! macro 181 | numbers.push(7); 182 | println!("{:?}", numbers); 183 | ---- 184 | 185 | == Wrap-up 186 | 187 | There is no end to what can trip you up when you try and jump into another language. If you haven't read https://doc.rust-lang.org/stable/book/[The Rust Book], you are going to start having trouble if you haven't already. If you _have_ read https://doc.rust-lang.org/stable/book/[The Rust Book], read it again. Every time you turn a corner in Rust, you'll start to see things more clearly. Documentation will look different. What didn't land right the first time will start to make sense now. 188 | 189 | Next up we'll dive into the basic types and start on Structs. Stay tuned! 190 | -------------------------------------------------------------------------------- /book/chapters/preface.adoc: -------------------------------------------------------------------------------- 1 | [preface] 2 | # Preface 3 | 4 | This book started as a series of posts on https://vino.dev/blog[vino.dev's blog] during December 2021. The series generated more interest than we ever expected and it started to take on a life of its own. Since then we've had numerous publishers and volunteers looking to extend this series and its reach. We converted the blog posts to asciidoc and put together the scaffolding necessary to turn it into an e-book. The book's source files and all the project's source code are open source under Creative Commons licenses. You are welcome and encouraged to submit contributions, fixes, translations, or new chapters as you see fit. 5 | 6 | Thank you everyone who contributed, provided feedback, and otherwise helped make the effort worthwhile. Special thanks go to my wife Kate Lane and my children Finn, Norah, and Elliot who tolerated me writing all day, every day over the 2021 holidays. 7 | 8 | 9 | ## A note on contributions: 10 | 11 | The spirit of this book and its original posts can be summed up as "Get to the point. Fast." The JavaScript and node.js community is top-notch when it comes to practical examples and working example code. I missed that when I started working with Rust. I began the original series to help those coming down this same path and I'd like to maintain that spirit as much as possible. If the book is outright *wrong*, then please contribute fixes. Otherwise, please err on the side of "gets the point across" vs 100% technical accuracy. 12 | 13 | ## Cover image 14 | 15 | Photo by https://unsplash.com/@jayrheike?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText[Jay Heike] on https://unsplash.com/s/photos/rust?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText[Unsplash] 16 | -------------------------------------------------------------------------------- /book/images/cliff of comprehension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/cliff of comprehension.png -------------------------------------------------------------------------------- /book/images/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/cover.png -------------------------------------------------------------------------------- /book/images/devtools-gc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/devtools-gc.png -------------------------------------------------------------------------------- /book/images/node-to-rust-vscode-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/node-to-rust-vscode-settings.png -------------------------------------------------------------------------------- /book/images/vs-code-conversion-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/vs-code-conversion-error.png -------------------------------------------------------------------------------- /book/images/vs-code-crates.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/vs-code-crates.gif -------------------------------------------------------------------------------- /book/images/vs-code-debugging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/vs-code-debugging.png -------------------------------------------------------------------------------- /book/images/vs-code-impl-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/vs-code-impl-error.png -------------------------------------------------------------------------------- /book/images/vs-code-impl-error2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/vs-code-impl-error2.png -------------------------------------------------------------------------------- /book/images/vs-code-inlay-hints.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/vs-code-inlay-hints.png -------------------------------------------------------------------------------- /book/images/vs-code-ownership.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/vs-code-ownership.png -------------------------------------------------------------------------------- /book/images/vs-code-private-module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/vs-code-private-module.png -------------------------------------------------------------------------------- /book/images/vs-code-quick-code-impl-display.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/vs-code-quick-code-impl-display.png -------------------------------------------------------------------------------- /book/images/vs-code-quick-code-implement-members.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/vs-code-quick-code-implement-members.png -------------------------------------------------------------------------------- /book/images/vs-code-quick-code-import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/book/images/vs-code-quick-code-import.png -------------------------------------------------------------------------------- /from-javascript-to-rust.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/from-javascript-to-rust.epub -------------------------------------------------------------------------------- /from-javascript-to-rust.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/from-javascript-to-rust.pdf -------------------------------------------------------------------------------- /src/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["crates/*/*"] 3 | 4 | exclude = [ 5 | "crates/day-19/project", 6 | "crates/day-20/project", 7 | "crates/day-21/project", 8 | "crates/day-21/wapc-guest", 9 | "crates/day-22/project", 10 | "crates/day-22/wapc-guest", 11 | ] 12 | -------------------------------------------------------------------------------- /src/crates/day-10/traits/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-10-traits" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-10/traits/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | fn main() { 4 | let traffic_light = TrafficLight::new(); 5 | let house_light = HouseLight::new(); 6 | 7 | print_state(&traffic_light); 8 | print_state(&house_light); 9 | } 10 | 11 | fn print_state(light: &impl Light) { 12 | println!("{}'s state is : {:?}", light.get_name(), light.get_state()); 13 | } 14 | 15 | trait Light { 16 | fn get_name(&self) -> &str; 17 | fn get_state(&self) -> &dyn std::fmt::Debug; 18 | } 19 | 20 | impl Light for HouseLight { 21 | fn get_name(&self) -> &str { 22 | "House light" 23 | } 24 | 25 | fn get_state(&self) -> &dyn std::fmt::Debug { 26 | &self.on 27 | } 28 | } 29 | 30 | impl Light for TrafficLight { 31 | fn get_name(&self) -> &str { 32 | "Traffic light" 33 | } 34 | 35 | fn get_state(&self) -> &dyn std::fmt::Debug { 36 | &self.color 37 | } 38 | } 39 | 40 | impl std::fmt::Display for TrafficLight { 41 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 42 | write!(f, "Traffic light is {}", self.color) 43 | } 44 | } 45 | 46 | #[derive(Debug)] 47 | struct TrafficLight { 48 | color: TrafficLightColor, 49 | } 50 | 51 | impl TrafficLight { 52 | pub fn new() -> Self { 53 | Self { 54 | color: TrafficLightColor::Red, 55 | } 56 | } 57 | 58 | pub fn turn_green(&mut self) { 59 | self.color = TrafficLightColor::Green 60 | } 61 | } 62 | 63 | #[derive(Debug)] 64 | enum TrafficLightColor { 65 | Red, 66 | Yellow, 67 | Green, 68 | } 69 | 70 | impl Display for TrafficLightColor { 71 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 72 | let color_string = match self { 73 | TrafficLightColor::Green => "green", 74 | TrafficLightColor::Red => "red", 75 | TrafficLightColor::Yellow => "yellow", 76 | }; 77 | write!(f, "{}", color_string) 78 | } 79 | } 80 | 81 | #[derive(Debug)] 82 | struct HouseLight { 83 | on: bool, 84 | } 85 | 86 | impl Display for HouseLight { 87 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 88 | write!(f, "Houselight is {}", if self.on { "on" } else { "off" }) 89 | } 90 | } 91 | 92 | impl HouseLight { 93 | pub fn new() -> Self { 94 | Self { on: false } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/crates/day-11/modules/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-11-modules" 3 | version = "0.0.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 | [[bin]] 11 | name = "nested-submodules" 12 | test = false 13 | bench = false 14 | path = "src/nested-submodules.rs" 15 | -------------------------------------------------------------------------------- /src/crates/day-11/modules/src/nested-submodules.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | my_module::print(my_module::submodule::MSG); 3 | } 4 | 5 | mod my_module { 6 | pub fn print(msg: &str) { 7 | println!("{}", msg); 8 | } 9 | 10 | pub mod submodule { 11 | pub const MSG: &str = "Hello world!"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/crates/day-11/traffic-light/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-11-traffic-light" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-11/traffic-light/src/light.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod house_light; 2 | pub(crate) mod traffic_light; 3 | 4 | pub(crate) trait Light { 5 | fn get_name(&self) -> &str; 6 | fn get_state(&self) -> &dyn std::fmt::Debug; 7 | } 8 | -------------------------------------------------------------------------------- /src/crates/day-11/traffic-light/src/light/house_light.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | use super::Light; 4 | 5 | impl Light for HouseLight { 6 | fn get_name(&self) -> &str { 7 | "House light" 8 | } 9 | 10 | fn get_state(&self) -> &dyn std::fmt::Debug { 11 | &self.on 12 | } 13 | } 14 | 15 | #[derive(Debug)] 16 | pub(crate) struct HouseLight { 17 | on: bool, 18 | } 19 | 20 | impl Display for HouseLight { 21 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 22 | write!(f, "Houselight is {}", if self.on { "on" } else { "off" }) 23 | } 24 | } 25 | 26 | impl HouseLight { 27 | pub fn new() -> Self { 28 | Self { on: false } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/crates/day-11/traffic-light/src/light/traffic_light.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | use super::Light; 4 | 5 | impl Light for TrafficLight { 6 | fn get_name(&self) -> &str { 7 | "Traffic light" 8 | } 9 | 10 | fn get_state(&self) -> &dyn std::fmt::Debug { 11 | &self.color 12 | } 13 | } 14 | 15 | impl std::fmt::Display for TrafficLight { 16 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 17 | write!(f, "Traffic light is {}", self.color) 18 | } 19 | } 20 | 21 | #[derive(Debug)] 22 | pub(crate) struct TrafficLight { 23 | color: TrafficLightColor, 24 | } 25 | 26 | impl TrafficLight { 27 | pub fn new() -> Self { 28 | Self { 29 | color: TrafficLightColor::Red, 30 | } 31 | } 32 | 33 | pub fn turn_green(&mut self) { 34 | self.color = TrafficLightColor::Green 35 | } 36 | } 37 | 38 | #[derive(Debug)] 39 | enum TrafficLightColor { 40 | Red, 41 | Yellow, 42 | Green, 43 | } 44 | 45 | impl Display for TrafficLightColor { 46 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 47 | let color_string = match self { 48 | TrafficLightColor::Green => "green", 49 | TrafficLightColor::Red => "red", 50 | TrafficLightColor::Yellow => "yellow", 51 | }; 52 | write!(f, "{}", color_string) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/crates/day-11/traffic-light/src/main.rs: -------------------------------------------------------------------------------- 1 | use crate::light::house_light::HouseLight; 2 | use crate::light::traffic_light::TrafficLight; 3 | use crate::light::Light; 4 | 5 | mod light; 6 | 7 | fn main() { 8 | let traffic_light = TrafficLight::new(); 9 | let house_light = HouseLight::new(); 10 | 11 | print_state(&traffic_light); 12 | print_state(&house_light); 13 | } 14 | 15 | fn print_state(light: &impl Light) { 16 | println!("{}'s state is : {:?}", light.get_name(), light.get_state()); 17 | } 18 | -------------------------------------------------------------------------------- /src/crates/day-12/impl-asref-str/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-12-impl-asref-str" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-12/impl-asref-str/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; // Imported to use Ipv4Addr::from_str 2 | 3 | fn main() { 4 | let ip_address = std::net::Ipv4Addr::from_str("127.0.0.1").unwrap(); 5 | let string_slice = "string slice"; 6 | let string_proper = "String proper".to_owned(); 7 | needs_string(string_slice); 8 | needs_string("Literal string"); 9 | needs_string(string_proper); 10 | // needs_string(ip_address); // Fails now 11 | } 12 | 13 | fn needs_string>(almost_string: T) { 14 | let real_string = almost_string.as_ref().to_owned(); 15 | println!("{}", real_string); 16 | } 17 | 18 | // fn needs_string(almost_string: impl AsRef) { 19 | // let real_string = almost_string.as_ref().to_owned(); 20 | // println!("{}", real_string); 21 | // } 22 | 23 | // fn needs_string(almost_string: T) 24 | // where 25 | // T: AsRef, 26 | // { 27 | // let real_string = almost_string.as_ref().to_owned(); 28 | // println!("{}", real_string); 29 | // } 30 | -------------------------------------------------------------------------------- /src/crates/day-12/impl-tostring/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-12-impl-tostring" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-12/impl-tostring/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; // Imported to use Ipv4Addr::from_str 2 | 3 | fn main() { 4 | let ip_address = std::net::Ipv4Addr::from_str("127.0.0.1").unwrap(); 5 | let string_proper = "String proper".to_owned(); 6 | let string_slice = "string slice"; 7 | needs_string(string_slice); 8 | needs_string("Literal string"); 9 | needs_string(string_proper); 10 | needs_string(ip_address); 11 | } 12 | 13 | fn needs_string(almost_string: T) { 14 | let real_string = almost_string.to_string(); 15 | println!("{}", real_string); 16 | } 17 | 18 | // fn needs_string(almost_string: impl ToString) { 19 | // let real_string = almost_string.to_string(); 20 | // println!("{}", real_string); 21 | // } 22 | 23 | // fn needs_string(almost_string: T) 24 | // where 25 | // T: ToString, 26 | // { 27 | // let real_string = almost_string.to_string(); 28 | // println!("{}", real_string); 29 | // } 30 | -------------------------------------------------------------------------------- /src/crates/day-13/option/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-13-option" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-13/option/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::time::Instant; 2 | 3 | fn main() { 4 | let some = returns_some(); 5 | println!("{:?}", some); 6 | 7 | let none = returns_none(); 8 | println!("{:?}", none); 9 | 10 | let default_string = "Default value".to_owned(); 11 | 12 | let unwrap_or = returns_none().unwrap_or(default_string); 13 | println!("returns_none().unwrap_or(...): {:?}", unwrap_or); 14 | 15 | let unwrap_or_else = returns_none() 16 | .unwrap_or_else(|| format!("Default value from a function at time {:?}", Instant::now())); 17 | 18 | println!( 19 | "returns_none().unwrap_or_else(|| {{...}}): {:?}", 20 | unwrap_or_else 21 | ); 22 | 23 | let unwrap_or_default = returns_none().unwrap_or_default(); 24 | 25 | println!( 26 | "returns_none().unwrap_or_default(): {:?}", 27 | unwrap_or_default 28 | ); 29 | 30 | let match_value = match returns_some() { 31 | Some(val) => val, 32 | None => "My default value".to_owned(), 33 | }; 34 | 35 | println!("match {{...}}: {:?}", match_value); 36 | 37 | if let Some(val) = returns_some() { 38 | println!("if let : {:?}", val); 39 | } 40 | } 41 | 42 | fn returns_some() -> Option { 43 | Some("my string".to_owned()) 44 | } 45 | 46 | fn returns_none() -> Option { 47 | None 48 | } 49 | -------------------------------------------------------------------------------- /src/crates/day-13/question-mark/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-13-question-mark" 3 | version = "0.0.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 | markdown = "0.3.0" 10 | -------------------------------------------------------------------------------- /src/crates/day-13/question-mark/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fs::read_to_string; 2 | 3 | fn main() -> Result<(), std::io::Error> { 4 | let html = render_markdown("./README.md")?; 5 | println!("{}", html); 6 | Ok(()) 7 | } 8 | 9 | fn render_markdown(file: &str) -> Result { 10 | let source = read_to_string(file)?; 11 | Ok(markdown::to_html(&source)) 12 | } 13 | -------------------------------------------------------------------------------- /src/crates/day-13/result/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-13-result" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-13/result/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let value = returns_ok(); 3 | println!("{:?}", value); 4 | 5 | let value = returns_err(); 6 | println!("{:?}", value); 7 | } 8 | 9 | fn returns_ok() -> Result { 10 | Ok("This turned out great!".to_owned()) 11 | } 12 | 13 | fn returns_err() -> Result { 14 | Err(MyError("This failed horribly.".to_owned())) 15 | } 16 | 17 | #[derive(Debug)] 18 | struct MyError(String); 19 | -------------------------------------------------------------------------------- /src/crates/day-14/boxed-errors/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-14-boxed-errors" 3 | version = "0.0.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 | markdown = "0.3.0" 10 | -------------------------------------------------------------------------------- /src/crates/day-14/boxed-errors/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, error::Error, fs::read_to_string}; 2 | 3 | fn main() -> Result<(), Box> { 4 | let html = render_markdown()?; 5 | // let result = weird_error()?; // This is a compilation error 6 | println!("{}", html); 7 | Ok(()) 8 | } 9 | 10 | fn render_markdown() -> Result> { 11 | let file = std::env::var("MARKDOWN")?; 12 | let source = read_to_string(file)?; 13 | Ok(markdown::to_html(&source)) 14 | } 15 | 16 | fn weird_error() -> Result<(), HashMap> { 17 | Err(HashMap::new()) 18 | } 19 | -------------------------------------------------------------------------------- /src/crates/day-14/custom-error-type/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-14-custom-error-type" 3 | version = "0.0.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 | markdown = "0.3.0" 10 | -------------------------------------------------------------------------------- /src/crates/day-14/custom-error-type/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fs::read_to_string; 2 | 3 | fn main() -> Result<(), MyError> { 4 | let html = render_markdown()?; 5 | println!("{}", html); 6 | Ok(()) 7 | } 8 | 9 | fn render_markdown() -> Result { 10 | let file = std::env::var("MARKDOWN")?; 11 | let source = read_to_string(file)?; 12 | Ok(markdown::to_html(&source)) 13 | } 14 | 15 | #[derive(Debug)] 16 | enum MyError { 17 | EnvironmentVariableNotFound, 18 | IOError(std::io::Error), 19 | } 20 | 21 | impl From for MyError { 22 | fn from(_: std::env::VarError) -> Self { 23 | Self::EnvironmentVariableNotFound 24 | } 25 | } 26 | 27 | impl From for MyError { 28 | fn from(value: std::io::Error) -> Self { 29 | Self::IOError(value) 30 | } 31 | } 32 | 33 | impl std::error::Error for MyError {} 34 | 35 | impl std::fmt::Display for MyError { 36 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 37 | match self { 38 | MyError::EnvironmentVariableNotFound => write!(f, "Environment variable not found"), 39 | MyError::IOError(err) => write!(f, "IO Error: {}", err.to_string()), 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/crates/day-14/error-chain/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-14-error-chain" 3 | version = "0.0.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 | markdown = "0.3.0" 10 | error-chain = "0.12.4" 11 | -------------------------------------------------------------------------------- /src/crates/day-14/error-chain/src/main.rs: -------------------------------------------------------------------------------- 1 | #![recursion_limit = "1024"] 2 | use std::fs::read_to_string; 3 | 4 | error_chain::error_chain! { 5 | foreign_links { 6 | EnvironmentVariableNotFound(::std::env::VarError); 7 | IOError(::std::io::Error); 8 | } 9 | } 10 | 11 | fn main() -> Result<()> { 12 | let html = render_markdown()?; 13 | println!("{}", html); 14 | Ok(()) 15 | } 16 | 17 | fn render_markdown() -> Result { 18 | let file = std::env::var("MARKDOWN")?; 19 | let source = read_to_string(file)?; 20 | Ok(markdown::to_html(&source)) 21 | } 22 | -------------------------------------------------------------------------------- /src/crates/day-14/from-into/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-14-from-into" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-14/from-into/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let string = "Hello, world".to_owned(); 3 | let wrapper: MyStringWrapper = string.into(); 4 | println!("{:?}", wrapper); 5 | let wrapper2 = MyStringWrapper::from("generated from MyStringWrapper::from".to_owned()); 6 | println!("{:?}", wrapper2); 7 | 8 | let string = "Hello, world again".to_owned(); 9 | let wrapper3: ADifferentStringWrapper = string.try_into().unwrap(); 10 | println!("{:?}", wrapper3); 11 | let wrapper4 = ADifferentStringWrapper::try_from( 12 | "generated from ADifferentStringWrapper::try_from".to_owned(), 13 | ); 14 | println!("{:?}", wrapper4); 15 | } 16 | 17 | #[derive(Debug)] 18 | struct MyStringWrapper(String); 19 | 20 | impl From for MyStringWrapper { 21 | fn from(value: String) -> Self { 22 | Self(value) 23 | } 24 | } 25 | 26 | #[derive(Debug)] 27 | struct ADifferentStringWrapper(String); 28 | 29 | impl TryFrom for ADifferentStringWrapper { 30 | type Error = String; 31 | 32 | fn try_from(value: String) -> Result { 33 | Ok(Self(value)) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/crates/day-14/snafu/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-14-snafu" 3 | version = "0.0.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 | markdown = "0.3.0" 10 | snafu = "0.6.10" 11 | -------------------------------------------------------------------------------- /src/crates/day-14/snafu/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fs::read_to_string; 2 | 3 | fn main() -> Result<(), MyError> { 4 | let html = render_markdown()?; 5 | println!("{}", html); 6 | Ok(()) 7 | } 8 | 9 | fn render_markdown() -> Result { 10 | let file = std::env::var("MARKDOWN")?; 11 | let source = read_to_string(file)?; 12 | Ok(markdown::to_html(&source)) 13 | } 14 | 15 | #[derive(snafu::Snafu, Debug)] 16 | enum MyError { 17 | #[snafu(display("Environment variable not found"))] 18 | EnvironmentVariableNotFound { source: std::env::VarError }, 19 | 20 | #[snafu(display("IO Error: {}", source.to_string()))] 21 | IOError { source: std::io::Error }, 22 | } 23 | 24 | impl From for MyError { 25 | fn from(source: std::env::VarError) -> Self { 26 | Self::EnvironmentVariableNotFound { source } 27 | } 28 | } 29 | 30 | impl From for MyError { 31 | fn from(source: std::io::Error) -> Self { 32 | Self::IOError { source } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/crates/day-14/thiserror/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-14-thiserror" 3 | version = "0.0.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 | markdown = "0.3.0" 10 | thiserror = "1.0.30" 11 | -------------------------------------------------------------------------------- /src/crates/day-14/thiserror/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fs::read_to_string; 2 | 3 | fn main() -> Result<(), MyError> { 4 | let html = render_markdown()?; 5 | println!("{}", html); 6 | Ok(()) 7 | } 8 | 9 | fn render_markdown() -> Result { 10 | let file = std::env::var("MARKDOWN")?; 11 | let source = read_to_string(file)?; 12 | Ok(markdown::to_html(&source)) 13 | } 14 | 15 | #[derive(thiserror::Error, Debug)] 16 | enum MyError { 17 | #[error("Environment variable not found")] 18 | EnvironmentVariableNotFound(#[from] std::env::VarError), 19 | #[error(transparent)] 20 | IOError(#[from] std::io::Error), 21 | } 22 | -------------------------------------------------------------------------------- /src/crates/day-15/closures/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-15-closures" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-15/closures/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let closure = || { 3 | println!("Hi! I'm in a closure"); 4 | }; 5 | closure(); 6 | 7 | let double = |num: i64| num + num; 8 | let num = 4; 9 | println!("{} + {} = {}", num, num, double(num)); 10 | 11 | let name = "Rebecca"; 12 | let closure = || { 13 | println!("Hi, {}.", name); 14 | }; 15 | closure(); 16 | 17 | let mut counter = 0; 18 | 19 | let mut closure = || { 20 | counter += 1; 21 | println!( 22 | "This closure has a counter. I've been run {} times.", 23 | counter 24 | ); 25 | }; 26 | closure(); 27 | closure(); 28 | closure(); 29 | println!("The closure was called a total of {} times", counter); 30 | 31 | let adder = |left: i32, right: i32| { 32 | println!("{} + {} is {}", left, right, left + right); 33 | left + right 34 | }; 35 | adder(4, 5); 36 | 37 | let name = "Dwayne".to_owned(); 38 | let consuming_closure = || name.into_bytes(); 39 | let bytes = consuming_closure(); 40 | // let bytes = consuming_closure(); // ← compilation error 41 | 42 | let plus_two = make_adder(2); 43 | plus_two(23); 44 | 45 | let times_two = |i: i32| i * 2; 46 | let double_plus_two = compose(plus_two, times_two); 47 | println!("{} * 2 + 2 = {}", 10, double_plus_two(10)); 48 | 49 | let fn_ref = regular_function; 50 | fn_ref(); 51 | 52 | let square = DynamicBehavior::new(Box::new(|num: i64| num * num)); 53 | println!("{} squared is {}", 5, square.run(5)) 54 | } 55 | 56 | fn regular_function() { 57 | println!("I'm a regular function"); 58 | } 59 | 60 | fn make_adder(left: i32) -> impl Fn(i32) -> i32 { 61 | move |right: i32| { 62 | println!("{} + {} is {}", left, right, left + right); 63 | left + right 64 | } 65 | } 66 | 67 | fn compose(f: impl Fn(T) -> T, g: impl Fn(T) -> T) -> impl Fn(T) -> T { 68 | move |i: T| f(g(i)) 69 | } 70 | 71 | struct DynamicBehavior { 72 | closure: Box T>, 73 | } 74 | 75 | impl DynamicBehavior { 76 | fn new(closure: Box T>) -> Self { 77 | Self { closure } 78 | } 79 | fn run(&self, arg: T) -> T { 80 | (self.closure)(arg) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/crates/day-16/elision/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-16-elision" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-16/elision/src/main.rs: -------------------------------------------------------------------------------- 1 | fn omits_annotations(list: &[String]) -> Option<&String> { 2 | list.get(0) 3 | } 4 | 5 | fn has_annotations<'a>(list: &'a [String]) -> Option<&'a String> { 6 | list.get(1) 7 | } 8 | 9 | fn main() { 10 | let authors = vec!["Samuel Clemens".to_owned(), "Jane Austen".to_owned()]; 11 | let value = omits_annotations(&authors).unwrap(); 12 | println!("The first author is '{}'", value); 13 | let value = has_annotations(&authors).unwrap(); 14 | println!("The second author is '{}'", value); 15 | } 16 | -------------------------------------------------------------------------------- /src/crates/day-16/static-bounds/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-16-static-bounds" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-16/static-bounds/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | fn main() { 4 | let mut string = "First".to_owned(); 5 | 6 | string.push_str(string.to_uppercase().as_str()); 7 | print_a(&string); 8 | print_b(&string); 9 | print_c(&string); // Compilation error 10 | print_d(&string); // Compilation error 11 | print_e(&string); 12 | print_f(&string); 13 | print_g(&string); // Compilation error 14 | } 15 | 16 | fn print_a(t: &T) { 17 | println!("{}", t); 18 | } 19 | 20 | fn print_b(t: &T) 21 | where 22 | T: Display + 'static, 23 | { 24 | println!("{}", t); 25 | } 26 | 27 | fn print_c(t: &'static dyn Display) { 28 | println!("{}", t) 29 | } 30 | 31 | fn print_d(t: &'static impl Display) { 32 | println!("{}", t) 33 | } 34 | 35 | fn print_e(t: &(dyn Display + 'static)) { 36 | println!("{}", t) 37 | } 38 | 39 | fn print_f(t: &(impl Display + 'static)) { 40 | println!("{}", t) 41 | } 42 | 43 | fn print_g(t: &'static String) { 44 | println!("{}", t); 45 | } 46 | -------------------------------------------------------------------------------- /src/crates/day-16/static/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-16-static" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-16/static/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | fn main() { 4 | let r1; 5 | let r2; 6 | { 7 | static STATIC_EXAMPLE: i32 = 42; 8 | r1 = &STATIC_EXAMPLE; 9 | let x = "&'static str"; 10 | r2 = x; 11 | } 12 | println!("&'static i32: {}", r1); 13 | println!("&'static str: {}", r2); 14 | 15 | let r3; 16 | 17 | { 18 | let string = "String".to_owned(); 19 | 20 | static_bound(&string); // This is *not* an error 21 | r3 = &string; // This *is* 22 | } 23 | println!("{}", r3); 24 | } 25 | 26 | fn static_bound(t: &T) { 27 | println!("{}", t); 28 | } 29 | -------------------------------------------------------------------------------- /src/crates/day-16/type-differences/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-16-type-differences" 3 | version = "0.0.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 | [[bin]] 11 | name = "impl-owned" 12 | test = false 13 | bench = false 14 | path = "src/impl-owned.rs" 15 | 16 | [[bin]] 17 | name = "impl-borrowed" 18 | test = false 19 | bench = false 20 | path = "src/impl-borrowed.rs" 21 | -------------------------------------------------------------------------------- /src/crates/day-16/type-differences/src/impl-borrowed.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | fn main() { 4 | let my_struct = MyStruct {}; 5 | // my_struct.print(); // Removed because the impl no longer exists 6 | println!(""); 7 | 8 | let struct_ref = &my_struct; 9 | struct_ref.print(); 10 | 11 | let mut mut_struct = MyStruct {}; 12 | // mut_struct.print(); // Removed because the impl no longer exists 13 | println!(""); 14 | 15 | let ref_mut_struct = &mut_struct; 16 | ref_mut_struct.print(); 17 | 18 | let mut_struct_ref = &mut mut_struct; 19 | mut_struct_ref.print(); 20 | } 21 | 22 | trait Printer { 23 | fn print(&self); 24 | } 25 | 26 | struct MyStruct {} 27 | 28 | // Watch how the output differs when this impl is removed. 29 | // 30 | // impl Printer for MyStruct { 31 | // fn print(&self) { 32 | // println!("Foo") 33 | // } 34 | // } 35 | 36 | impl Printer for &MyStruct { 37 | fn print(&self) { 38 | println!("&Foo") 39 | } 40 | } 41 | 42 | impl Printer for &mut MyStruct { 43 | fn print(&self) { 44 | println!("&mut Foo") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/crates/day-16/type-differences/src/impl-owned.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | fn main() { 4 | let my_struct = MyStruct {}; 5 | my_struct.print(); 6 | 7 | let struct_ref = &my_struct; 8 | struct_ref.print(); 9 | 10 | let mut mut_struct = MyStruct {}; 11 | mut_struct.print(); 12 | 13 | let ref_mut_struct = &mut_struct; 14 | ref_mut_struct.print(); 15 | 16 | let mut_struct_ref = &mut mut_struct; 17 | mut_struct_ref.print(); 18 | } 19 | 20 | trait Printer { 21 | fn print(&self); 22 | } 23 | 24 | struct MyStruct {} 25 | 26 | impl Printer for MyStruct { 27 | fn print(&self) { 28 | println!("Foo") 29 | } 30 | } 31 | 32 | impl Printer for &MyStruct { 33 | fn print(&self) { 34 | println!("&Foo") 35 | } 36 | } 37 | 38 | impl Printer for &mut MyStruct { 39 | fn print(&self) { 40 | println!("&mut Foo") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/crates/day-16/unsafe-pointers/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-16-unsafe-pointers" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-16/unsafe-pointers/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{slice::from_raw_parts, str::from_utf8_unchecked}; 2 | 3 | fn get_memory_location() -> (usize, usize) { 4 | let string = "Hello World!"; 5 | let pointer = string.as_ptr() as usize; 6 | let length = string.len(); 7 | (pointer, length) 8 | // `string` is dropped here. 9 | // It's no longer accessible, but the data lives on. 10 | } 11 | 12 | fn get_str_at_location(pointer: usize, length: usize) -> &'static str { 13 | // Notice the `unsafe {}` block. We can't do things like this without 14 | // acknowledging to Rust that we know this is dangerous. 15 | unsafe { from_utf8_unchecked(from_raw_parts(pointer as *const u8, length)) } 16 | } 17 | 18 | fn main() { 19 | let (pointer, length) = get_memory_location(); 20 | let message = get_str_at_location(pointer, length); 21 | println!( 22 | "The {} bytes at 0x{:X} stored: {}", 23 | length, pointer, message 24 | ); 25 | // If you want to see why dealing with raw pointers is dangerous, 26 | // uncomment this line. 27 | // let message = get_str_at_location(1000, 10); 28 | } 29 | -------------------------------------------------------------------------------- /src/crates/day-17/arrays/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-17-arrays" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-17/arrays/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | fn main() { 4 | for_common(); 5 | for_in(); 6 | for_of(); 7 | while_not_done(); 8 | while_true(); 9 | labels(); 10 | loop_expressions(); 11 | } 12 | 13 | fn for_common() { 14 | let max = 4; 15 | for i in 0..max { 16 | println!("{}", i); 17 | } 18 | } 19 | 20 | fn for_in() { 21 | let obj = HashMap::from([("key1", "value1"), ("key2", "value2")]); 22 | for prop in obj.keys() { 23 | println!("{}: {}", prop, obj.get(prop).unwrap()); 24 | } 25 | } 26 | 27 | fn for_of() { 28 | let numbers = [1, 2, 3, 4, 5]; 29 | for number in numbers { 30 | println!("{}", number); 31 | } 32 | } 33 | 34 | fn while_not_done() { 35 | struct Worker { 36 | data: Vec<&'static str>, 37 | } 38 | impl Worker { 39 | fn doWork(&mut self) -> Option<&'static str> { 40 | self.data.pop() 41 | } 42 | } 43 | let mut obj = Worker { 44 | data: vec!["a", "b", "c"], 45 | }; 46 | 47 | while let Some(data) = obj.doWork() { 48 | println!("{}", data); 49 | } 50 | } 51 | 52 | fn while_true() { 53 | let mut n = 0; 54 | loop { 55 | n += 1; 56 | if n > 3 { 57 | break; 58 | } 59 | } 60 | println!("Finished. n={}", n); 61 | } 62 | 63 | #[allow(clippy::never_loop)] 64 | fn labels() { 65 | println!("Start"); 66 | 'outer: loop { 67 | loop { 68 | break 'outer; 69 | } 70 | } 71 | println!("Finished"); 72 | } 73 | 74 | #[allow(clippy::never_loop)] 75 | fn loop_expressions() { 76 | let value = loop { 77 | if true { 78 | break "A"; 79 | } else { 80 | break "B"; 81 | } 82 | }; 83 | println!("Loop value is: {}", value); 84 | } 85 | -------------------------------------------------------------------------------- /src/crates/day-17/iterators/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-17-iterators" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-17/iterators/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | 3 | fn main() { 4 | filter(); 5 | find(); 6 | for_each(); 7 | join(); 8 | map(); 9 | push_pop(); 10 | shift_unshift(); 11 | } 12 | 13 | fn filter() { 14 | let numbers = [1, 2, 3, 4, 5]; 15 | let even: Vec<_> = numbers.iter().filter(|x| *x % 2 == 0).collect(); 16 | println!("{:?}", even); 17 | } 18 | 19 | fn find() { 20 | let numbers = [1, 2, 3, 4, 5]; 21 | let mut iter = numbers.iter(); 22 | let first_even = iter.find(|x| *x % 2 == 0); 23 | println!("{:?}", first_even.unwrap()); 24 | // let second_even = iter.find(|x| *x % 2 == 0); 25 | // println!("{:?}", second_even.unwrap()); 26 | } 27 | 28 | fn for_each() { 29 | let numbers = [1, 2, 3]; 30 | numbers.iter().for_each(|x| println!("{}", x)); 31 | } 32 | 33 | fn join() { 34 | let names = ["Sam", "Janet", "Hunter"]; 35 | let csv = names.join(","); 36 | println!("{}", csv); 37 | } 38 | 39 | fn map() { 40 | let list = vec![1, 2, 3]; 41 | let doubled: Vec<_> = list.iter().map(|num| num * 2).collect(); 42 | println!("{:?}", doubled) 43 | } 44 | 45 | fn push_pop() { 46 | let mut list = vec![1, 2]; 47 | list.push(3); 48 | println!("{:?}", list.pop()); 49 | println!("{:?}", list.pop()); 50 | println!("{:?}", list.pop()); 51 | println!("{:?}", list.pop()); 52 | } 53 | 54 | fn shift_unshift() { 55 | let mut list = VecDeque::from([1, 2]); 56 | list.push_front(0); 57 | println!("{:?}", list.pop_front()); 58 | println!("{:?}", list.pop_front()); 59 | println!("{:?}", list.pop_front()); 60 | println!("{:?}", list.pop_front()); 61 | } 62 | -------------------------------------------------------------------------------- /src/crates/day-17/names/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-17-names" 3 | version = "0.0.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 | serde = { version = "1.0", features = ["derive"] } 10 | serde_json = "1.0" 11 | regex = "1.5" 12 | -------------------------------------------------------------------------------- /src/crates/day-17/names/src/main.rs: -------------------------------------------------------------------------------- 1 | #[derive(serde::Serialize, serde::Deserialize)] 2 | struct Names { 3 | names: Vec, 4 | } 5 | 6 | impl Names { 7 | fn search>(&self, regex_string: T) -> impl Iterator { 8 | let regex = regex::Regex::new(regex_string.as_ref()).unwrap(); 9 | self.names.iter().filter(move |name| regex.is_match(name)) 10 | } 11 | } 12 | 13 | fn main() { 14 | let raw = include_str!("./names.json"); 15 | let names: Names = serde_json::from_str(raw).unwrap(); 16 | let mut result = names.search("er$"); 17 | 18 | println!("First 5 names that end in 'er':"); 19 | 20 | for i in 0..5 { 21 | println!("{}: {}", i + 1, result.next().unwrap()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/crates/day-18/async/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 = "bitflags" 7 | version = "1.3.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 10 | 11 | [[package]] 12 | name = "bytes" 13 | version = "1.1.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 16 | 17 | [[package]] 18 | name = "cfg-if" 19 | version = "1.0.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 22 | 23 | [[package]] 24 | name = "day-18-async" 25 | version = "0.0.0" 26 | dependencies = [ 27 | "thiserror", 28 | "tokio", 29 | ] 30 | 31 | [[package]] 32 | name = "hermit-abi" 33 | version = "0.1.19" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 36 | dependencies = [ 37 | "libc", 38 | ] 39 | 40 | [[package]] 41 | name = "instant" 42 | version = "0.1.12" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 45 | dependencies = [ 46 | "cfg-if", 47 | ] 48 | 49 | [[package]] 50 | name = "libc" 51 | version = "0.2.112" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" 54 | 55 | [[package]] 56 | name = "lock_api" 57 | version = "0.4.5" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" 60 | dependencies = [ 61 | "scopeguard", 62 | ] 63 | 64 | [[package]] 65 | name = "log" 66 | version = "0.4.14" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 69 | dependencies = [ 70 | "cfg-if", 71 | ] 72 | 73 | [[package]] 74 | name = "memchr" 75 | version = "2.4.1" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 78 | 79 | [[package]] 80 | name = "mio" 81 | version = "0.7.14" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" 84 | dependencies = [ 85 | "libc", 86 | "log", 87 | "miow", 88 | "ntapi", 89 | "winapi", 90 | ] 91 | 92 | [[package]] 93 | name = "miow" 94 | version = "0.3.7" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 97 | dependencies = [ 98 | "winapi", 99 | ] 100 | 101 | [[package]] 102 | name = "ntapi" 103 | version = "0.3.6" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 106 | dependencies = [ 107 | "winapi", 108 | ] 109 | 110 | [[package]] 111 | name = "num_cpus" 112 | version = "1.13.0" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 115 | dependencies = [ 116 | "hermit-abi", 117 | "libc", 118 | ] 119 | 120 | [[package]] 121 | name = "once_cell" 122 | version = "1.9.0" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" 125 | 126 | [[package]] 127 | name = "parking_lot" 128 | version = "0.11.2" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 131 | dependencies = [ 132 | "instant", 133 | "lock_api", 134 | "parking_lot_core", 135 | ] 136 | 137 | [[package]] 138 | name = "parking_lot_core" 139 | version = "0.8.5" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 142 | dependencies = [ 143 | "cfg-if", 144 | "instant", 145 | "libc", 146 | "redox_syscall", 147 | "smallvec", 148 | "winapi", 149 | ] 150 | 151 | [[package]] 152 | name = "pin-project-lite" 153 | version = "0.2.7" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 156 | 157 | [[package]] 158 | name = "proc-macro2" 159 | version = "1.0.34" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1" 162 | dependencies = [ 163 | "unicode-xid", 164 | ] 165 | 166 | [[package]] 167 | name = "quote" 168 | version = "1.0.10" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" 171 | dependencies = [ 172 | "proc-macro2", 173 | ] 174 | 175 | [[package]] 176 | name = "redox_syscall" 177 | version = "0.2.10" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 180 | dependencies = [ 181 | "bitflags", 182 | ] 183 | 184 | [[package]] 185 | name = "scopeguard" 186 | version = "1.1.0" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 189 | 190 | [[package]] 191 | name = "signal-hook-registry" 192 | version = "1.4.0" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 195 | dependencies = [ 196 | "libc", 197 | ] 198 | 199 | [[package]] 200 | name = "smallvec" 201 | version = "1.7.0" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" 204 | 205 | [[package]] 206 | name = "syn" 207 | version = "1.0.82" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" 210 | dependencies = [ 211 | "proc-macro2", 212 | "quote", 213 | "unicode-xid", 214 | ] 215 | 216 | [[package]] 217 | name = "thiserror" 218 | version = "1.0.30" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 221 | dependencies = [ 222 | "thiserror-impl", 223 | ] 224 | 225 | [[package]] 226 | name = "thiserror-impl" 227 | version = "1.0.30" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 230 | dependencies = [ 231 | "proc-macro2", 232 | "quote", 233 | "syn", 234 | ] 235 | 236 | [[package]] 237 | name = "tokio" 238 | version = "1.15.0" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" 241 | dependencies = [ 242 | "bytes", 243 | "libc", 244 | "memchr", 245 | "mio", 246 | "num_cpus", 247 | "once_cell", 248 | "parking_lot", 249 | "pin-project-lite", 250 | "signal-hook-registry", 251 | "tokio-macros", 252 | "winapi", 253 | ] 254 | 255 | [[package]] 256 | name = "tokio-macros" 257 | version = "1.7.0" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" 260 | dependencies = [ 261 | "proc-macro2", 262 | "quote", 263 | "syn", 264 | ] 265 | 266 | [[package]] 267 | name = "unicode-xid" 268 | version = "0.2.2" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 271 | 272 | [[package]] 273 | name = "winapi" 274 | version = "0.3.9" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 277 | dependencies = [ 278 | "winapi-i686-pc-windows-gnu", 279 | "winapi-x86_64-pc-windows-gnu", 280 | ] 281 | 282 | [[package]] 283 | name = "winapi-i686-pc-windows-gnu" 284 | version = "0.4.0" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 287 | 288 | [[package]] 289 | name = "winapi-x86_64-pc-windows-gnu" 290 | version = "0.4.0" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 293 | -------------------------------------------------------------------------------- /src/crates/day-18/async/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-18-async" 3 | version = "0.0.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 | thiserror = "1.0" 10 | tokio = { version = "1", features = ["full"] } 11 | 12 | [[bin]] 13 | path = "./src/simple.rs" 14 | harness = false 15 | test = false 16 | name = "simple" 17 | 18 | [[bin]] 19 | path = "./src/fs.rs" 20 | harness = false 21 | test = false 22 | name = "fs" 23 | 24 | [[bin]] 25 | path = "./src/send-sync.rs" 26 | harness = false 27 | test = false 28 | name = "send-sync" 29 | 30 | [[bin]] 31 | path = "./src/send-sync2.rs" 32 | harness = false 33 | test = false 34 | name = "send-sync2" 35 | 36 | [[bin]] 37 | path = "./src/lazy.rs" 38 | harness = false 39 | test = false 40 | name = "lazy" 41 | 42 | [[bin]] 43 | path = "./src/async-blocks.rs" 44 | harness = false 45 | test = false 46 | name = "async-blocks" 47 | -------------------------------------------------------------------------------- /src/crates/day-18/async/src/async-blocks.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() { 3 | let msg = "Hello world".to_owned(); 4 | 5 | let async_block = || async { 6 | println!("{}", msg); 7 | }; 8 | async_block().await; 9 | 10 | let closure = || async { 11 | println!("{}", msg); 12 | }; 13 | closure().await; 14 | } 15 | -------------------------------------------------------------------------------- /src/crates/day-18/async/src/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Error, Debug)] 4 | pub enum Error { 5 | #[error("Error {0}")] 6 | Msg(String), 7 | #[error(transparent)] 8 | IOError(#[from] std::io::Error), 9 | } 10 | -------------------------------------------------------------------------------- /src/crates/day-18/async/src/fs.rs: -------------------------------------------------------------------------------- 1 | pub mod error; 2 | 3 | use std::path::PathBuf; 4 | 5 | type Result = std::result::Result; 6 | 7 | #[tokio::main] 8 | async fn main() -> Result<()> { 9 | ls(None).await?; 10 | Ok(()) 11 | } 12 | 13 | async fn ls(dir: Option) -> Result<()> { 14 | let dir = match dir { 15 | Some(value) => value, 16 | None => std::env::current_dir()?, 17 | }; 18 | 19 | let mut files = tokio::fs::read_dir(dir).await?; 20 | while let Some(file) = files.next_entry().await? { 21 | println!("{}", file.file_name().to_string_lossy()) 22 | } 23 | Ok(()) 24 | } 25 | -------------------------------------------------------------------------------- /src/crates/day-18/async/src/lazy.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() { 3 | println!("One"); 4 | let future = prints_two(); 5 | println!("Three"); 6 | // Uncomment and move the following line around to see how the behavior changes. 7 | // future.await; 8 | } 9 | 10 | async fn prints_two() { 11 | println!("Two") 12 | } 13 | -------------------------------------------------------------------------------- /src/crates/day-18/async/src/send-sync.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | use tokio::task::JoinHandle; 3 | 4 | #[tokio::main] 5 | async fn main() { 6 | let mark_twain = "Samuel Clemens".to_owned(); 7 | 8 | async_print(mark_twain).await; 9 | } 10 | 11 | fn async_print(msg: T) -> JoinHandle<()> { 12 | tokio::task::spawn(async move { 13 | println!("{}", msg); 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/crates/day-18/async/src/simple.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() { 3 | let msg = regular_fn(); 4 | println!("{}", msg); 5 | 6 | let msg = async_fn().await; 7 | println!("{}", msg); 8 | } 9 | 10 | fn regular_fn() -> String { 11 | "I'm a regular function".to_owned() 12 | } 13 | 14 | // The return value here is actually: impl Future 15 | async fn async_fn() -> String { 16 | "I'm an async function".to_owned() 17 | } 18 | -------------------------------------------------------------------------------- /src/crates/day-19/project/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 = "cli" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "my-lib", 10 | ] 11 | 12 | [[package]] 13 | name = "my-lib" 14 | version = "0.1.0" 15 | -------------------------------------------------------------------------------- /src/crates/day-19/project/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["crates/*"] 3 | -------------------------------------------------------------------------------- /src/crates/day-19/project/crates/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cli" 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 | my-lib = { path = "../my-lib" } 10 | -------------------------------------------------------------------------------- /src/crates/day-19/project/crates/cli/src/main.rs: -------------------------------------------------------------------------------- 1 | use my_lib::Module; 2 | 3 | fn main() { 4 | match Module::from_file("./module.wasm") { 5 | Ok(_) => { 6 | println!("Module loaded"); 7 | } 8 | Err(e) => { 9 | println!("Module failed to load: {}", e); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/crates/day-19/project/crates/my-lib/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /src/crates/day-19/project/crates/my-lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "my-lib" 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 | -------------------------------------------------------------------------------- /src/crates/day-19/project/crates/my-lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | pub struct Module {} 3 | 4 | impl Module { 5 | pub fn from_file>(path: T) -> Result { 6 | Ok(Self {}) 7 | } 8 | } 9 | 10 | #[cfg(test)] 11 | mod tests { 12 | use super::*; 13 | #[test] 14 | fn loads_wasm_file() { 15 | let result = Module::from_file("./tests/test.wasm"); 16 | assert!(result.is_ok()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/crates/day-20/project/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["crates/*"] 3 | -------------------------------------------------------------------------------- /src/crates/day-20/project/crates/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cli" 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 | my-lib = { path = "../my-lib" } 10 | log = "0.4" 11 | env_logger = "0.9" 12 | structopt = "0.3" 13 | -------------------------------------------------------------------------------- /src/crates/day-20/project/crates/cli/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use my_lib::Module; 4 | use structopt::{clap::AppSettings, StructOpt}; 5 | 6 | #[macro_use] 7 | extern crate log; 8 | 9 | #[derive(StructOpt)] 10 | #[structopt( 11 | name = "wasm-runner", 12 | about = "Sample project from https://vino.dev/blog/node-to-rust-day-1-rustup/", 13 | global_settings(&[ 14 | AppSettings::ColoredHelp 15 | ]), 16 | )] 17 | struct CliOptions { 18 | /// The WebAssembly file to load. 19 | #[structopt(parse(from_os_str))] 20 | pub(crate) file_path: PathBuf, 21 | } 22 | 23 | fn main() { 24 | env_logger::init(); 25 | debug!("Initialized logger"); 26 | 27 | let options = CliOptions::from_args(); 28 | 29 | match Module::from_file(&options.file_path) { 30 | Ok(_) => { 31 | info!("Module loaded"); 32 | } 33 | Err(e) => { 34 | error!("Module failed to load: {}", e); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/crates/day-20/project/crates/my-lib/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /src/crates/day-20/project/crates/my-lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "my-lib" 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 | log = "0.4" 10 | -------------------------------------------------------------------------------- /src/crates/day-20/project/crates/my-lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | 3 | #[macro_use] 4 | extern crate log; 5 | 6 | pub struct Module {} 7 | 8 | impl Module { 9 | pub fn from_file>(path: T) -> Result { 10 | debug!("Loading wasm file from {:?}", path.as_ref()); 11 | Ok(Self {}) 12 | } 13 | } 14 | 15 | #[cfg(test)] 16 | mod tests { 17 | use super::*; 18 | #[test] 19 | fn loads_wasm_file() { 20 | let result = Module::from_file("./tests/test.wasm"); 21 | assert!(result.is_ok()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/crates/day-21/project/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["crates/*"] 3 | -------------------------------------------------------------------------------- /src/crates/day-21/project/crates/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cli" 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 | my-lib = { path = "../my-lib" } 10 | log = "0.4" 11 | env_logger = "0.9" 12 | structopt = "0.3" 13 | rmp-serde = "0.15" 14 | anyhow = "1.0" 15 | -------------------------------------------------------------------------------- /src/crates/day-21/project/crates/cli/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use my_lib::Module; 4 | use structopt::{clap::AppSettings, StructOpt}; 5 | 6 | #[macro_use] 7 | extern crate log; 8 | 9 | #[derive(StructOpt)] 10 | #[structopt( 11 | name = "wasm-runner", 12 | about = "Sample project from https://vino.dev/blog/node-to-rust-day-1-rustup/", 13 | global_settings(&[ 14 | AppSettings::ColoredHelp 15 | ]), 16 | )] 17 | struct CliOptions { 18 | /// The WebAssembly file to load. 19 | #[structopt(parse(from_os_str))] 20 | pub(crate) file_path: PathBuf, 21 | 22 | /// The operation to invoke in the WASM file. 23 | #[structopt()] 24 | pub(crate) operation: String, 25 | 26 | /// The data to pass to the operation 27 | #[structopt()] 28 | pub(crate) data: String, 29 | } 30 | 31 | fn main() { 32 | env_logger::init(); 33 | debug!("Initialized logger"); 34 | 35 | let options = CliOptions::from_args(); 36 | 37 | match run(options) { 38 | Ok(output) => { 39 | println!("{}", output); 40 | info!("Done"); 41 | } 42 | Err(e) => { 43 | error!("Module failed to load: {}", e); 44 | std::process::exit(1); 45 | } 46 | }; 47 | } 48 | 49 | fn run(options: CliOptions) -> anyhow::Result { 50 | let module = Module::from_file(&options.file_path)?; 51 | info!("Module loaded"); 52 | 53 | let bytes = rmp_serde::to_vec(&options.data)?; 54 | let result = module.run(&options.operation, &bytes)?; 55 | let unpacked: String = rmp_serde::from_read_ref(&result)?; 56 | 57 | Ok(unpacked) 58 | } 59 | -------------------------------------------------------------------------------- /src/crates/day-21/project/crates/my-lib/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /src/crates/day-21/project/crates/my-lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "my-lib" 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 | log = "0.4" 10 | thiserror = "1.0" 11 | wapc = "0.10.1" 12 | wasmtime-provider = "0.0.7" 13 | 14 | [dev-dependencies] 15 | rmp-serde = "0.15" 16 | -------------------------------------------------------------------------------- /src/crates/day-21/project/crates/my-lib/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | #[derive(thiserror::Error, Debug)] 4 | pub enum Error { 5 | #[error(transparent)] 6 | WapcError(#[from] wapc::errors::Error), 7 | #[error("Could not read file {0}: {1}")] 8 | FileNotReadable(PathBuf, String), 9 | } 10 | -------------------------------------------------------------------------------- /src/crates/day-21/project/crates/my-lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod error; 2 | 3 | use std::{fs, path::Path}; 4 | use wapc::WapcHost; 5 | 6 | use error::Error; 7 | 8 | #[macro_use] 9 | extern crate log; 10 | 11 | pub struct Module { 12 | host: WapcHost, 13 | } 14 | 15 | impl Module { 16 | pub fn new(bytes: &[u8]) -> Result { 17 | let engine = wasmtime_provider::WasmtimeEngineProvider::new(bytes, None); 18 | 19 | let host = WapcHost::new(Box::new(engine), |_id, binding, ns, operation, payload| { 20 | trace!( 21 | "Guest called: binding={}, namespace={}, operation={}, payload={:?}", 22 | binding, 23 | ns, 24 | operation, 25 | payload 26 | ); 27 | Err("Not implemented".into()) 28 | })?; 29 | Ok(Module { host }) 30 | } 31 | 32 | pub fn from_file>(path: T) -> Result { 33 | debug!("Loading wasm file from {:?}", path.as_ref()); 34 | let bytes = fs::read(path.as_ref()) 35 | .map_err(|e| Error::FileNotReadable(path.as_ref().to_path_buf(), e.to_string()))?; 36 | Self::new(&bytes) 37 | } 38 | 39 | pub fn run(&self, operation: &str, payload: &[u8]) -> Result, Error> { 40 | debug!("Invoking {}", operation); 41 | let result = self.host.call(operation, payload)?; 42 | Ok(result) 43 | } 44 | } 45 | 46 | #[cfg(test)] 47 | mod tests { 48 | use super::*; 49 | #[test] 50 | fn loads_wasm_file() { 51 | let result = Module::from_file("./tests/test.wasm"); 52 | assert!(result.is_ok()); 53 | } 54 | 55 | #[test] 56 | fn runs_operation() -> Result<(), Error> { 57 | let module = Module::from_file("./tests/test.wasm")?; 58 | 59 | let bytes = rmp_serde::to_vec("World").unwrap(); 60 | let payload = module.run("hello", &bytes)?; 61 | let unpacked: String = rmp_serde::decode::from_read_ref(&payload).unwrap(); 62 | assert_eq!(unpacked, "Hello, World."); 63 | Ok(()) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/crates/day-21/project/crates/my-lib/tests/test.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/src/crates/day-21/project/crates/my-lib/tests/test.wasm -------------------------------------------------------------------------------- /src/crates/day-21/wapc-guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wapc-guest" 3 | version = "0.0.1" 4 | description = "Sample guest" 5 | authors = [""] 6 | edition = "2018" 7 | license = "Apache-2.0" 8 | 9 | [lib] 10 | crate-type = ["cdylib", "rlib"] 11 | 12 | [features] 13 | default = ["guest"] 14 | guest = [] 15 | 16 | [dependencies] 17 | wapc-guest = "0.4.0" 18 | serde = { version = "1.0.115", features = ["derive"] } 19 | serde_json = "1.0.57" 20 | serde_derive = "1.0.115" 21 | serde_bytes = "0.11.5" 22 | rmp-serde = "0.14.4" 23 | lazy_static = "1.4.0" 24 | 25 | [dev-dependencies] 26 | structopt = "0.3.17" 27 | serde_json = "1.0.57" 28 | base64 = "0.12.3" 29 | 30 | [profile.release] 31 | # Optimize for small code size 32 | opt-level = "s" 33 | lto = true 34 | -------------------------------------------------------------------------------- /src/crates/day-21/wapc-guest/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all deps codegen build clean doc test 2 | 3 | all: deps codegen build 4 | 5 | deps: 6 | 7 | codegen: 8 | wapc generate codegen.yaml 9 | 10 | build: 11 | cargo build --target wasm32-unknown-unknown --release 12 | mkdir -p build && cp target/wasm32-unknown-unknown/release/*.wasm build/ 13 | 14 | # Rust builds accrue disk space over time (specifically the target directory), 15 | # so running `make clean` should be done periodically. 16 | clean: 17 | cargo clean 18 | rm -Rf build 19 | 20 | doc: 21 | 22 | test: build 23 | cargo test 24 | -------------------------------------------------------------------------------- /src/crates/day-21/wapc-guest/build/wapc_guest.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/src/crates/day-21/wapc-guest/build/wapc_guest.wasm -------------------------------------------------------------------------------- /src/crates/day-21/wapc-guest/codegen.yaml: -------------------------------------------------------------------------------- 1 | schema: schema.widl 2 | generates: 3 | src/generated.rs: 4 | module: '@wapc/widl-codegen/rust' 5 | visitorClass: ModuleVisitor 6 | src/lib.rs: 7 | ifNotExists: true 8 | module: '@wapc/widl-codegen/rust' 9 | visitorClass: ScaffoldVisitor 10 | config: 11 | use: generated -------------------------------------------------------------------------------- /src/crates/day-21/wapc-guest/schema.widl: -------------------------------------------------------------------------------- 1 | interface { 2 | hello{name:string}: string 3 | } 4 | -------------------------------------------------------------------------------- /src/crates/day-21/wapc-guest/src/generated.rs: -------------------------------------------------------------------------------- 1 | extern crate rmp_serde as rmps; 2 | use rmps::{Deserializer, Serializer}; 3 | use serde::{Deserialize, Serialize}; 4 | use std::io::Cursor; 5 | 6 | #[cfg(feature = "guest")] 7 | extern crate wapc_guest as guest; 8 | #[cfg(feature = "guest")] 9 | use guest::prelude::*; 10 | 11 | #[cfg(feature = "guest")] 12 | pub struct Host { 13 | binding: String, 14 | } 15 | 16 | #[cfg(feature = "guest")] 17 | impl Default for Host { 18 | fn default() -> Self { 19 | Host { 20 | binding: "default".to_string(), 21 | } 22 | } 23 | } 24 | 25 | /// Creates a named host binding 26 | #[cfg(feature = "guest")] 27 | pub fn host(binding: &str) -> Host { 28 | Host { 29 | binding: binding.to_string(), 30 | } 31 | } 32 | 33 | /// Creates the default host binding 34 | #[cfg(feature = "guest")] 35 | pub fn default() -> Host { 36 | Host::default() 37 | } 38 | 39 | #[cfg(feature = "guest")] 40 | impl Host { 41 | pub fn hello(&self, name: String) -> HandlerResult { 42 | host_call(&self.binding, "", "hello", &serialize(name)?) 43 | .map(|vec| { 44 | let resp = deserialize::(vec.as_ref()).unwrap(); 45 | resp 46 | }) 47 | .map_err(|e| e.into()) 48 | } 49 | } 50 | 51 | #[cfg(feature = "guest")] 52 | pub struct Handlers {} 53 | 54 | #[cfg(feature = "guest")] 55 | impl Handlers { 56 | pub fn register_hello(f: fn(String) -> HandlerResult) { 57 | *HELLO.write().unwrap() = Some(f); 58 | register_function(&"hello", hello_wrapper); 59 | } 60 | } 61 | 62 | #[cfg(feature = "guest")] 63 | lazy_static::lazy_static! { 64 | static ref HELLO: std::sync::RwLock HandlerResult>> = std::sync::RwLock::new(None); 65 | } 66 | 67 | #[cfg(feature = "guest")] 68 | fn hello_wrapper(input_payload: &[u8]) -> CallResult { 69 | let input = deserialize::(input_payload)?; 70 | let lock = HELLO.read().unwrap().unwrap(); 71 | let result = lock(input)?; 72 | serialize(result) 73 | } 74 | 75 | /// The standard function for serializing codec structs into a format that can be 76 | /// used for message exchange between actor and host. Use of any other function to 77 | /// serialize could result in breaking incompatibilities. 78 | pub fn serialize( 79 | item: T, 80 | ) -> ::std::result::Result, Box> 81 | where 82 | T: Serialize, 83 | { 84 | let mut buf = Vec::new(); 85 | item.serialize(&mut Serializer::new(&mut buf).with_struct_map())?; 86 | Ok(buf) 87 | } 88 | 89 | /// The standard function for de-serializing codec structs from a format suitable 90 | /// for message exchange between actor and host. Use of any other function to 91 | /// deserialize could result in breaking incompatibilities. 92 | pub fn deserialize<'de, T: Deserialize<'de>>( 93 | buf: &[u8], 94 | ) -> ::std::result::Result> { 95 | let mut de = Deserializer::new(Cursor::new(buf)); 96 | match Deserialize::deserialize(&mut de) { 97 | Ok(t) => Ok(t), 98 | Err(e) => Err(format!("Failed to de-serialize: {}", e).into()), 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/crates/day-21/wapc-guest/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod generated; 2 | pub use generated::*; 3 | use wapc_guest::prelude::*; 4 | 5 | #[no_mangle] 6 | pub fn wapc_init() { 7 | Handlers::register_hello(hello); 8 | } 9 | 10 | fn hello(name: String) -> HandlerResult { 11 | Ok(format!("Hello, {}.", name)) 12 | } 13 | -------------------------------------------------------------------------------- /src/crates/day-22/project/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["crates/*"] 3 | -------------------------------------------------------------------------------- /src/crates/day-22/project/blog.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ title }} 4 | 5 | 6 |

{{ title }}

7 |

By {{ author }}

8 |

{{ body }}

9 | 10 | 11 | -------------------------------------------------------------------------------- /src/crates/day-22/project/blog.json: -------------------------------------------------------------------------------- 1 | { 2 | "blog": { 3 | "title": "The Adventures of Tom Sawyer", 4 | "body": "“TOM!”\n\nNo answer.\n\n“TOM!”\n\nNo answer.\n\n“What’s gone with that boy, I wonder? You TOM!”\n\nNo answer.", 5 | "author": "Mark Twain" 6 | }, 7 | "template": "{{ title }}

{{ title }}

By {{ author }}

{{ body }}

" 8 | } 9 | -------------------------------------------------------------------------------- /src/crates/day-22/project/blog.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/src/crates/day-22/project/blog.wasm -------------------------------------------------------------------------------- /src/crates/day-22/project/crates/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wapc-runner" 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 | my-lib = { path = "../my-lib" } 10 | log = "0.4" 11 | env_logger = "0.9" 12 | structopt = "0.3" 13 | rmp-serde = "0.15" 14 | anyhow = "1.0" 15 | serde_json = "1.0" 16 | -------------------------------------------------------------------------------- /src/crates/day-22/project/crates/cli/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{fs, path::PathBuf}; 2 | 3 | use my_lib::Module; 4 | use structopt::{clap::AppSettings, StructOpt}; 5 | 6 | #[macro_use] 7 | extern crate log; 8 | 9 | #[derive(StructOpt)] 10 | #[structopt( 11 | name = "wasm-runner", 12 | about = "Sample project from https://vino.dev/blog/node-to-rust-day-1-rustup/", 13 | global_settings(&[ 14 | AppSettings::ColoredHelp 15 | ]), 16 | )] 17 | struct CliOptions { 18 | /// The WebAssembly file to load. 19 | #[structopt(parse(from_os_str))] 20 | pub(crate) file_path: PathBuf, 21 | 22 | /// The operation to invoke in the WASM file. 23 | #[structopt()] 24 | pub(crate) operation: String, 25 | 26 | /// The path to the JSON data to use as input. 27 | #[structopt(parse(from_os_str))] 28 | pub(crate) json_path: PathBuf, 29 | } 30 | 31 | fn main() { 32 | env_logger::init(); 33 | debug!("Initialized logger"); 34 | 35 | let options = CliOptions::from_args(); 36 | 37 | match run(options) { 38 | Ok(output) => { 39 | println!("{}", output); 40 | info!("Done"); 41 | } 42 | Err(e) => { 43 | error!("Module failed to load: {}", e); 44 | std::process::exit(1); 45 | } 46 | }; 47 | } 48 | 49 | fn run(options: CliOptions) -> anyhow::Result { 50 | let module = Module::from_file(&options.file_path)?; 51 | info!("Module loaded"); 52 | 53 | let json = fs::read_to_string(options.json_path)?; 54 | let data: serde_json::Value = serde_json::from_str(&json)?; 55 | debug!("Data: {:?}", data); 56 | 57 | let bytes = rmp_serde::to_vec(&data)?; 58 | 59 | debug!("Running {} with payload: {:?}", options.operation, bytes); 60 | let result = module.run(&options.operation, &bytes)?; 61 | let unpacked: serde_json::Value = rmp_serde::from_read_ref(&result)?; 62 | 63 | Ok(unpacked) 64 | } 65 | -------------------------------------------------------------------------------- /src/crates/day-22/project/crates/my-lib/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /src/crates/day-22/project/crates/my-lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "my-lib" 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 | log = "0.4" 10 | thiserror = "1.0" 11 | wapc = "0.10.1" 12 | wasmtime-provider = "0.0.7" 13 | 14 | [dev-dependencies] 15 | rmp-serde = "0.15" 16 | -------------------------------------------------------------------------------- /src/crates/day-22/project/crates/my-lib/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | #[derive(thiserror::Error, Debug)] 4 | pub enum Error { 5 | #[error(transparent)] 6 | WapcError(#[from] wapc::errors::Error), 7 | #[error("Could not read file {0}: {1}")] 8 | FileNotReadable(PathBuf, String), 9 | } 10 | -------------------------------------------------------------------------------- /src/crates/day-22/project/crates/my-lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod error; 2 | 3 | use std::{fs, path::Path}; 4 | use wapc::WapcHost; 5 | 6 | use error::Error; 7 | 8 | #[macro_use] 9 | extern crate log; 10 | 11 | pub struct Module { 12 | host: WapcHost, 13 | } 14 | 15 | impl Module { 16 | pub fn new(bytes: &[u8]) -> Result { 17 | let engine = wasmtime_provider::WasmtimeEngineProvider::new(bytes, None); 18 | 19 | let host = WapcHost::new(Box::new(engine), |_id, binding, ns, operation, payload| { 20 | trace!( 21 | "Guest called: binding={}, namespace={}, operation={}, payload={:?}", 22 | binding, 23 | ns, 24 | operation, 25 | payload 26 | ); 27 | Err("Not implemented".into()) 28 | })?; 29 | Ok(Module { host }) 30 | } 31 | 32 | pub fn from_file>(path: T) -> Result { 33 | debug!("Loading wasm file from {:?}", path.as_ref()); 34 | let bytes = fs::read(path.as_ref()) 35 | .map_err(|e| Error::FileNotReadable(path.as_ref().to_path_buf(), e.to_string()))?; 36 | Self::new(&bytes) 37 | } 38 | 39 | pub fn run(&self, operation: &str, payload: &[u8]) -> Result, Error> { 40 | debug!("Invoking {}", operation); 41 | let result = self.host.call(operation, payload)?; 42 | Ok(result) 43 | } 44 | } 45 | 46 | #[cfg(test)] 47 | mod tests { 48 | use super::*; 49 | #[test] 50 | fn loads_wasm_file() { 51 | let result = Module::from_file("./tests/test.wasm"); 52 | assert!(result.is_ok()); 53 | } 54 | 55 | #[test] 56 | fn runs_operation() -> Result<(), Error> { 57 | let module = Module::from_file("./tests/test.wasm")?; 58 | 59 | let bytes = rmp_serde::to_vec("World").unwrap(); 60 | let payload = module.run("hello", &bytes)?; 61 | let unpacked: String = rmp_serde::decode::from_read_ref(&payload).unwrap(); 62 | assert_eq!(unpacked, "Hello, World."); 63 | Ok(()) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/crates/day-22/project/crates/my-lib/tests/test.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/src/crates/day-22/project/crates/my-lib/tests/test.wasm -------------------------------------------------------------------------------- /src/crates/day-22/project/hello.json: -------------------------------------------------------------------------------- 1 | "Potter" 2 | -------------------------------------------------------------------------------- /src/crates/day-22/serde/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 = "bitflags" 7 | version = "1.3.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 10 | 11 | [[package]] 12 | name = "bytes" 13 | version = "1.1.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 16 | 17 | [[package]] 18 | name = "cfg-if" 19 | version = "1.0.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 22 | 23 | [[package]] 24 | name = "day-18-async" 25 | version = "0.0.0" 26 | dependencies = [ 27 | "thiserror", 28 | "tokio", 29 | ] 30 | 31 | [[package]] 32 | name = "hermit-abi" 33 | version = "0.1.19" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 36 | dependencies = [ 37 | "libc", 38 | ] 39 | 40 | [[package]] 41 | name = "instant" 42 | version = "0.1.12" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 45 | dependencies = [ 46 | "cfg-if", 47 | ] 48 | 49 | [[package]] 50 | name = "libc" 51 | version = "0.2.112" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" 54 | 55 | [[package]] 56 | name = "lock_api" 57 | version = "0.4.5" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" 60 | dependencies = [ 61 | "scopeguard", 62 | ] 63 | 64 | [[package]] 65 | name = "log" 66 | version = "0.4.14" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 69 | dependencies = [ 70 | "cfg-if", 71 | ] 72 | 73 | [[package]] 74 | name = "memchr" 75 | version = "2.4.1" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 78 | 79 | [[package]] 80 | name = "mio" 81 | version = "0.7.14" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" 84 | dependencies = [ 85 | "libc", 86 | "log", 87 | "miow", 88 | "ntapi", 89 | "winapi", 90 | ] 91 | 92 | [[package]] 93 | name = "miow" 94 | version = "0.3.7" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 97 | dependencies = [ 98 | "winapi", 99 | ] 100 | 101 | [[package]] 102 | name = "ntapi" 103 | version = "0.3.6" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 106 | dependencies = [ 107 | "winapi", 108 | ] 109 | 110 | [[package]] 111 | name = "num_cpus" 112 | version = "1.13.0" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 115 | dependencies = [ 116 | "hermit-abi", 117 | "libc", 118 | ] 119 | 120 | [[package]] 121 | name = "once_cell" 122 | version = "1.9.0" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" 125 | 126 | [[package]] 127 | name = "parking_lot" 128 | version = "0.11.2" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 131 | dependencies = [ 132 | "instant", 133 | "lock_api", 134 | "parking_lot_core", 135 | ] 136 | 137 | [[package]] 138 | name = "parking_lot_core" 139 | version = "0.8.5" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 142 | dependencies = [ 143 | "cfg-if", 144 | "instant", 145 | "libc", 146 | "redox_syscall", 147 | "smallvec", 148 | "winapi", 149 | ] 150 | 151 | [[package]] 152 | name = "pin-project-lite" 153 | version = "0.2.7" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 156 | 157 | [[package]] 158 | name = "proc-macro2" 159 | version = "1.0.34" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1" 162 | dependencies = [ 163 | "unicode-xid", 164 | ] 165 | 166 | [[package]] 167 | name = "quote" 168 | version = "1.0.10" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" 171 | dependencies = [ 172 | "proc-macro2", 173 | ] 174 | 175 | [[package]] 176 | name = "redox_syscall" 177 | version = "0.2.10" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 180 | dependencies = [ 181 | "bitflags", 182 | ] 183 | 184 | [[package]] 185 | name = "scopeguard" 186 | version = "1.1.0" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 189 | 190 | [[package]] 191 | name = "signal-hook-registry" 192 | version = "1.4.0" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 195 | dependencies = [ 196 | "libc", 197 | ] 198 | 199 | [[package]] 200 | name = "smallvec" 201 | version = "1.7.0" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" 204 | 205 | [[package]] 206 | name = "syn" 207 | version = "1.0.82" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" 210 | dependencies = [ 211 | "proc-macro2", 212 | "quote", 213 | "unicode-xid", 214 | ] 215 | 216 | [[package]] 217 | name = "thiserror" 218 | version = "1.0.30" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 221 | dependencies = [ 222 | "thiserror-impl", 223 | ] 224 | 225 | [[package]] 226 | name = "thiserror-impl" 227 | version = "1.0.30" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 230 | dependencies = [ 231 | "proc-macro2", 232 | "quote", 233 | "syn", 234 | ] 235 | 236 | [[package]] 237 | name = "tokio" 238 | version = "1.15.0" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" 241 | dependencies = [ 242 | "bytes", 243 | "libc", 244 | "memchr", 245 | "mio", 246 | "num_cpus", 247 | "once_cell", 248 | "parking_lot", 249 | "pin-project-lite", 250 | "signal-hook-registry", 251 | "tokio-macros", 252 | "winapi", 253 | ] 254 | 255 | [[package]] 256 | name = "tokio-macros" 257 | version = "1.7.0" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" 260 | dependencies = [ 261 | "proc-macro2", 262 | "quote", 263 | "syn", 264 | ] 265 | 266 | [[package]] 267 | name = "unicode-xid" 268 | version = "0.2.2" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 271 | 272 | [[package]] 273 | name = "winapi" 274 | version = "0.3.9" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 277 | dependencies = [ 278 | "winapi-i686-pc-windows-gnu", 279 | "winapi-x86_64-pc-windows-gnu", 280 | ] 281 | 282 | [[package]] 283 | name = "winapi-i686-pc-windows-gnu" 284 | version = "0.4.0" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 287 | 288 | [[package]] 289 | name = "winapi-x86_64-pc-windows-gnu" 290 | version = "0.4.0" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 293 | -------------------------------------------------------------------------------- /src/crates/day-22/serde/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-22-serde" 3 | version = "0.0.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 | serde = { version = "1.0", features = ["derive"] } 10 | serde_json = "1.0" 11 | rmp-serde = "0.15" 12 | -------------------------------------------------------------------------------- /src/crates/day-22/serde/src/main.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Serialize, Deserialize, Debug)] 4 | struct Author { 5 | first: String, 6 | last: String, 7 | } 8 | 9 | fn main() { 10 | let mark_twain = Author { 11 | first: "Samuel".to_owned(), 12 | last: "Clemens".to_owned(), 13 | }; 14 | 15 | let serialized_json = serde_json::to_string(&mark_twain).unwrap(); 16 | println!("Serialized as JSON: {}", serialized_json); 17 | let serialized_mp = rmp_serde::to_vec(&mark_twain).unwrap(); 18 | println!("Serialized as MessagePack: {:?}", serialized_mp); 19 | 20 | let deserialized_json: Author = serde_json::from_str(&serialized_json).unwrap(); 21 | println!("Deserialized from JSON: {:?}", deserialized_json); 22 | let deserialized_mp: Author = rmp_serde::from_read_ref(&serialized_mp).unwrap(); 23 | println!("Deserialized from MessagePack: {:?}", deserialized_mp); 24 | } 25 | -------------------------------------------------------------------------------- /src/crates/day-22/wapc-guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wapc-guest" 3 | version = "0.0.1" 4 | description = "Sample guest" 5 | authors = [""] 6 | edition = "2018" 7 | license = "Apache-2.0" 8 | 9 | [lib] 10 | crate-type = ["cdylib", "rlib"] 11 | 12 | [features] 13 | default = ["guest"] 14 | guest = [] 15 | 16 | [dependencies] 17 | wapc-guest = "0.4.0" 18 | serde = { version = "1.0.115", features = ["derive"] } 19 | serde_json = "1.0.57" 20 | serde_derive = "1.0.115" 21 | serde_bytes = "0.11.5" 22 | rmp-serde = "0.14.4" 23 | lazy_static = "1.4.0" 24 | handlebars = "4" 25 | 26 | [dev-dependencies] 27 | structopt = "0.3.17" 28 | serde_json = "1.0.57" 29 | base64 = "0.12.3" 30 | 31 | [profile.release] 32 | # Optimize for small code size 33 | opt-level = "s" 34 | lto = true 35 | -------------------------------------------------------------------------------- /src/crates/day-22/wapc-guest/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all deps codegen build clean doc test 2 | 3 | all: deps codegen build 4 | 5 | deps: 6 | 7 | codegen: 8 | wapc generate codegen.yaml 9 | 10 | build: 11 | cargo build --target wasm32-unknown-unknown --release 12 | mkdir -p build && cp target/wasm32-unknown-unknown/release/*.wasm build/ 13 | 14 | # Rust builds accrue disk space over time (specifically the target directory), 15 | # so running `make clean` should be done periodically. 16 | clean: 17 | cargo clean 18 | rm -Rf build 19 | 20 | doc: 21 | 22 | test: build 23 | cargo test 24 | -------------------------------------------------------------------------------- /src/crates/day-22/wapc-guest/build/wapc_guest.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsoverson/node-to-rust/ec7ef43fa7271ac99229f076765fd86756780814/src/crates/day-22/wapc-guest/build/wapc_guest.wasm -------------------------------------------------------------------------------- /src/crates/day-22/wapc-guest/codegen.yaml: -------------------------------------------------------------------------------- 1 | schema: schema.widl 2 | generates: 3 | src/generated.rs: 4 | module: '@wapc/widl-codegen/rust' 5 | visitorClass: ModuleVisitor 6 | src/lib.rs: 7 | ifNotExists: true 8 | module: '@wapc/widl-codegen/rust' 9 | visitorClass: ScaffoldVisitor 10 | config: 11 | use: generated -------------------------------------------------------------------------------- /src/crates/day-22/wapc-guest/schema.widl: -------------------------------------------------------------------------------- 1 | 2 | interface { 3 | render(blog:Blog, template: string): string 4 | } 5 | 6 | type Blog { 7 | title: string, 8 | body: string, 9 | author: string 10 | } 11 | -------------------------------------------------------------------------------- /src/crates/day-22/wapc-guest/src/generated.rs: -------------------------------------------------------------------------------- 1 | extern crate rmp_serde as rmps; 2 | use rmps::{Deserializer, Serializer}; 3 | use serde::{Deserialize, Serialize}; 4 | use std::io::Cursor; 5 | 6 | #[cfg(feature = "guest")] 7 | extern crate wapc_guest as guest; 8 | #[cfg(feature = "guest")] 9 | use guest::prelude::*; 10 | 11 | #[cfg(feature = "guest")] 12 | pub struct Host { 13 | binding: String, 14 | } 15 | 16 | #[cfg(feature = "guest")] 17 | impl Default for Host { 18 | fn default() -> Self { 19 | Host { 20 | binding: "default".to_string(), 21 | } 22 | } 23 | } 24 | 25 | /// Creates a named host binding 26 | #[cfg(feature = "guest")] 27 | pub fn host(binding: &str) -> Host { 28 | Host { 29 | binding: binding.to_string(), 30 | } 31 | } 32 | 33 | /// Creates the default host binding 34 | #[cfg(feature = "guest")] 35 | pub fn default() -> Host { 36 | Host::default() 37 | } 38 | 39 | #[cfg(feature = "guest")] 40 | impl Host { 41 | pub fn render(&self, blog: Blog, template: String) -> HandlerResult { 42 | let input_args = RenderArgs { blog, template }; 43 | host_call(&self.binding, "", "render", &serialize(input_args)?) 44 | .map(|vec| { 45 | let resp = deserialize::(vec.as_ref()).unwrap(); 46 | resp 47 | }) 48 | .map_err(|e| e.into()) 49 | } 50 | } 51 | 52 | #[cfg(feature = "guest")] 53 | pub struct Handlers {} 54 | 55 | #[cfg(feature = "guest")] 56 | impl Handlers { 57 | pub fn register_render(f: fn(Blog, String) -> HandlerResult) { 58 | *RENDER.write().unwrap() = Some(f); 59 | register_function(&"render", render_wrapper); 60 | } 61 | } 62 | 63 | #[cfg(feature = "guest")] 64 | lazy_static::lazy_static! { 65 | static ref RENDER: std::sync::RwLock HandlerResult>> = std::sync::RwLock::new(None); 66 | } 67 | 68 | #[cfg(feature = "guest")] 69 | fn render_wrapper(input_payload: &[u8]) -> CallResult { 70 | let input = deserialize::(input_payload)?; 71 | let lock = RENDER.read().unwrap().unwrap(); 72 | let result = lock(input.blog, input.template)?; 73 | serialize(result) 74 | } 75 | 76 | #[derive(Debug, PartialEq, Deserialize, Serialize, Default, Clone)] 77 | pub struct RenderArgs { 78 | #[serde(rename = "blog")] 79 | pub blog: Blog, 80 | #[serde(rename = "template")] 81 | pub template: String, 82 | } 83 | 84 | #[derive(Debug, PartialEq, Deserialize, Serialize, Default, Clone)] 85 | pub struct Blog { 86 | #[serde(rename = "title")] 87 | pub title: String, 88 | #[serde(rename = "body")] 89 | pub body: String, 90 | #[serde(rename = "author")] 91 | pub author: String, 92 | } 93 | 94 | /// The standard function for serializing codec structs into a format that can be 95 | /// used for message exchange between actor and host. Use of any other function to 96 | /// serialize could result in breaking incompatibilities. 97 | pub fn serialize( 98 | item: T, 99 | ) -> ::std::result::Result, Box> 100 | where 101 | T: Serialize, 102 | { 103 | let mut buf = Vec::new(); 104 | item.serialize(&mut Serializer::new(&mut buf).with_struct_map())?; 105 | Ok(buf) 106 | } 107 | 108 | /// The standard function for de-serializing codec structs from a format suitable 109 | /// for message exchange between actor and host. Use of any other function to 110 | /// deserialize could result in breaking incompatibilities. 111 | pub fn deserialize<'de, T: Deserialize<'de>>( 112 | buf: &[u8], 113 | ) -> ::std::result::Result> { 114 | let mut de = Deserializer::new(Cursor::new(buf)); 115 | match Deserialize::deserialize(&mut de) { 116 | Ok(t) => Ok(t), 117 | Err(e) => Err(format!("Failed to de-serialize: {}", e).into()), 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/crates/day-22/wapc-guest/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod generated; 2 | pub use generated::*; 3 | use handlebars::Handlebars; 4 | use wapc_guest::prelude::*; 5 | 6 | #[no_mangle] 7 | pub fn wapc_init() { 8 | Handlers::register_render(render); 9 | } 10 | 11 | fn render(blog: Blog, template: String) -> HandlerResult { 12 | let mut handlebars = Handlebars::new(); 13 | handlebars.register_template_string("blog", template)?; 14 | 15 | Ok(handlebars.render("blog", &blog)?) 16 | } 17 | -------------------------------------------------------------------------------- /src/crates/day-23/rc-arc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-23-rc-arc" 3 | version = "0.0.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 | parking_lot = "0.11" 10 | tokio = { version = "1", features = ["full"] } 11 | 12 | [[bin]] 13 | path = "./src/references.rs" 14 | name = "references" 15 | 16 | [[bin]] 17 | path = "./src/rc.rs" 18 | name = "rc" 19 | 20 | [[bin]] 21 | path = "./src/arc.rs" 22 | name = "arc" 23 | 24 | [[bin]] 25 | path = "./src/rwlock.rs" 26 | name = "rwlock" 27 | 28 | [[bin]] 29 | path = "./src/async.rs" 30 | name = "async" 31 | -------------------------------------------------------------------------------- /src/crates/day-23/rc-arc/src/arc.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | fn main() { 4 | let booty = Arc::new(Treasure { dubloons: 1000 }); 5 | 6 | let my_map = TreasureMap::new(booty); 7 | 8 | let your_map = my_map.clone(); 9 | let sender = std::thread::spawn(move || { 10 | println!("Map in thread {:?}", your_map); 11 | }); 12 | println!("{:?}", my_map); 13 | 14 | sender.join(); 15 | } 16 | 17 | #[derive(Debug)] 18 | struct Treasure { 19 | dubloons: u32, 20 | } 21 | 22 | #[derive(Clone, Debug)] 23 | struct TreasureMap { 24 | treasure: Arc, 25 | } 26 | 27 | impl TreasureMap { 28 | fn new(treasure: Arc) -> Self { 29 | TreasureMap { treasure } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/crates/day-23/rc-arc/src/async.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use parking_lot::RwLock; 4 | 5 | #[tokio::main] 6 | async fn main() { 7 | let treasure = RwLock::new(Treasure { dubloons: 100 }); 8 | tokio::task::spawn(empty_treasure_and_party(&treasure)).await; 9 | } 10 | 11 | async fn empty_treasure_and_party(treasure: &RwLock) { 12 | let mut lock = treasure.write(); 13 | lock.dubloons = 0; 14 | 15 | // Await an async function 16 | pirate_party().await; 17 | } // lock goes out of scope here 18 | 19 | async fn pirate_party() {} 20 | 21 | #[derive(Debug)] 22 | struct Treasure { 23 | dubloons: u32, 24 | } 25 | 26 | #[derive(Clone, Debug)] 27 | struct TreasureMap { 28 | treasure: Arc>, 29 | } 30 | 31 | impl TreasureMap { 32 | fn new(treasure: Arc>) -> Self { 33 | TreasureMap { treasure } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/crates/day-23/rc-arc/src/rc.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | fn main() { 4 | let booty = Rc::new(Treasure { dubloons: 1000 }); 5 | 6 | let my_map = TreasureMap::new(booty); 7 | let your_map = my_map.clone(); 8 | println!("{:?}", my_map); 9 | println!("{:?}", your_map); 10 | } 11 | 12 | #[derive(Debug)] 13 | struct Treasure { 14 | dubloons: u32, 15 | } 16 | 17 | #[derive(Clone, Debug)] 18 | struct TreasureMap { 19 | treasure: Rc, 20 | } 21 | 22 | impl TreasureMap { 23 | fn new(treasure: Rc) -> Self { 24 | TreasureMap { treasure } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/crates/day-23/rc-arc/src/references.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let booty = Treasure { dubloons: 1000 }; 3 | 4 | let my_map = TreasureMap::new(&booty); 5 | let your_map = my_map.clone(); 6 | println!("{:?}", my_map); 7 | println!("{:?}", your_map); 8 | } 9 | 10 | #[derive(Debug)] 11 | struct Treasure { 12 | dubloons: u32, 13 | } 14 | 15 | #[derive(Clone, Debug)] 16 | struct TreasureMap<'a> { 17 | treasure: &'a Treasure, 18 | } 19 | 20 | impl<'a> TreasureMap<'a> { 21 | fn new(treasure: &'a Treasure) -> Self { 22 | TreasureMap { treasure } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/crates/day-23/rc-arc/src/rwlock.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use parking_lot::RwLock; 4 | 5 | fn main() { 6 | let booty = Arc::new(RwLock::new(Treasure { dubloons: 1000 })); 7 | 8 | let my_map = TreasureMap::new(booty); 9 | 10 | println!("My TreasureMap before: {:?}", my_map); 11 | 12 | let your_map = my_map.clone(); 13 | let sender = std::thread::spawn(move || { 14 | { 15 | let mut treasure = your_map.treasure.write(); 16 | treasure.dubloons = 0; 17 | } 18 | println!("Treasure emptied!"); 19 | println!("Your TreasureMap after {:?}", your_map); 20 | }); 21 | sender.join(); 22 | 23 | println!("My TreasureMap after: {:?}", my_map); 24 | } 25 | 26 | #[derive(Debug)] 27 | struct Treasure { 28 | dubloons: u32, 29 | } 30 | 31 | #[derive(Clone, Debug)] 32 | struct TreasureMap { 33 | treasure: Arc>, 34 | } 35 | 36 | impl TreasureMap { 37 | fn new(treasure: Arc>) -> Self { 38 | TreasureMap { treasure } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/crates/day-4/hello-world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-4-hello-world" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-4/hello-world/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /src/crates/day-4/strings-wtf-1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-4-strings-wtf-1" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-4/strings-wtf-1/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let greeting = "Hello, world!"; 3 | println!(greeting); 4 | } 5 | -------------------------------------------------------------------------------- /src/crates/day-4/strings-wtf-2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-4-strings-wtf-2" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-4/strings-wtf-2/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | greet("World"); 3 | } 4 | 5 | fn greet(target: String) { 6 | println!("Hello, {}", target); 7 | } -------------------------------------------------------------------------------- /src/crates/day-5/borrowing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-5-borrowing" 3 | version = "0.0.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 | [[bin]] 11 | name = "borrow" 12 | path = "./src/borrow.rs" 13 | 14 | [[bin]] 15 | name = "mutable-borrow" 16 | path = "./src/mutable-borrow.rs" 17 | -------------------------------------------------------------------------------- /src/crates/day-5/borrowing/README.md: -------------------------------------------------------------------------------- 1 | # Test README 2 | -------------------------------------------------------------------------------- /src/crates/day-5/borrowing/src/borrow.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, fs::read_to_string}; 2 | 3 | fn main() { 4 | let source = read_to_string("./README.md").unwrap(); 5 | let mut files = HashMap::new(); 6 | files.insert("README", source.clone()); 7 | files.insert("README2", source); 8 | 9 | let files_ref = &files; 10 | let files_ref2 = &files; 11 | 12 | print_borrowed_map(files_ref); 13 | print_borrowed_map(files_ref2); 14 | } 15 | 16 | fn print_borrowed_map(map: &HashMap<&str, String>) { 17 | println!("{:?}", map) 18 | } 19 | -------------------------------------------------------------------------------- /src/crates/day-5/borrowing/src/mutable-borrow.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, fs::read_to_string}; 2 | 3 | fn main() { 4 | let source = read_to_string("./README.md").unwrap(); 5 | let mut files = HashMap::new(); 6 | files.insert("README", source.clone()); 7 | files.insert("README2", source); 8 | 9 | let files_ref = &mut files; 10 | let files_ref2 = &mut files; 11 | 12 | needs_mutable_ref(files_ref); 13 | needs_mutable_ref(files_ref2); 14 | } 15 | 16 | fn needs_mutable_ref(map: &mut HashMap<&str, String>) {} 17 | -------------------------------------------------------------------------------- /src/crates/day-5/let-vs-const/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /src/crates/day-5/let-vs-const/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-5-let-vs-const" 3 | version = "0.0.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 | 11 | [[bin]] 12 | name = "reassigning" 13 | path = "./src/reassigning.rs" 14 | 15 | [[bin]] 16 | name = "reassigning-wrong-type" 17 | path = "./src/reassigning-wrong-type.rs" 18 | 19 | [[bin]] 20 | name = "reassigning-rebind" 21 | path = "./src/reassigning-rebind.rs" 22 | -------------------------------------------------------------------------------- /src/crates/day-5/let-vs-const/src/reassigning-rebind.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let myvar = 1; 3 | println!("{}", myvar); 4 | let myvar = "3"; 5 | println!("{}", myvar); 6 | } 7 | -------------------------------------------------------------------------------- /src/crates/day-5/let-vs-const/src/reassigning-wrong-type.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut mutable = 1; 3 | println!("{}", mutable); 4 | mutable = "3"; 5 | println!("{}", mutable); 6 | } 7 | -------------------------------------------------------------------------------- /src/crates/day-5/let-vs-const/src/reassigning.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut mutable = 1; 3 | println!("{}", mutable); 4 | mutable = 3; 5 | println!("{}", mutable); 6 | } 7 | -------------------------------------------------------------------------------- /src/crates/day-6/loads-of-strs/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /src/crates/day-6/loads-of-strs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-6-loads-of-strs" 3 | version = "0.0.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 | [[bin]] 10 | name = "one-print" 11 | test = false 12 | bench = false 13 | path = "src/one-print.rs" 14 | 15 | [[bin]] 16 | name = "200-empty-prints" 17 | test = false 18 | bench = false 19 | path = "src/200-empty-prints.rs" 20 | 21 | [[bin]] 22 | name = "200-prints" 23 | test = false 24 | bench = false 25 | path = "src/200-prints.rs" 26 | 27 | [[bin]] 28 | name = "200-unique-prints" 29 | test = false 30 | bench = false 31 | path = "src/200-unique-prints.rs" 32 | -------------------------------------------------------------------------------- /src/crates/day-6/loads-of-strs/src/200-empty-prints.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | print(""); 3 | print(""); 4 | print(""); 5 | print(""); 6 | print(""); 7 | print(""); 8 | print(""); 9 | print(""); 10 | print(""); 11 | print(""); 12 | print(""); 13 | print(""); 14 | print(""); 15 | print(""); 16 | print(""); 17 | print(""); 18 | print(""); 19 | print(""); 20 | print(""); 21 | print(""); 22 | print(""); 23 | print(""); 24 | print(""); 25 | print(""); 26 | print(""); 27 | print(""); 28 | print(""); 29 | print(""); 30 | print(""); 31 | print(""); 32 | print(""); 33 | print(""); 34 | print(""); 35 | print(""); 36 | print(""); 37 | print(""); 38 | print(""); 39 | print(""); 40 | print(""); 41 | print(""); 42 | print(""); 43 | print(""); 44 | print(""); 45 | print(""); 46 | print(""); 47 | print(""); 48 | print(""); 49 | print(""); 50 | print(""); 51 | print(""); 52 | print(""); 53 | print(""); 54 | print(""); 55 | print(""); 56 | print(""); 57 | print(""); 58 | print(""); 59 | print(""); 60 | print(""); 61 | print(""); 62 | print(""); 63 | print(""); 64 | print(""); 65 | print(""); 66 | print(""); 67 | print(""); 68 | print(""); 69 | print(""); 70 | print(""); 71 | print(""); 72 | print(""); 73 | print(""); 74 | print(""); 75 | print(""); 76 | print(""); 77 | print(""); 78 | print(""); 79 | print(""); 80 | print(""); 81 | print(""); 82 | print(""); 83 | print(""); 84 | print(""); 85 | print(""); 86 | print(""); 87 | print(""); 88 | print(""); 89 | print(""); 90 | print(""); 91 | print(""); 92 | print(""); 93 | print(""); 94 | print(""); 95 | print(""); 96 | print(""); 97 | print(""); 98 | print(""); 99 | print(""); 100 | print(""); 101 | print(""); 102 | print(""); 103 | print(""); 104 | print(""); 105 | print(""); 106 | print(""); 107 | print(""); 108 | print(""); 109 | print(""); 110 | print(""); 111 | print(""); 112 | print(""); 113 | print(""); 114 | print(""); 115 | print(""); 116 | print(""); 117 | print(""); 118 | print(""); 119 | print(""); 120 | print(""); 121 | print(""); 122 | print(""); 123 | print(""); 124 | print(""); 125 | print(""); 126 | print(""); 127 | print(""); 128 | print(""); 129 | print(""); 130 | print(""); 131 | print(""); 132 | print(""); 133 | print(""); 134 | print(""); 135 | print(""); 136 | print(""); 137 | print(""); 138 | print(""); 139 | print(""); 140 | print(""); 141 | print(""); 142 | print(""); 143 | print(""); 144 | print(""); 145 | print(""); 146 | print(""); 147 | print(""); 148 | print(""); 149 | print(""); 150 | print(""); 151 | print(""); 152 | print(""); 153 | print(""); 154 | print(""); 155 | print(""); 156 | print(""); 157 | print(""); 158 | print(""); 159 | print(""); 160 | print(""); 161 | print(""); 162 | print(""); 163 | print(""); 164 | print(""); 165 | print(""); 166 | print(""); 167 | print(""); 168 | print(""); 169 | print(""); 170 | print(""); 171 | print(""); 172 | print(""); 173 | print(""); 174 | print(""); 175 | print(""); 176 | print(""); 177 | print(""); 178 | print(""); 179 | print(""); 180 | print(""); 181 | print(""); 182 | print(""); 183 | print(""); 184 | print(""); 185 | print(""); 186 | print(""); 187 | print(""); 188 | print(""); 189 | print(""); 190 | print(""); 191 | print(""); 192 | print(""); 193 | print(""); 194 | print(""); 195 | print(""); 196 | print(""); 197 | print(""); 198 | print(""); 199 | print(""); 200 | print(""); 201 | print(""); 202 | } 203 | 204 | fn print(msg: &str) { 205 | println!("{}", msg); 206 | } 207 | -------------------------------------------------------------------------------- /src/crates/day-6/loads-of-strs/src/one-print.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | print("TESTING:12345678901234567890123456789012345678901234567890"); 3 | } 4 | 5 | fn print(msg: &str) { 6 | println!("{}", msg); 7 | } 8 | -------------------------------------------------------------------------------- /src/crates/day-7/syntax/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /src/crates/day-7/syntax/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-7-syntax" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-7/syntax/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | apples(); 3 | vec(); 4 | } 5 | 6 | fn add_numbers(left: i64, right: i64) -> i64 { 7 | left + right 8 | } 9 | 10 | fn apples() { 11 | let apples = 6; 12 | let message = if apples > 10 { 13 | "Lots of apples" 14 | } else if apples > 4 { 15 | "A few apples" 16 | } else { 17 | "Not many apples at all" 18 | }; 19 | 20 | println!("{}", message) 21 | } 22 | 23 | fn vec() { 24 | let mut numbers = vec![1, 2, 3, 4, 5]; 25 | numbers.push(7); 26 | println!("{:?}", numbers); 27 | } 28 | -------------------------------------------------------------------------------- /src/crates/day-8/maps/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /src/crates/day-8/maps/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-8-maps" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-8/maps/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | fn main() { 4 | let mut map = HashMap::new(); 5 | 6 | map.insert("key1", "value1"); 7 | map.insert("key2", "value2"); 8 | 9 | println!("{}", map.get("key1").unwrap_or(&"")); 10 | println!("{}", map.get("key2").unwrap_or(&"")); 11 | } 12 | -------------------------------------------------------------------------------- /src/crates/day-8/structs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-8-structs" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-8/structs/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut light = TrafficLight::new(); 3 | println!("{}", light); 4 | println!("{:?}", light); 5 | } 6 | 7 | impl std::fmt::Display for TrafficLight { 8 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 9 | write!(f, "Traffic light is {}", self.color) 10 | } 11 | } 12 | 13 | #[derive(Debug)] 14 | struct TrafficLight { 15 | color: String, 16 | } 17 | 18 | impl TrafficLight { 19 | pub fn new() -> Self { 20 | Self { 21 | color: "red".to_owned(), 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/crates/day-9/structs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "day-9-structs" 3 | version = "0.0.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 | -------------------------------------------------------------------------------- /src/crates/day-9/structs/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | fn main() { 4 | let mut light = TrafficLight::new(); 5 | println!("{}", light); 6 | println!("{:?}", light); 7 | light.turn_green(); 8 | println!("{:?}", light); 9 | } 10 | 11 | impl std::fmt::Display for TrafficLight { 12 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 13 | write!(f, "Traffic light is {}", self.color) 14 | } 15 | } 16 | 17 | #[derive(Debug)] 18 | struct TrafficLight { 19 | color: TrafficLightColor, 20 | } 21 | 22 | impl TrafficLight { 23 | pub fn new() -> Self { 24 | Self { 25 | color: TrafficLightColor::Red, 26 | } 27 | } 28 | 29 | pub fn get_state(&self) -> &TrafficLightColor { 30 | &self.color 31 | } 32 | 33 | pub fn turn_green(&mut self) { 34 | self.color = TrafficLightColor::Green 35 | } 36 | } 37 | 38 | #[derive(Debug)] 39 | enum TrafficLightColor { 40 | Red, 41 | Yellow, 42 | Green, 43 | } 44 | 45 | impl Display for TrafficLightColor { 46 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 47 | let color_string = match self { 48 | TrafficLightColor::Green => "green", 49 | TrafficLightColor::Red => "red", 50 | TrafficLightColor::Yellow => "yellow", 51 | }; 52 | write!(f, "{}", color_string) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/javascript/day-10/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "day-8", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "devDependencies": { 8 | "@types/node": "^16.11.12" 9 | } 10 | }, 11 | "node_modules/@types/node": { 12 | "version": "16.11.12", 13 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", 14 | "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", 15 | "dev": true 16 | } 17 | }, 18 | "dependencies": { 19 | "@types/node": { 20 | "version": "16.11.12", 21 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", 22 | "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", 23 | "dev": true 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/javascript/day-10/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": {} 3 | } 4 | -------------------------------------------------------------------------------- /src/javascript/day-10/src/mixins.js: -------------------------------------------------------------------------------- 1 | const utilityMixin = { 2 | prettyPrint() { 3 | console.log(JSON.stringify(this, null, 2)); 4 | }, 5 | }; 6 | 7 | class Person { 8 | constructor(first, last) { 9 | this.firstName = first; 10 | this.lastName = last; 11 | } 12 | } 13 | 14 | function mixin(base, mixer) { 15 | Object.assign(base.prototype, mixer); 16 | } 17 | 18 | mixin(Person, utilityMixin); 19 | 20 | const author = new Person("Jarrod", "Overson"); 21 | author.prettyPrint(); 22 | -------------------------------------------------------------------------------- /src/javascript/day-15/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "day-8", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "devDependencies": { 8 | "@types/node": "^16.11.12" 9 | } 10 | }, 11 | "node_modules/@types/node": { 12 | "version": "16.11.12", 13 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", 14 | "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", 15 | "dev": true 16 | } 17 | }, 18 | "dependencies": { 19 | "@types/node": { 20 | "version": "16.11.12", 21 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", 22 | "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", 23 | "dev": true 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/javascript/day-15/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "@types/node": "^16.11.12" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/javascript/day-15/src/closures.ts: -------------------------------------------------------------------------------- 1 | function main() { 2 | let closure = () => { 3 | console.log("Hi! I'm in a closure"); 4 | }; 5 | closure(); 6 | 7 | let double = (num: number) => num + num; 8 | let num = 4; 9 | console.log(`${num} + ${num} = ${double(num)}`); 10 | 11 | let name = "Rebecca"; 12 | closure = () => { 13 | console.log(`Hi, ${name}.`); 14 | }; 15 | closure(); 16 | 17 | let counter = 0; 18 | closure = () => { 19 | counter += 1; 20 | console.log(`This closure has a counter. I've been run ${counter} times.`); 21 | }; 22 | closure(); 23 | closure(); 24 | closure(); 25 | console.log(`The closure was called a total of ${counter} times`); 26 | 27 | let adder = (left: number, right: number) => { 28 | console.log(`${left} + ${right} is ${left + right}`); 29 | left + right; 30 | }; 31 | adder(4, 5); 32 | 33 | let plusTwo = makeAdder(2); 34 | plusTwo(23); 35 | 36 | let timesTwo = (i: number) => i * 2; 37 | let doublePlusTwo = compose(plusTwo, timesTwo); 38 | console.log(`${10} * 2 + 2 = ${doublePlusTwo(10)}`); 39 | 40 | let fnRef = regularFunction; 41 | fnRef(); 42 | 43 | let square = new DynamicBehavior((num: number) => num * num); 44 | console.log(`${5} squared is ${square.run(5)}`); 45 | } 46 | 47 | function regularFunction() { 48 | console.log("I'm a regular function"); 49 | } 50 | 51 | function makeAdder(left: number): (left: number) => number { 52 | return (right: number) => { 53 | console.log(`${left} + ${right} is ${left + right}`); 54 | return left + right; 55 | }; 56 | } 57 | 58 | function compose(f: (left: T) => T, g: (left: T) => T): (left: T) => T { 59 | return (right: T) => f(g(right)); 60 | } 61 | 62 | class DynamicBehavior { 63 | closure: (num: T) => T; 64 | constructor(closure: (num: T) => T) { 65 | this.closure = closure; 66 | } 67 | run(arg: T): T { 68 | return this.closure(arg); 69 | } 70 | } 71 | 72 | main(); 73 | -------------------------------------------------------------------------------- /src/javascript/day-15/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src/**/*", "test/**/*"], 3 | "exclude": ["node_modules"], 4 | "compilerOptions": { 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, 8 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, 9 | "lib": [ 10 | "es2020" 11 | ] /* Specify library files to be included in the compilation. */, 12 | "resolveJsonModule": true, 13 | // "allowJs": true, /* Allow javascript files to be compiled. */ 14 | // "checkJs": true, /* Report errors in .js files. */ 15 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 16 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 17 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 18 | "sourceMap": true /* Generates corresponding '.map' file. */, 19 | // "outFile": "./", /* Concatenate and emit output to single file. */ 20 | "outDir": "./dist" /* Redirect output structure to the directory. */, 21 | "rootDir": "./" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, 22 | // "composite": true, /* Enable project compilation */ 23 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 24 | // "removeComments": true, /* Do not emit comments to output. */ 25 | // "noEmit": true, /* Do not emit outputs. */ 26 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 27 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 28 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 29 | /* Strict Type-Checking Options */ 30 | "strict": true /* Enable all strict type-checking options. */, 31 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 32 | // "strictNullChecks": true, /* Enable strict null checks. */ 33 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 34 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 35 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 36 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 37 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 38 | /* Additional Checks */ 39 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 40 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 41 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 42 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 43 | /* Module Resolution Options */ 44 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 45 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 46 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 47 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 48 | // "typeRoots": [], /* List of folders to include type definitions from. */ 49 | "typeRoots": ["./types", "./node_modules/@types"], 50 | // "types": [], /* Type declaration files to be included in compilation. */ 51 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 52 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 53 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 54 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 55 | /* Source Map Options */ 56 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 59 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 60 | /* Experimental Options */ 61 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 62 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 63 | /* Advanced Options */ 64 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/javascript/day-17/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "day-8", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "devDependencies": { 8 | "@types/node": "^16.11.12" 9 | } 10 | }, 11 | "node_modules/@types/node": { 12 | "version": "16.11.12", 13 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", 14 | "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", 15 | "dev": true 16 | } 17 | }, 18 | "dependencies": { 19 | "@types/node": { 20 | "version": "16.11.12", 21 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", 22 | "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", 23 | "dev": true 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/javascript/day-17/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "@types/node": "^16.11.12" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/javascript/day-17/src/arrays.ts: -------------------------------------------------------------------------------- 1 | function main() { 2 | for_common(); 3 | for_in(); 4 | for_of(); 5 | while_not_done(); 6 | while_true(); 7 | labels(); 8 | } 9 | 10 | function for_common() { 11 | let max = 4; 12 | for (let i = 0; i < max; i++) { 13 | console.log(i); 14 | } 15 | } 16 | 17 | function for_in() { 18 | let obj: any = { 19 | key1: "value1", 20 | key2: "value2", 21 | }; 22 | for (let prop in obj) { 23 | console.log(`${prop}: ${obj[prop]}`); 24 | } 25 | } 26 | 27 | function for_of() { 28 | let numbers = [1, 2, 3, 4, 5]; 29 | for (let number of numbers) { 30 | console.log(number); 31 | } 32 | } 33 | 34 | function while_not_done() { 35 | let obj = { 36 | data: ["a", "b", "c"], 37 | doWork() { 38 | return this.data.pop(); 39 | }, 40 | }; 41 | let data; 42 | while ((data = obj.doWork())) { 43 | console.log(data); 44 | } 45 | } 46 | 47 | function while_true() { 48 | let n = 0; 49 | 50 | while (true) { 51 | n++; 52 | if (n > 3) break; 53 | } 54 | console.log(`Finished. n=${n}`); 55 | } 56 | 57 | function labels() { 58 | console.log("Start"); 59 | outer: while (true) { 60 | while (true) { 61 | break outer; 62 | } 63 | } 64 | console.log("Finished"); 65 | } 66 | 67 | main(); 68 | -------------------------------------------------------------------------------- /src/javascript/day-17/src/iterators.ts: -------------------------------------------------------------------------------- 1 | function main() { 2 | filter(); 3 | find(); 4 | forEach(); 5 | join(); 6 | map(); 7 | push_pop(); 8 | shift_unshift(); 9 | } 10 | 11 | function filter() { 12 | let numbers = [1, 2, 3, 4, 5]; 13 | let even = numbers.filter((x) => x % 2 === 0); 14 | console.log(even); 15 | } 16 | 17 | function find() { 18 | let numbers = [1, 2, 3, 4, 5]; 19 | let firstEven = numbers.find((x) => x % 2 === 0); 20 | console.log(firstEven); 21 | } 22 | 23 | function forEach() { 24 | let numbers = [1, 2, 3]; 25 | numbers.forEach((x) => console.log(x)); 26 | } 27 | 28 | function join() { 29 | let names = ["Sam", "Janet", "Hunter"]; 30 | let csv = names.join(","); 31 | console.log(csv); 32 | } 33 | 34 | function map() { 35 | let list = [1, 2, 3]; 36 | let doubled = list.map((x) => x * 2); 37 | console.log(doubled); 38 | } 39 | 40 | function push_pop() { 41 | let list = [1, 2]; 42 | list.push(3); 43 | console.log(list.pop()); 44 | console.log(list.pop()); 45 | console.log(list.pop()); 46 | console.log(list.pop()); 47 | } 48 | 49 | function shift_unshift() { 50 | let list = [1, 2]; 51 | list.unshift(0); 52 | console.log(list.shift()); 53 | console.log(list.shift()); 54 | console.log(list.shift()); 55 | console.log(list.shift()); 56 | } 57 | 58 | main(); 59 | -------------------------------------------------------------------------------- /src/javascript/day-17/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src/**/*", "test/**/*"], 3 | "exclude": ["node_modules"], 4 | "compilerOptions": { 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, 8 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, 9 | "lib": [ 10 | "es2020" 11 | ] /* Specify library files to be included in the compilation. */, 12 | "resolveJsonModule": true, 13 | // "allowJs": true, /* Allow javascript files to be compiled. */ 14 | // "checkJs": true, /* Report errors in .js files. */ 15 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 16 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 17 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 18 | "sourceMap": true /* Generates corresponding '.map' file. */, 19 | // "outFile": "./", /* Concatenate and emit output to single file. */ 20 | "outDir": "./dist" /* Redirect output structure to the directory. */, 21 | "rootDir": "./" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, 22 | // "composite": true, /* Enable project compilation */ 23 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 24 | // "removeComments": true, /* Do not emit comments to output. */ 25 | // "noEmit": true, /* Do not emit outputs. */ 26 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 27 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 28 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 29 | /* Strict Type-Checking Options */ 30 | "strict": true /* Enable all strict type-checking options. */, 31 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 32 | // "strictNullChecks": true, /* Enable strict null checks. */ 33 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 34 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 35 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 36 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 37 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 38 | /* Additional Checks */ 39 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 40 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 41 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 42 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 43 | /* Module Resolution Options */ 44 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 45 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 46 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 47 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 48 | // "typeRoots": [], /* List of folders to include type definitions from. */ 49 | "typeRoots": ["./types", "./node_modules/@types"], 50 | // "types": [], /* Type declaration files to be included in compilation. */ 51 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 52 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 53 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 54 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 55 | /* Source Map Options */ 56 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 59 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 60 | /* Experimental Options */ 61 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 62 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 63 | /* Advanced Options */ 64 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/javascript/day-5/let-vs-const/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "references", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC" 11 | } 12 | -------------------------------------------------------------------------------- /src/javascript/day-5/let-vs-const/reassigning.js: -------------------------------------------------------------------------------- 1 | let mutable = 1; 2 | console.log({ mutable }); 3 | mutable = 3; 4 | console.log({ mutable }); 5 | -------------------------------------------------------------------------------- /src/javascript/day-5/references/index.js: -------------------------------------------------------------------------------- 1 | function actOnString(string) { 2 | string += " What a nice day."; 3 | console.log(`String in function: ${string}`); 4 | } 5 | 6 | const stringValue = "Hello!"; 7 | console.log(`String before function: ${stringValue}`); 8 | actOnString(stringValue); 9 | console.log(`String after function: ${stringValue}\n`); 10 | 11 | function actOnNumber(number) { 12 | number++; 13 | console.log(`Number in function: ${number}`); 14 | } 15 | 16 | const numberValue = 2000; 17 | console.log(`Number before function: ${numberValue}`); 18 | actOnNumber(numberValue); 19 | console.log(`Number after function: ${numberValue}\n`); 20 | 21 | function actOnObject(object) { 22 | object.firstName = "Samuel"; 23 | object.lastName = "Clemens"; 24 | console.log(`Object in function: ${objectValue}`); 25 | } 26 | 27 | const objectValue = { 28 | firstName: "Jane", 29 | lastName: "Doe", 30 | }; 31 | objectValue.toString = function () { 32 | return `${this.firstName} ${this.lastName}`; 33 | }; 34 | console.log(`Object before function: ${objectValue}`); 35 | actOnObject(objectValue); 36 | console.log(`Object after function: ${objectValue}`); 37 | -------------------------------------------------------------------------------- /src/javascript/day-5/references/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "references", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC" 11 | } 12 | -------------------------------------------------------------------------------- /src/javascript/day-8/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "day-8", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "devDependencies": { 8 | "@types/node": "^16.11.12" 9 | } 10 | }, 11 | "node_modules/@types/node": { 12 | "version": "16.11.12", 13 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", 14 | "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", 15 | "dev": true 16 | } 17 | }, 18 | "dependencies": { 19 | "@types/node": { 20 | "version": "16.11.12", 21 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", 22 | "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", 23 | "dev": true 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/javascript/day-8/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "@types/node": "^16.11.12" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/javascript/day-8/src/maps.ts: -------------------------------------------------------------------------------- 1 | const map = new Map(); 2 | 3 | map.set("key1", "value1"); 4 | map.set("key2", "value2"); 5 | 6 | console.log(map.get("key1")); 7 | console.log(map.get("key2")); 8 | -------------------------------------------------------------------------------- /src/javascript/day-8/src/structs.ts: -------------------------------------------------------------------------------- 1 | class TrafficLight { 2 | color: string; 3 | 4 | constructor() { 5 | this.color = "red"; 6 | } 7 | } 8 | 9 | const light = new TrafficLight(); 10 | -------------------------------------------------------------------------------- /src/javascript/day-8/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src/**/*", "test/**/*"], 3 | "exclude": ["node_modules"], 4 | "compilerOptions": { 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, 8 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, 9 | "lib": [ 10 | "es2020" 11 | ] /* Specify library files to be included in the compilation. */, 12 | "resolveJsonModule": true, 13 | // "allowJs": true, /* Allow javascript files to be compiled. */ 14 | // "checkJs": true, /* Report errors in .js files. */ 15 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 16 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 17 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 18 | "sourceMap": true /* Generates corresponding '.map' file. */, 19 | // "outFile": "./", /* Concatenate and emit output to single file. */ 20 | "outDir": "./dist" /* Redirect output structure to the directory. */, 21 | "rootDir": "./" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, 22 | // "composite": true, /* Enable project compilation */ 23 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 24 | // "removeComments": true, /* Do not emit comments to output. */ 25 | // "noEmit": true, /* Do not emit outputs. */ 26 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 27 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 28 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 29 | /* Strict Type-Checking Options */ 30 | "strict": true /* Enable all strict type-checking options. */, 31 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 32 | // "strictNullChecks": true, /* Enable strict null checks. */ 33 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 34 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 35 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 36 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 37 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 38 | /* Additional Checks */ 39 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 40 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 41 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 42 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 43 | /* Module Resolution Options */ 44 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 45 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 46 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 47 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 48 | // "typeRoots": [], /* List of folders to include type definitions from. */ 49 | "typeRoots": ["./types", "./node_modules/@types"], 50 | // "types": [], /* Type declaration files to be included in compilation. */ 51 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 52 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 53 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 54 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 55 | /* Source Map Options */ 56 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 59 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 60 | /* Experimental Options */ 61 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 62 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 63 | /* Advanced Options */ 64 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/javascript/day-9/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "day-8", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "devDependencies": { 8 | "@types/node": "^16.11.12" 9 | } 10 | }, 11 | "node_modules/@types/node": { 12 | "version": "16.11.12", 13 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", 14 | "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", 15 | "dev": true 16 | } 17 | }, 18 | "dependencies": { 19 | "@types/node": { 20 | "version": "16.11.12", 21 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", 22 | "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", 23 | "dev": true 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/javascript/day-9/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "@types/node": "^16.11.12" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/javascript/day-9/src/structs.ts: -------------------------------------------------------------------------------- 1 | class TrafficLight { 2 | color: TrafficLightColor; 3 | 4 | constructor() { 5 | this.color = TrafficLightColor.Red; 6 | } 7 | 8 | getState(): TrafficLightColor { 9 | return this.color; 10 | } 11 | 12 | turnGreen() { 13 | this.color = TrafficLightColor.Green; 14 | } 15 | } 16 | 17 | enum TrafficLightColor { 18 | Red = "red", 19 | Yellow = "yellow", 20 | Green = "green", 21 | } 22 | 23 | const light = new TrafficLight(); 24 | console.log(light.getState()); 25 | light.turnGreen(); 26 | console.log(light.getState()); 27 | -------------------------------------------------------------------------------- /src/javascript/day-9/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src/**/*", "test/**/*"], 3 | "exclude": ["node_modules"], 4 | "compilerOptions": { 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, 8 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, 9 | "lib": [ 10 | "es2020" 11 | ] /* Specify library files to be included in the compilation. */, 12 | "resolveJsonModule": true, 13 | // "allowJs": true, /* Allow javascript files to be compiled. */ 14 | // "checkJs": true, /* Report errors in .js files. */ 15 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 16 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 17 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 18 | "sourceMap": true /* Generates corresponding '.map' file. */, 19 | // "outFile": "./", /* Concatenate and emit output to single file. */ 20 | "outDir": "./dist" /* Redirect output structure to the directory. */, 21 | "rootDir": "./" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, 22 | // "composite": true, /* Enable project compilation */ 23 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 24 | // "removeComments": true, /* Do not emit comments to output. */ 25 | // "noEmit": true, /* Do not emit outputs. */ 26 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 27 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 28 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 29 | /* Strict Type-Checking Options */ 30 | "strict": true /* Enable all strict type-checking options. */, 31 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 32 | // "strictNullChecks": true, /* Enable strict null checks. */ 33 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 34 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 35 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 36 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 37 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 38 | /* Additional Checks */ 39 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 40 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 41 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 42 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 43 | /* Module Resolution Options */ 44 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 45 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 46 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 47 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 48 | // "typeRoots": [], /* List of folders to include type definitions from. */ 49 | "typeRoots": ["./types", "./node_modules/@types"], 50 | // "types": [], /* Type declaration files to be included in compilation. */ 51 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 52 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 53 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 54 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 55 | /* Source Map Options */ 56 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 59 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 60 | /* Experimental Options */ 61 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 62 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 63 | /* Advanced Options */ 64 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 65 | } 66 | } 67 | --------------------------------------------------------------------------------