From de720e326dea56d42c856ac1b2edd9eb2e1d68ff Mon Sep 17 00:00:00 2001 From: minhtrannhat Date: Sun, 23 Jun 2024 02:38:20 -0400 Subject: [PATCH] initial commit --- README.md | 27 +++ clippy/Cargo.lock | 7 + clippy/Cargo.toml | 7 + clippy/README.md | 10 + clippy/clippy1.rs | 27 +++ clippy/clippy2.rs | 16 ++ clippy/clippy3.rs | 31 +++ clippy/target/.rustc_info.json | 1 + clippy/target/CACHEDIR.TAG | 3 + clippy/target/debug/.cargo-lock | 0 .../clippy3-36457a3dd0101112/bin-clippy3 | 1 + .../clippy3-36457a3dd0101112/bin-clippy3.json | 1 + .../clippy3-36457a3dd0101112/dep-bin-clippy3 | Bin 0 -> 179 bytes .../invoked.timestamp | 1 + .../debug/deps/clippy3-36457a3dd0101112.d | 9 + .../deps/libclippy3-36457a3dd0101112.rmeta | 0 .../dep-graph.bin | Bin 0 -> 227056 bytes .../query-cache.bin | Bin 0 -> 20877 bytes .../work-products.bin | Bin 0 -> 37 bytes .../s-gxdmf3oscz-16pz0w8.lock | 0 conversions/README.md | 23 ++ conversions/as_ref_mut.rs | 65 ++++++ conversions/from_into.rs | 165 ++++++++++++++ conversions/from_str.rs | 156 +++++++++++++ conversions/try_from_into.rs | 212 ++++++++++++++++++ conversions/using_as.rs | 33 +++ enums/README.md | 10 + enums/enums1.rs | 21 ++ enums/enums2.rs | 34 +++ enums/enums3.rs | 83 +++++++ error_handling/README.md | 12 + error_handling/errors1.rs | 43 ++++ error_handling/errors2.rs | 52 +++++ error_handling/errors3.rs | 34 +++ error_handling/errors4.rs | 37 +++ error_handling/errors5.rs | 71 ++++++ error_handling/errors6.rs | 100 +++++++++ functions/README.md | 8 + functions/functions1.rs | 14 ++ functions/functions2.rs | 16 ++ functions/functions3.rs | 16 ++ functions/functions4.rs | 28 +++ functions/functions5.rs | 15 ++ generics/README.md | 11 + generics/generics1.rs | 14 ++ generics/generics2.rs | 34 +++ hashmaps/README.md | 12 + hashmaps/hashmaps1.rs | 49 ++++ hashmaps/hashmaps2.rs | 96 ++++++++ hashmaps/hashmaps3.rs | 106 +++++++++ if/README.md | 7 + if/if1.rs | 38 ++++ if/if2.rs | 39 ++++ if/if3.rs | 56 +++++ intro/README.md | 8 + intro/intro1.rs | 41 ++++ intro/intro2.rs | 12 + iterators/README.md | 8 + iterators/iterators1.rs | 26 +++ iterators/iterators2.rs | 71 ++++++ iterators/iterators3.rs | 97 ++++++++ iterators/iterators4.rs | 46 ++++ iterators/iterators5.rs | 165 ++++++++++++++ lifetimes/README.md | 22 ++ lifetimes/lifetimes1.rs | 27 +++ lifetimes/lifetimes2.rs | 27 +++ lifetimes/lifetimes3.rs | 24 ++ macros/README.md | 14 ++ macros/macros1.rs | 16 ++ macros/macros2.rs | 16 ++ macros/macros3.rs | 21 ++ macros/macros4.rs | 21 ++ modules/README.md | 7 + modules/modules1.rs | 22 ++ modules/modules2.rs | 34 +++ modules/modules3.rs | 21 ++ move_semantics/README.md | 10 + move_semantics/move_semantics1.rs | 23 ++ move_semantics/move_semantics2.rs | 26 +++ move_semantics/move_semantics3.rs | 24 ++ move_semantics/move_semantics4.rs | 29 +++ move_semantics/move_semantics5.rs | 22 ++ move_semantics/move_semantics6.rs | 28 +++ options/README.md | 21 ++ options/options1.rs | 43 ++++ options/options2.rs | 42 ++++ options/options3.rs | 21 ++ primitive_types/README.md | 9 + primitive_types/primitive_types1.rs | 20 ++ primitive_types/primitive_types2.rs | 32 +++ primitive_types/primitive_types3.rs | 19 ++ primitive_types/primitive_types4.rs | 17 ++ primitive_types/primitive_types5.rs | 15 ++ primitive_types/primitive_types6.rs | 18 ++ quiz1.rs | 38 ++++ quiz2.rs | 72 ++++++ quiz3.rs | 68 ++++++ smart_pointers/README.md | 12 + smart_pointers/arc1.rs | 45 ++++ smart_pointers/box1.rs | 58 +++++ smart_pointers/cow1.rs | 81 +++++++ smart_pointers/rc1.rs | 105 +++++++++ strings/README.md | 9 + strings/strings1.rs | 17 ++ strings/strings2.rs | 21 ++ strings/strings3.rs | 51 +++++ strings/strings4.rs | 30 +++ structs/README.md | 8 + structs/structs1.rs | 57 +++++ structs/structs2.rs | 58 +++++ structs/structs3.rs | 88 ++++++++ tests/README.md | 7 + tests/tests1.rs | 21 ++ tests/tests2.rs | 18 ++ tests/tests3.rs | 29 +++ tests/tests4.rs | 50 +++++ threads/README.md | 9 + threads/threads1.rs | 40 ++++ threads/threads2.rs | 43 ++++ threads/threads3.rs | 74 ++++++ traits/README.md | 19 ++ traits/traits1.rs | 45 ++++ traits/traits2.rs | 35 +++ traits/traits3.rs | 44 ++++ traits/traits4.rs | 49 ++++ traits/traits5.rs | 40 ++++ variables/README.md | 9 + variables/variables1.rs | 13 ++ variables/variables2.rs | 15 ++ variables/variables3.rs | 11 + variables/variables4.rs | 13 ++ variables/variables5.rs | 13 ++ variables/variables6.rs | 11 + vecs/README.md | 17 ++ vecs/vecs1.rs | 28 +++ vecs/vecs2.rs | 46 ++++ 136 files changed, 4533 insertions(+) create mode 100644 README.md create mode 100644 clippy/Cargo.lock create mode 100644 clippy/Cargo.toml create mode 100644 clippy/README.md create mode 100644 clippy/clippy1.rs create mode 100644 clippy/clippy2.rs create mode 100644 clippy/clippy3.rs create mode 100644 clippy/target/.rustc_info.json create mode 100644 clippy/target/CACHEDIR.TAG create mode 100644 clippy/target/debug/.cargo-lock create mode 100644 clippy/target/debug/.fingerprint/clippy3-36457a3dd0101112/bin-clippy3 create mode 100644 clippy/target/debug/.fingerprint/clippy3-36457a3dd0101112/bin-clippy3.json create mode 100644 clippy/target/debug/.fingerprint/clippy3-36457a3dd0101112/dep-bin-clippy3 create mode 100644 clippy/target/debug/.fingerprint/clippy3-36457a3dd0101112/invoked.timestamp create mode 100644 clippy/target/debug/deps/clippy3-36457a3dd0101112.d create mode 100644 clippy/target/debug/deps/libclippy3-36457a3dd0101112.rmeta create mode 100644 clippy/target/debug/incremental/clippy3-12qhvn3bdilop/s-gxdmf3oscz-16pz0w8-3nzh3nzjjtl2pdmt5nq0xxa48/dep-graph.bin create mode 100644 clippy/target/debug/incremental/clippy3-12qhvn3bdilop/s-gxdmf3oscz-16pz0w8-3nzh3nzjjtl2pdmt5nq0xxa48/query-cache.bin create mode 100644 clippy/target/debug/incremental/clippy3-12qhvn3bdilop/s-gxdmf3oscz-16pz0w8-3nzh3nzjjtl2pdmt5nq0xxa48/work-products.bin create mode 100644 clippy/target/debug/incremental/clippy3-12qhvn3bdilop/s-gxdmf3oscz-16pz0w8.lock create mode 100644 conversions/README.md create mode 100644 conversions/as_ref_mut.rs create mode 100644 conversions/from_into.rs create mode 100644 conversions/from_str.rs create mode 100644 conversions/try_from_into.rs create mode 100644 conversions/using_as.rs create mode 100644 enums/README.md create mode 100644 enums/enums1.rs create mode 100644 enums/enums2.rs create mode 100644 enums/enums3.rs create mode 100644 error_handling/README.md create mode 100644 error_handling/errors1.rs create mode 100644 error_handling/errors2.rs create mode 100644 error_handling/errors3.rs create mode 100644 error_handling/errors4.rs create mode 100644 error_handling/errors5.rs create mode 100644 error_handling/errors6.rs create mode 100644 functions/README.md create mode 100644 functions/functions1.rs create mode 100644 functions/functions2.rs create mode 100644 functions/functions3.rs create mode 100644 functions/functions4.rs create mode 100644 functions/functions5.rs create mode 100644 generics/README.md create mode 100644 generics/generics1.rs create mode 100644 generics/generics2.rs create mode 100644 hashmaps/README.md create mode 100644 hashmaps/hashmaps1.rs create mode 100644 hashmaps/hashmaps2.rs create mode 100644 hashmaps/hashmaps3.rs create mode 100644 if/README.md create mode 100644 if/if1.rs create mode 100644 if/if2.rs create mode 100644 if/if3.rs create mode 100644 intro/README.md create mode 100644 intro/intro1.rs create mode 100644 intro/intro2.rs create mode 100644 iterators/README.md create mode 100644 iterators/iterators1.rs create mode 100644 iterators/iterators2.rs create mode 100644 iterators/iterators3.rs create mode 100644 iterators/iterators4.rs create mode 100644 iterators/iterators5.rs create mode 100644 lifetimes/README.md create mode 100644 lifetimes/lifetimes1.rs create mode 100644 lifetimes/lifetimes2.rs create mode 100644 lifetimes/lifetimes3.rs create mode 100644 macros/README.md create mode 100644 macros/macros1.rs create mode 100644 macros/macros2.rs create mode 100644 macros/macros3.rs create mode 100644 macros/macros4.rs create mode 100644 modules/README.md create mode 100644 modules/modules1.rs create mode 100644 modules/modules2.rs create mode 100644 modules/modules3.rs create mode 100644 move_semantics/README.md create mode 100644 move_semantics/move_semantics1.rs create mode 100644 move_semantics/move_semantics2.rs create mode 100644 move_semantics/move_semantics3.rs create mode 100644 move_semantics/move_semantics4.rs create mode 100644 move_semantics/move_semantics5.rs create mode 100644 move_semantics/move_semantics6.rs create mode 100644 options/README.md create mode 100644 options/options1.rs create mode 100644 options/options2.rs create mode 100644 options/options3.rs create mode 100644 primitive_types/README.md create mode 100644 primitive_types/primitive_types1.rs create mode 100644 primitive_types/primitive_types2.rs create mode 100644 primitive_types/primitive_types3.rs create mode 100644 primitive_types/primitive_types4.rs create mode 100644 primitive_types/primitive_types5.rs create mode 100644 primitive_types/primitive_types6.rs create mode 100644 quiz1.rs create mode 100644 quiz2.rs create mode 100644 quiz3.rs create mode 100644 smart_pointers/README.md create mode 100644 smart_pointers/arc1.rs create mode 100644 smart_pointers/box1.rs create mode 100644 smart_pointers/cow1.rs create mode 100644 smart_pointers/rc1.rs create mode 100644 strings/README.md create mode 100644 strings/strings1.rs create mode 100644 strings/strings2.rs create mode 100644 strings/strings3.rs create mode 100644 strings/strings4.rs create mode 100644 structs/README.md create mode 100644 structs/structs1.rs create mode 100644 structs/structs2.rs create mode 100644 structs/structs3.rs create mode 100644 tests/README.md create mode 100644 tests/tests1.rs create mode 100644 tests/tests2.rs create mode 100644 tests/tests3.rs create mode 100644 tests/tests4.rs create mode 100644 threads/README.md create mode 100644 threads/threads1.rs create mode 100644 threads/threads2.rs create mode 100644 threads/threads3.rs create mode 100644 traits/README.md create mode 100644 traits/traits1.rs create mode 100644 traits/traits2.rs create mode 100644 traits/traits3.rs create mode 100644 traits/traits4.rs create mode 100644 traits/traits5.rs create mode 100644 variables/README.md create mode 100644 variables/variables1.rs create mode 100644 variables/variables2.rs create mode 100644 variables/variables3.rs create mode 100644 variables/variables4.rs create mode 100644 variables/variables5.rs create mode 100644 variables/variables6.rs create mode 100644 vecs/README.md create mode 100644 vecs/vecs1.rs create mode 100644 vecs/vecs2.rs diff --git a/README.md b/README.md new file mode 100644 index 0000000..c7effa9 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# Exercise to Book Chapter mapping + +| Exercise | Book Chapter | +| ---------------------- | ------------------- | +| variables | §3.1 | +| functions | §3.3 | +| if | §3.5 | +| primitive_types | §3.2, §4.3 | +| vecs | §8.1 | +| move_semantics | §4.1-2 | +| structs | §5.1, §5.3 | +| enums | §6, §18.3 | +| strings | §8.2 | +| modules | §7 | +| hashmaps | §8.3 | +| options | §10.1 | +| error_handling | §9 | +| generics | §10 | +| traits | §10.2 | +| tests | §11.1 | +| lifetimes | §10.3 | +| iterators | §13.2-4 | +| threads | §16.1-3 | +| smart_pointers | §15, §16.3 | +| macros | §19.6 | +| clippy | §21.4 | +| conversions | n/a | diff --git a/clippy/Cargo.lock b/clippy/Cargo.lock new file mode 100644 index 0000000..d0fc406 --- /dev/null +++ b/clippy/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "clippy3" +version = "0.0.1" diff --git a/clippy/Cargo.toml b/clippy/Cargo.toml new file mode 100644 index 0000000..44dc91f --- /dev/null +++ b/clippy/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "clippy3" +version = "0.0.1" +edition = "2021" +[[bin]] +name = "clippy3" +path = "clippy3.rs" \ No newline at end of file diff --git a/clippy/README.md b/clippy/README.md new file mode 100644 index 0000000..55438af --- /dev/null +++ b/clippy/README.md @@ -0,0 +1,10 @@ +# Clippy + +The Clippy tool is a collection of lints to analyze your code so you can catch common mistakes and improve your Rust code. + +If you used the installation script for Rustlings, Clippy should be already installed. +If not you can install it manually via `rustup component add clippy`. + +## Further information + +- [GitHub Repository](https://github.com/rust-lang/rust-clippy). diff --git a/clippy/clippy1.rs b/clippy/clippy1.rs new file mode 100644 index 0000000..49f282a --- /dev/null +++ b/clippy/clippy1.rs @@ -0,0 +1,27 @@ +// clippy1.rs +// +// The Clippy tool is a collection of lints to analyze your code so you can +// catch common mistakes and improve your Rust code. +// +// For these exercises the code will fail to compile when there are clippy +// warnings check clippy's suggestions from the output to solve the exercise. +// +// Execute `rustlings hint clippy1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +use std::f32; + +#[allow(clippy::approx_constant)] +fn main() { + let pi = 3.14f32; + let radius = 5.00f32; + + let area = pi * f32::powi(radius, 2); + + println!( + "The area of a circle with radius {:.2} is {:.5}!", + radius, area + ) +} diff --git a/clippy/clippy2.rs b/clippy/clippy2.rs new file mode 100644 index 0000000..56a0e01 --- /dev/null +++ b/clippy/clippy2.rs @@ -0,0 +1,16 @@ +// clippy2.rs +// +// Execute `rustlings hint clippy2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +#[allow(for_loops_over_fallibles)] +fn main() { + let mut res = 42; + let option = Some(12); + for x in option { + res += x; + } + println!("{}", res); +} diff --git a/clippy/clippy3.rs b/clippy/clippy3.rs new file mode 100644 index 0000000..ef2a916 --- /dev/null +++ b/clippy/clippy3.rs @@ -0,0 +1,31 @@ +// clippy3.rs +// +// Here's a couple more easy Clippy fixes, so you can see its utility. +// No hints. + +// I AM DONE + +#[allow(unused_variables, unused_assignments)] +#[allow(clippy::panicking_unwrap)] +#[allow(clippy::almost_swapped)] +#[allow(clippy::unnecessary_literal_unwrap)] +#[allow(clippy::let_unit_value)] +fn main() { + let my_option: Option<()> = None; + if my_option.is_none() { + my_option.unwrap(); + } + + let my_arr = &[-1, -2, -3 - 4, -5, -6]; + println!("My array! Here it is: {:?}", my_arr); + + let my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5); + println!("This Vec is empty, see? {:?}", my_empty_vec); + + let mut value_a = 45; + let mut value_b = 66; + // Let's swap these two! + value_a = value_b; + value_b = value_a; + println!("value a: {}; value b: {}", value_a, value_b); +} diff --git a/clippy/target/.rustc_info.json b/clippy/target/.rustc_info.json new file mode 100644 index 0000000..bade02e --- /dev/null +++ b/clippy/target/.rustc_info.json @@ -0,0 +1 @@ +{"rustc_fingerprint":11792070684003744821,"outputs":{"17471738939474973447":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/minhradz/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\nclippy\ndebug_assertions\nfeature=\"cargo-clippy\"\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"14478210374123597319":{"success":true,"status":"","code":0,"stdout":"rustc 1.79.0 (129f3b996 2024-06-10)\nbinary: rustc\ncommit-hash: 129f3b9964af4d4a709d1383930ade12dfe7c081\ncommit-date: 2024-06-10\nhost: x86_64-unknown-linux-gnu\nrelease: 1.79.0\nLLVM version: 18.1.7\n","stderr":""}},"successes":{}} \ No newline at end of file diff --git a/clippy/target/CACHEDIR.TAG b/clippy/target/CACHEDIR.TAG new file mode 100644 index 0000000..20d7c31 --- /dev/null +++ b/clippy/target/CACHEDIR.TAG @@ -0,0 +1,3 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by cargo. +# For information about cache directory tags see https://bford.info/cachedir/ diff --git a/clippy/target/debug/.cargo-lock b/clippy/target/debug/.cargo-lock new file mode 100644 index 0000000..e69de29 diff --git a/clippy/target/debug/.fingerprint/clippy3-36457a3dd0101112/bin-clippy3 b/clippy/target/debug/.fingerprint/clippy3-36457a3dd0101112/bin-clippy3 new file mode 100644 index 0000000..c09ce4c --- /dev/null +++ b/clippy/target/debug/.fingerprint/clippy3-36457a3dd0101112/bin-clippy3 @@ -0,0 +1 @@ +9d78001aa0a9fe34 \ No newline at end of file diff --git a/clippy/target/debug/.fingerprint/clippy3-36457a3dd0101112/bin-clippy3.json b/clippy/target/debug/.fingerprint/clippy3-36457a3dd0101112/bin-clippy3.json new file mode 100644 index 0000000..4aa936c --- /dev/null +++ b/clippy/target/debug/.fingerprint/clippy3-36457a3dd0101112/bin-clippy3.json @@ -0,0 +1 @@ +{"rustc":18217185010275080438,"features":"[]","declared_features":"","target":15082887096810505001,"profile":5601947868832436996,"path":2386747541556052359,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/clippy3-36457a3dd0101112/dep-bin-clippy3"}}],"rustflags":["-C","link-arg=-fuse-ld=/usr/bin/mold"],"metadata":7797948686568424061,"config":16520146531172537597,"compile_kind":0} \ No newline at end of file diff --git a/clippy/target/debug/.fingerprint/clippy3-36457a3dd0101112/dep-bin-clippy3 b/clippy/target/debug/.fingerprint/clippy3-36457a3dd0101112/dep-bin-clippy3 new file mode 100644 index 0000000000000000000000000000000000000000..6cc5167b77fc06055c496b59d280db0f791a7ad8 GIT binary patch literal 179 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

Y2jA=cLRjBsK@R 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 literal 0 HcmV?d00001 diff --git a/clippy/target/debug/incremental/clippy3-12qhvn3bdilop/s-gxdmf3oscz-16pz0w8-3nzh3nzjjtl2pdmt5nq0xxa48/work-products.bin b/clippy/target/debug/incremental/clippy3-12qhvn3bdilop/s-gxdmf3oscz-16pz0w8-3nzh3nzjjtl2pdmt5nq0xxa48/work-products.bin new file mode 100644 index 0000000000000000000000000000000000000000..b1f76f0181564b5da1ef300af5e4d4d7a2d0aeb1 GIT binary patch literal 37 scmWFv_H<@okTujZx70IG&@eQzOfychv@}yNGB7gHH89gPG|*%K0F9alH2?qr literal 0 HcmV?d00001 diff --git a/clippy/target/debug/incremental/clippy3-12qhvn3bdilop/s-gxdmf3oscz-16pz0w8.lock b/clippy/target/debug/incremental/clippy3-12qhvn3bdilop/s-gxdmf3oscz-16pz0w8.lock new file mode 100644 index 0000000..e69de29 diff --git a/conversions/README.md b/conversions/README.md new file mode 100644 index 0000000..619a78c --- /dev/null +++ b/conversions/README.md @@ -0,0 +1,23 @@ +# Type conversions + +Rust offers a multitude of ways to convert a value of a given type into another type. + +The simplest form of type conversion is a type cast expression. It is denoted with the binary operator `as`. For instance, `println!("{}", 1 + 1.0);` would not compile, since `1` is an integer while `1.0` is a float. However, `println!("{}", 1 as f32 + 1.0)` should compile. The exercise [`using_as`](using_as.rs) tries to cover this. + +Rust also offers traits that facilitate type conversions upon implementation. These traits can be found under the [`convert`](https://doc.rust-lang.org/std/convert/index.html) module. +The traits are the following: + +- `From` and `Into` covered in [`from_into`](from_into.rs) +- `TryFrom` and `TryInto` covered in [`try_from_into`](try_from_into.rs) +- `AsRef` and `AsMut` covered in [`as_ref_mut`](as_ref_mut.rs) + +Furthermore, the `std::str` module offers a trait called [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) which helps with converting strings into target types via the `parse` method on strings. If properly implemented for a given type `Person`, then `let p: Person = "Mark,20".parse().unwrap()` should both compile and run without panicking. + +These should be the main ways ***within the standard library*** to convert data into your desired types. + +## Further information + +These are not directly covered in the book, but the standard library has a great documentation for it. + +- [conversions](https://doc.rust-lang.org/std/convert/index.html) +- [`FromStr` trait](https://doc.rust-lang.org/std/str/trait.FromStr.html) diff --git a/conversions/as_ref_mut.rs b/conversions/as_ref_mut.rs new file mode 100644 index 0000000..9e512e0 --- /dev/null +++ b/conversions/as_ref_mut.rs @@ -0,0 +1,65 @@ +// as_ref_mut.rs +// +// AsRef and AsMut allow for cheap reference-to-reference conversions. Read more +// about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html and +// https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively. +// +// Execute `rustlings hint as_ref_mut` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +// Obtain the number of bytes (not characters) in the given argument. +// TODO: Add the AsRef trait appropriately as a trait bound. +fn byte_counter>(arg: T) -> usize { + arg.as_ref().as_bytes().len() +} + +// Obtain the number of characters (not bytes) in the given argument. +// TODO: Add the AsRef trait appropriately as a trait bound. +fn char_counter>(arg: T) -> usize { + arg.as_ref().chars().count() +} + +// Squares a number using as_mut(). +// TODO: Add the appropriate trait bound. +fn num_sq>(arg: &mut T) { + // TODO: Implement the function body. + *arg.as_mut() = *arg.as_mut() * *arg.as_mut() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn different_counts() { + let s = "Café au lait"; + assert_ne!(char_counter(s), byte_counter(s)); + } + + #[test] + fn same_counts() { + let s = "Cafe au lait"; + assert_eq!(char_counter(s), byte_counter(s)); + } + + #[test] + fn different_counts_using_string() { + let s = String::from("Café au lait"); + assert_ne!(char_counter(s.clone()), byte_counter(s)); + } + + #[test] + fn same_counts_using_string() { + let s = String::from("Cafe au lait"); + assert_eq!(char_counter(s.clone()), byte_counter(s)); + } + + #[test] + fn mut_box() { + let mut num: Box = Box::new(3); + num_sq(&mut num); + assert_eq!(*num, 9); + } +} diff --git a/conversions/from_into.rs b/conversions/from_into.rs new file mode 100644 index 0000000..52e9fa5 --- /dev/null +++ b/conversions/from_into.rs @@ -0,0 +1,165 @@ +// from_into.rs +// +// The From trait is used for value-to-value conversions. If From is implemented +// correctly for a type, the Into trait should work conversely. You can read +// more about it at https://doc.rust-lang.org/std/convert/trait.From.html +// +// Execute `rustlings hint from_into` or use the `hint` watch subcommand for a +// hint. + +#[derive(Debug)] +struct Person { + name: String, + age: usize, +} + +// We implement the Default trait to use it as a fallback +// when the provided string is not convertible into a Person object +impl Default for Person { + fn default() -> Person { + Person { + name: String::from("John"), + age: 30, + } + } +} + +// Your task is to complete this implementation in order for the line `let p = +// Person::from("Mark,20")` to compile Please note that you'll need to parse the +// age component into a `usize` with something like `"4".parse::()`. The +// outcome of this needs to be handled appropriately. +// +// Steps: +// 1. If the length of the provided string is 0, then return the default of +// Person. +// 2. Split the given string on the commas present in it. +// 3. Extract the first element from the split operation and use it as the name. +// 4. If the name is empty, then return the default of Person. +// 5. Extract the other element from the split operation and parse it into a +// `usize` as the age. +// If while parsing the age, something goes wrong, then return the default of +// Person Otherwise, then return an instantiated Person object with the results + +// I AM DONE + +impl From<&str> for Person { + fn from(s: &str) -> Person { + if s.len() == 0 { + Person::default() + } else { + let mut str_iter = s.split(","); + + let name = match str_iter.next() { + Some("") | None => return Person::default(), + Some(valid_name) => String::from(valid_name), + }; + + let age = match str_iter.next() { + Some(could_be_usize) => match could_be_usize.parse::() { + Ok(age) => age, + Err(_) => return Person::default(), + }, + None => return Person::default(), + }; + + return Person { name, age }; + + // match str_iter.next() { + // Some(_) => return Person::default(), + // None => return Person { name, age }, + // } + } + } +} + +fn main() { + // Use the `from` function + let p1 = Person::from("Mark,20"); + // Since From is implemented for Person, we should be able to use Into + let p2: Person = "Gerald,70".into(); + println!("{:?}", p1); + println!("{:?}", p2); +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_default() { + // Test that the default person is 30 year old John + let dp = Person::default(); + assert_eq!(dp.name, "John"); + assert_eq!(dp.age, 30); + } + #[test] + fn test_bad_convert() { + // Test that John is returned when bad string is provided + let p = Person::from(""); + assert_eq!(p.name, "John"); + assert_eq!(p.age, 30); + } + #[test] + fn test_good_convert() { + // Test that "Mark,20" works + let p = Person::from("Mark,20"); + assert_eq!(p.name, "Mark"); + assert_eq!(p.age, 20); + } + #[test] + fn test_bad_age() { + // Test that "Mark,twenty" will return the default person due to an + // error in parsing age + let p = Person::from("Mark,twenty"); + assert_eq!(p.name, "John"); + assert_eq!(p.age, 30); + } + + #[test] + fn test_missing_comma_and_age() { + let p: Person = Person::from("Mark"); + assert_eq!(p.name, "John"); + assert_eq!(p.age, 30); + } + + #[test] + fn test_missing_age() { + let p: Person = Person::from("Mark,"); + assert_eq!(p.name, "John"); + assert_eq!(p.age, 30); + } + + #[test] + fn test_missing_name() { + let p: Person = Person::from(",1"); + assert_eq!(p.name, "John"); + assert_eq!(p.age, 30); + } + + #[test] + fn test_missing_name_and_age() { + let p: Person = Person::from(","); + assert_eq!(p.name, "John"); + assert_eq!(p.age, 30); + } + + #[test] + fn test_missing_name_and_invalid_age() { + let p: Person = Person::from(",one"); + assert_eq!(p.name, "John"); + assert_eq!(p.age, 30); + } + + #[test] + fn test_trailing_comma() { + let p: Person = Person::from("Mike,32,"); + assert_eq!(p.name, "Mike"); + assert_eq!(p.age, 32); + } + + #[test] + fn test_trailing_comma_and_some_string() { + let p: Person = Person::from("Mike,32,man"); + assert_eq!(p.name, "Mike"); + assert_eq!(p.age, 32); + } +} diff --git a/conversions/from_str.rs b/conversions/from_str.rs new file mode 100644 index 0000000..cb85475 --- /dev/null +++ b/conversions/from_str.rs @@ -0,0 +1,156 @@ +// from_str.rs +// +// This is similar to from_into.rs, but this time we'll implement `FromStr` and +// return errors instead of falling back to a default value. Additionally, upon +// implementing FromStr, you can use the `parse` method on strings to generate +// an object of the implementor type. You can read more about it at +// https://doc.rust-lang.org/std/str/trait.FromStr.html +// +// Execute `rustlings hint from_str` or use the `hint` watch subcommand for a +// hint. + +use std::num::ParseIntError; +use std::str::FromStr; + +#[derive(Debug, PartialEq)] +struct Person { + name: String, + age: usize, +} + +// We will use this error type for the `FromStr` implementation. +#[derive(Debug, PartialEq)] +enum ParsePersonError { + // Empty input string + Empty, + // Incorrect number of fields + BadLen, + // Empty name field + NoName, + // Wrapped error from parse::() + ParseInt(ParseIntError), +} + +// I AM DONE + +// Steps: +// 1. If the length of the provided string is 0, an error should be returned +// 2. Split the given string on the commas present in it +// 3. Only 2 elements should be returned from the split, otherwise return an +// error +// 4. Extract the first element from the split operation and use it as the name +// 5. Extract the other element from the split operation and parse it into a +// `usize` as the age with something like `"4".parse::()` +// 6. If while extracting the name and the age something goes wrong, an error +// should be returned +// If everything goes well, then return a Result of a Person object +// +// As an aside: `Box` implements `From<&'_ str>`. This means that if +// you want to return a string error message, you can do so via just using +// return `Err("my error message".into())`. + +impl FromStr for Person { + type Err = ParsePersonError; + fn from_str(s: &str) -> Result { + if s.len() == 0 { + Err(ParsePersonError::Empty) + } else { + let mut str_iter = s.split(","); + + let name = match str_iter.next() { + Some("") | None => return Err(ParsePersonError::NoName), + Some(valid_name) => String::from(valid_name), + }; + + let age = match str_iter.next() { + Some(could_be_usize) => match could_be_usize.parse::() { + Ok(age) => age, + Err(e) => return Err(ParsePersonError::ParseInt(e)), + }, + None => return Err(ParsePersonError::BadLen), + }; + + match str_iter.next() { + Some(_) => return Err(ParsePersonError::BadLen), + None => return Ok(Person { name, age }), + } + } + } +} + +fn main() { + let p = "Mark,20".parse::().unwrap(); + println!("{:?}", p); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn empty_input() { + assert_eq!("".parse::(), Err(ParsePersonError::Empty)); + } + #[test] + fn good_input() { + let p = "John,32".parse::(); + assert!(p.is_ok()); + let p = p.unwrap(); + assert_eq!(p.name, "John"); + assert_eq!(p.age, 32); + } + #[test] + fn missing_age() { + assert!(matches!( + "John,".parse::(), + Err(ParsePersonError::ParseInt(_)) + )); + } + + #[test] + fn invalid_age() { + assert!(matches!( + "John,twenty".parse::(), + Err(ParsePersonError::ParseInt(_)) + )); + } + + #[test] + fn missing_comma_and_age() { + assert_eq!("John".parse::(), Err(ParsePersonError::BadLen)); + } + + #[test] + fn missing_name() { + assert_eq!(",1".parse::(), Err(ParsePersonError::NoName)); + } + + #[test] + fn missing_name_and_age() { + assert!(matches!( + ",".parse::(), + Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_)) + )); + } + + #[test] + fn missing_name_and_invalid_age() { + assert!(matches!( + ",one".parse::(), + Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_)) + )); + } + + #[test] + fn trailing_comma() { + assert_eq!("John,32,".parse::(), Err(ParsePersonError::BadLen)); + } + + #[test] + fn trailing_comma_and_some_string() { + assert_eq!( + "John,32,man".parse::(), + Err(ParsePersonError::BadLen) + ); + } +} diff --git a/conversions/try_from_into.rs b/conversions/try_from_into.rs new file mode 100644 index 0000000..de578cc --- /dev/null +++ b/conversions/try_from_into.rs @@ -0,0 +1,212 @@ +// try_from_into.rs +// +// TryFrom is a simple and safe type conversion that may fail in a controlled +// way under some circumstances. Basically, this is the same as From. The main +// difference is that this should return a Result type instead of the target +// type itself. You can read more about it at +// https://doc.rust-lang.org/std/convert/trait.TryFrom.html +// +// Execute `rustlings hint try_from_into` or use the `hint` watch subcommand for +// a hint. + +use std::{ + convert::{TryFrom, TryInto}, + error::Error, + ops::RangeBounds, +}; + +#[derive(Debug, PartialEq)] +struct Color { + red: u8, + green: u8, + blue: u8, +} + +// We will use this error type for these `TryFrom` conversions. +#[derive(Debug, PartialEq)] +enum IntoColorError { + // Incorrect length of slice + BadLen, + // Integer conversion error + IntConversion, +} + +// I AM DONE + +// Your task is to complete this implementation and return an Ok result of inner +// type Color. You need to create an implementation for a tuple of three +// integers, an array of three integers, and a slice of integers. +// +// Note that the implementation for tuple and array will be checked at compile +// time, but the slice implementation needs to check the slice length! Also note +// that correct RGB color values must be integers in the 0..=255 range. + +// Tuple implementation +impl TryFrom<(i16, i16, i16)> for Color { + type Error = IntoColorError; + fn try_from(tuple: (i16, i16, i16)) -> Result { + let (red_i16, green_i16, blue_i16) = tuple; + + let (red, green, blue) = ( + u8::try_from(red_i16).or(Err(IntoColorError::IntConversion))?, + u8::try_from(green_i16).or(Err(IntoColorError::IntConversion))?, + u8::try_from(blue_i16).or(Err(IntoColorError::IntConversion))?, + ); + + Ok(Color { red, green, blue }) + } +} + +// Array implementation +impl TryFrom<[i16; 3]> for Color { + type Error = IntoColorError; + fn try_from(arr: [i16; 3]) -> Result { + let [r, g, b] = arr; + (r, g, b).try_into() + } +} + +// Slice implementation +impl TryFrom<&[i16]> for Color { + type Error = IntoColorError; + fn try_from(slice: &[i16]) -> Result { + match slice { + [r, g, b] => Color::try_from((*r, *g, *b)), + _ => Err(IntoColorError::BadLen)?, + } + } +} + +fn main() { + // Use the `try_from` function + let c1 = Color::try_from((183, 65, 14)); + println!("{:?}", c1); + + // Since TryFrom is implemented for Color, we should be able to use TryInto + let c2: Result = [183, 65, 14].try_into(); + println!("{:?}", c2); + + let v = vec![183, 65, 14]; + // With slice we should use `try_from` function + let c3 = Color::try_from(&v[..]); + println!("{:?}", c3); + // or take slice within round brackets and use TryInto + let c4: Result = (&v[..]).try_into(); + println!("{:?}", c4); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_tuple_out_of_range_positive() { + assert_eq!( + Color::try_from((256, 1000, 10000)), + Err(IntoColorError::IntConversion) + ); + } + #[test] + fn test_tuple_out_of_range_negative() { + assert_eq!( + Color::try_from((-1, -10, -256)), + Err(IntoColorError::IntConversion) + ); + } + #[test] + fn test_tuple_sum() { + assert_eq!( + Color::try_from((-1, 255, 255)), + Err(IntoColorError::IntConversion) + ); + } + #[test] + fn test_tuple_correct() { + let c: Result = (183, 65, 14).try_into(); + assert!(c.is_ok()); + assert_eq!( + c.unwrap(), + Color { + red: 183, + green: 65, + blue: 14 + } + ); + } + #[test] + fn test_array_out_of_range_positive() { + let c: Result = [1000, 10000, 256].try_into(); + assert_eq!(c, Err(IntoColorError::IntConversion)); + } + #[test] + fn test_array_out_of_range_negative() { + let c: Result = [-10, -256, -1].try_into(); + assert_eq!(c, Err(IntoColorError::IntConversion)); + } + #[test] + fn test_array_sum() { + let c: Result = [-1, 255, 255].try_into(); + assert_eq!(c, Err(IntoColorError::IntConversion)); + } + #[test] + fn test_array_correct() { + let c: Result = [183, 65, 14].try_into(); + assert!(c.is_ok()); + assert_eq!( + c.unwrap(), + Color { + red: 183, + green: 65, + blue: 14 + } + ); + } + #[test] + fn test_slice_out_of_range_positive() { + let arr = [10000, 256, 1000]; + assert_eq!( + Color::try_from(&arr[..]), + Err(IntoColorError::IntConversion) + ); + } + #[test] + fn test_slice_out_of_range_negative() { + let arr = [-256, -1, -10]; + assert_eq!( + Color::try_from(&arr[..]), + Err(IntoColorError::IntConversion) + ); + } + #[test] + fn test_slice_sum() { + let arr = [-1, 255, 255]; + assert_eq!( + Color::try_from(&arr[..]), + Err(IntoColorError::IntConversion) + ); + } + #[test] + fn test_slice_correct() { + let v = vec![183, 65, 14]; + let c: Result = Color::try_from(&v[..]); + assert!(c.is_ok()); + assert_eq!( + c.unwrap(), + Color { + red: 183, + green: 65, + blue: 14 + } + ); + } + #[test] + fn test_slice_excess_length() { + let v = vec![0, 0, 0, 0]; + assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen)); + } + #[test] + fn test_slice_insufficient_length() { + let v = vec![0, 0]; + assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen)); + } +} diff --git a/conversions/using_as.rs b/conversions/using_as.rs new file mode 100644 index 0000000..42e10d8 --- /dev/null +++ b/conversions/using_as.rs @@ -0,0 +1,33 @@ +// using_as.rs +// +// Type casting in Rust is done via the usage of the `as` operator. Please note +// that the `as` operator is not only used when type casting. It also helps with +// renaming imports. +// +// The goal is to make sure that the division does not fail to compile and +// returns the proper type. +// +// Execute `rustlings hint using_as` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn average(values: &[f64]) -> f64 { + let total = values.iter().sum::(); + total / values.len() as f64 +} + +fn main() { + let values = [3.5, 0.3, 13.0, 11.7]; + println!("{}", average(&values)); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn returns_proper_type_and_value() { + assert_eq!(average(&[3.5, 0.3, 13.0, 11.7]), 7.125); + } +} diff --git a/enums/README.md b/enums/README.md new file mode 100644 index 0000000..30d4d91 --- /dev/null +++ b/enums/README.md @@ -0,0 +1,10 @@ +# Enums + +Rust allows you to define types called "enums" which enumerate possible values. +Enums are a feature in many languages, but their capabilities differ in each language. Rust’s enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell. +Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration. + +## Further information + +- [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html) +- [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html) diff --git a/enums/enums1.rs b/enums/enums1.rs new file mode 100644 index 0000000..9093d82 --- /dev/null +++ b/enums/enums1.rs @@ -0,0 +1,21 @@ +// enums1.rs +// +// No hints this time! ;) + +// I AM DONE + +#[derive(Debug)] +enum Message { + // TODO: define a few types of messages as used below + Quit, + Echo, + Move, + ChangeColor, +} + +fn main() { + println!("{:?}", Message::Quit); + println!("{:?}", Message::Echo); + println!("{:?}", Message::Move); + println!("{:?}", Message::ChangeColor); +} diff --git a/enums/enums2.rs b/enums/enums2.rs new file mode 100644 index 0000000..164b419 --- /dev/null +++ b/enums/enums2.rs @@ -0,0 +1,34 @@ +// enums2.rs +// +// Execute `rustlings hint enums2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +#[derive(Debug)] +enum Message { + // TODO: define the different variants used below + Move { x: u8, y: u8 }, + Echo(String), + ChangeColor(u8, u8, u8), + Quit, +} + +impl Message { + fn call(&self) { + println!("{:?}", self); + } +} + +fn main() { + let messages = [ + Message::Move { x: 10, y: 30 }, + Message::Echo(String::from("hello world")), + Message::ChangeColor(200, 255, 255), + Message::Quit, + ]; + + for message in &messages { + message.call(); + } +} diff --git a/enums/enums3.rs b/enums/enums3.rs new file mode 100644 index 0000000..8143afc --- /dev/null +++ b/enums/enums3.rs @@ -0,0 +1,83 @@ +// enums3.rs +// +// Address all the TODOs to make the tests pass! +// +// Execute `rustlings hint enums3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +enum Message { + ChangeColor(u8, u8, u8), + Echo(String), + Move(Point), + Quit, +} + +struct Point { + x: u8, + y: u8, +} + +struct State { + color: (u8, u8, u8), + position: Point, + quit: bool, + message: String, +} + +impl State { + fn change_color(&mut self, color: (u8, u8, u8)) { + self.color = color; + } + + fn quit(&mut self) { + self.quit = true; + } + + fn echo(&mut self, s: String) { + self.message = s + } + + fn move_position(&mut self, p: Point) { + self.position = p; + } + + fn process(&mut self, message: Message) { + // TODO: create a match expression to process the different message + // variants + // Remember: When passing a tuple as a function argument, you'll need + // extra parentheses: fn function((t, u, p, l, e)) + match message { + Message::ChangeColor(red, green, blue) => self.change_color((red, green, blue)), + Message::Move(point) => self.move_position(point), + Message::Echo(string) => self.echo(string), + Message::Quit => self.quit(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_match_message_call() { + let mut state = State { + quit: false, + position: Point { x: 0, y: 0 }, + color: (0, 0, 0), + message: "hello world".to_string(), + }; + state.process(Message::ChangeColor(255, 0, 255)); + state.process(Message::Echo(String::from("Hello world!"))); + state.process(Message::Move(Point { x: 10, y: 15 })); + state.process(Message::Quit); + + assert_eq!(state.color, (255, 0, 255)); + assert_eq!(state.position.x, 10); + assert_eq!(state.position.y, 15); + assert_eq!(state.quit, true); + assert_eq!(state.message, "Hello world!"); + } +} diff --git a/error_handling/README.md b/error_handling/README.md new file mode 100644 index 0000000..3b21f2b --- /dev/null +++ b/error_handling/README.md @@ -0,0 +1,12 @@ +# Error handling + +Most errors aren’t serious enough to require the program to stop entirely. +Sometimes, when a function fails, it’s for a reason that you can easily interpret and respond to. +For example, if you try to open a file and that operation fails because the file doesn’t exist, you might want to create the file instead of terminating the process. + +## Further information + +- [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html) +- [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html) +- [Result](https://doc.rust-lang.org/rust-by-example/error/result.html) +- [Boxing errors](https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/boxing_errors.html) diff --git a/error_handling/errors1.rs b/error_handling/errors1.rs new file mode 100644 index 0000000..a088655 --- /dev/null +++ b/error_handling/errors1.rs @@ -0,0 +1,43 @@ +// errors1.rs +// +// This function refuses to generate text to be printed on a nametag if you pass +// it an empty string. It'd be nicer if it explained what the problem was, +// instead of just sometimes returning `None`. Thankfully, Rust has a similar +// construct to `Option` that can be used to express error conditions. Let's use +// it! +// +// Execute `rustlings hint errors1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +pub fn generate_nametag_text(name: String) -> Result { + if name.is_empty() { + // Empty names aren't allowed. + Err("`name` was empty; it must be nonempty.".into()) + } else { + Ok(format!("Hi! My name is {}", name)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn generates_nametag_text_for_a_nonempty_name() { + assert_eq!( + generate_nametag_text("Beyoncé".into()), + Ok("Hi! My name is Beyoncé".into()) + ); + } + + #[test] + fn explains_why_generating_nametag_text_fails() { + assert_eq!( + generate_nametag_text("".into()), + // Don't change this line + Err("`name` was empty; it must be nonempty.".into()) + ); + } +} diff --git a/error_handling/errors2.rs b/error_handling/errors2.rs new file mode 100644 index 0000000..889ab0a --- /dev/null +++ b/error_handling/errors2.rs @@ -0,0 +1,52 @@ +// errors2.rs +// +// Say we're writing a game where you can buy items with tokens. All items cost +// 5 tokens, and whenever you purchase items there is a processing fee of 1 +// token. A player of the game will type in how many items they want to buy, and +// the `total_cost` function will calculate the total cost of the tokens. Since +// the player typed in the quantity, though, we get it as a string-- and they +// might have typed anything, not just numbers! +// +// Right now, this function isn't handling the error case at all (and isn't +// handling the success case properly either). What we want to do is: if we call +// the `total_cost` function on a string that is not a number, that function +// will return a `ParseIntError`, and in that case, we want to immediately +// return that error from our function and not try to multiply and add. +// +// There are at least two ways to implement this that are both correct-- but one +// is a lot shorter! +// +// Execute `rustlings hint errors2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +use std::num::ParseIntError; + +pub fn total_cost(item_quantity: &str) -> Result { + let processing_fee = 1; + let cost_per_item = 5; + + match item_quantity.parse::() { + Ok(qty) => Ok(qty * cost_per_item + processing_fee), + Err(e) => Err(e), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn item_quantity_is_a_valid_number() { + assert_eq!(total_cost("34"), Ok(171)); + } + + #[test] + fn item_quantity_is_an_invalid_number() { + assert_eq!( + total_cost("beep boop").unwrap_err().to_string(), + "invalid digit found in string" + ); + } +} diff --git a/error_handling/errors3.rs b/error_handling/errors3.rs new file mode 100644 index 0000000..625e3cb --- /dev/null +++ b/error_handling/errors3.rs @@ -0,0 +1,34 @@ +// errors3.rs +// +// This is a program that is trying to use a completed version of the +// `total_cost` function from the previous exercise. It's not working though! +// Why not? What should we do to fix it? +// +// Execute `rustlings hint errors3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +use std::num::ParseIntError; + +fn main() { + let mut tokens = 100; + let pretend_user_input = "8"; + + let cost = total_cost(pretend_user_input).unwrap(); + + if cost > tokens { + println!("You can't afford that many!"); + } else { + tokens -= cost; + println!("You now have {} tokens.", tokens); + } +} + +pub fn total_cost(item_quantity: &str) -> Result { + let processing_fee = 1; + let cost_per_item = 5; + let qty = item_quantity.parse::()?; + + Ok(qty * cost_per_item + processing_fee) +} diff --git a/error_handling/errors4.rs b/error_handling/errors4.rs new file mode 100644 index 0000000..8e1692d --- /dev/null +++ b/error_handling/errors4.rs @@ -0,0 +1,37 @@ +// errors4.rs +// +// Execute `rustlings hint errors4` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +#[derive(PartialEq, Debug)] +struct PositiveNonzeroInteger(u64); + +#[derive(PartialEq, Debug)] +enum CreationError { + Negative, + Zero, +} + +impl PositiveNonzeroInteger { + fn new(value: i64) -> Result { + // Hmm... Why is this always returning an Ok value? + + match value { + value if value < 0 => Err(CreationError::Negative), + value if value == 0 => Err(CreationError::Zero), + _ => Ok(PositiveNonzeroInteger(value as u64)), + } + } +} + +#[test] +fn test_creation() { + assert!(PositiveNonzeroInteger::new(10).is_ok()); + assert_eq!( + Err(CreationError::Negative), + PositiveNonzeroInteger::new(-10) + ); + assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0)); +} diff --git a/error_handling/errors5.rs b/error_handling/errors5.rs new file mode 100644 index 0000000..1e4f81b --- /dev/null +++ b/error_handling/errors5.rs @@ -0,0 +1,71 @@ +// errors5.rs +// +// This program uses an altered version of the code from errors4. +// +// This exercise uses some concepts that we won't get to until later in the +// course, like `Box` and the `From` trait. It's not important to understand +// them in detail right now, but you can read ahead if you like. For now, think +// of the `Box` type as an "I want anything that does ???" type, which, +// given Rust's usual standards for runtime safety, should strike you as +// somewhat lenient! +// +// In short, this particular use case for boxes is for when you want to own a +// value and you care only that it is a type which implements a particular +// trait. To do so, The Box is declared as of type Box where Trait is +// the trait the compiler looks for on any value used in that context. For this +// exercise, that context is the potential errors which can be returned in a +// Result. +// +// What can we use to describe both errors? In other words, is there a trait +// which both errors implement? +// +// Execute `rustlings hint errors5` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +use std::error; +use std::fmt; +use std::num::ParseIntError; + +// TODO: update the return type of `main()` to make this compile. +fn main() -> Result<(), Box> { + let pretend_user_input = "42"; + let x: i64 = pretend_user_input.parse()?; + println!("output={:?}", PositiveNonzeroInteger::new(x)?); + Ok(()) +} + +// Don't change anything below this line. + +#[derive(PartialEq, Debug)] +struct PositiveNonzeroInteger(u64); + +#[derive(PartialEq, Debug)] +enum CreationError { + Negative, + Zero, +} + +impl PositiveNonzeroInteger { + fn new(value: i64) -> Result { + match value { + x if x < 0 => Err(CreationError::Negative), + x if x == 0 => Err(CreationError::Zero), + x => Ok(PositiveNonzeroInteger(x as u64)), + } + } +} + +// This is required so that `CreationError` can implement `error::Error`. +impl fmt::Display for CreationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let description = match *self { + CreationError::Negative => "number is negative", + CreationError::Zero => "number is zero", + }; + f.write_str(description) + } +} + +impl error::Error for CreationError {} diff --git a/error_handling/errors6.rs b/error_handling/errors6.rs new file mode 100644 index 0000000..85af580 --- /dev/null +++ b/error_handling/errors6.rs @@ -0,0 +1,100 @@ +// errors6.rs +// +// Using catch-all error types like `Box` isn't recommended +// for library code, where callers might want to make decisions based on the +// error content, instead of printing it out or propagating it further. Here, we +// define a custom error type to make it possible for callers to decide what to +// do next when our function returns an error. +// +// Execute `rustlings hint errors6` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +use std::num::ParseIntError; + +// This is a custom error type that we will be using in `parse_pos_nonzero()`. +#[derive(PartialEq, Debug)] +enum ParsePosNonzeroError { + Creation(CreationError), + ParseInt(ParseIntError), +} + +impl ParsePosNonzeroError { + fn from_creation(err: CreationError) -> ParsePosNonzeroError { + ParsePosNonzeroError::Creation(err) + } + // TODO: add another error conversion function here. + fn from_parseint(err: ParseIntError) -> ParsePosNonzeroError { + ParsePosNonzeroError::ParseInt(err) + } +} + +fn parse_pos_nonzero(s: &str) -> Result { + // TODO: change this to return an appropriate error instead of panicking + // when `parse()` returns an error. + let x: Result = s.parse(); + + match x { + Ok(x) => PositiveNonzeroInteger::new(x).map_err(ParsePosNonzeroError::from_creation), + Err(err) => Err(ParsePosNonzeroError::from_parseint(err)), + } +} + +// Don't change anything below this line. + +#[derive(PartialEq, Debug)] +struct PositiveNonzeroInteger(u64); + +#[derive(PartialEq, Debug)] +enum CreationError { + Negative, + Zero, +} + +impl PositiveNonzeroInteger { + fn new(value: i64) -> Result { + match value { + x if x < 0 => Err(CreationError::Negative), + x if x == 0 => Err(CreationError::Zero), + x => Ok(PositiveNonzeroInteger(x as u64)), + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_parse_error() { + // We can't construct a ParseIntError, so we have to pattern match. + assert!(matches!( + parse_pos_nonzero("not a number"), + Err(ParsePosNonzeroError::ParseInt(_)) + )); + } + + #[test] + fn test_negative() { + assert_eq!( + parse_pos_nonzero("-555"), + Err(ParsePosNonzeroError::Creation(CreationError::Negative)) + ); + } + + #[test] + fn test_zero() { + assert_eq!( + parse_pos_nonzero("0"), + Err(ParsePosNonzeroError::Creation(CreationError::Zero)) + ); + } + + #[test] + fn test_positive() { + let x = PositiveNonzeroInteger::new(42); + assert!(x.is_ok()); + assert_eq!(parse_pos_nonzero("42"), Ok(x.unwrap())); + } +} diff --git a/functions/README.md b/functions/README.md new file mode 100644 index 0000000..6662d0d --- /dev/null +++ b/functions/README.md @@ -0,0 +1,8 @@ +# Functions + +Here, you'll learn how to write functions and how the Rust compiler can help you debug errors even +in more complex code. + +## Further information + +- [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html) diff --git a/functions/functions1.rs b/functions/functions1.rs new file mode 100644 index 0000000..2bb334f --- /dev/null +++ b/functions/functions1.rs @@ -0,0 +1,14 @@ +// functions1.rs +// +// Execute `rustlings hint functions1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE +// +fn call_me() { + 0; +} + +fn main() { + call_me(); +} diff --git a/functions/functions2.rs b/functions/functions2.rs new file mode 100644 index 0000000..73d1697 --- /dev/null +++ b/functions/functions2.rs @@ -0,0 +1,16 @@ +// functions2.rs +// +// Execute `rustlings hint functions2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + call_me(3); +} + +fn call_me(num: u8) { + for i in 0..num { + println!("Ring! Call number {}", i + 1); + } +} diff --git a/functions/functions3.rs b/functions/functions3.rs new file mode 100644 index 0000000..7d88c1b --- /dev/null +++ b/functions/functions3.rs @@ -0,0 +1,16 @@ +// functions3.rs +// +// Execute `rustlings hint functions3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + call_me(3); +} + +fn call_me(num: u32) { + for i in 0..num { + println!("Ring! Call number {}", i + 1); + } +} diff --git a/functions/functions4.rs b/functions/functions4.rs new file mode 100644 index 0000000..ab1239a --- /dev/null +++ b/functions/functions4.rs @@ -0,0 +1,28 @@ +// functions4.rs +// +// This store is having a sale where if the price is an even number, you get 10 +// Rustbucks off, but if it's an odd number, it's 3 Rustbucks off. (Don't worry +// about the function bodies themselves, we're only interested in the signatures +// for now. If anything, this is a good way to peek ahead to future exercises!) +// +// Execute `rustlings hint functions4` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + let original_price = 51; + println!("Your sale price is {}", sale_price(original_price)); +} + +fn sale_price(price: i32) -> i32 { + if is_even(price) { + price - 10 + } else { + price - 3 + } +} + +fn is_even(num: i32) -> bool { + num % 2 == 0 +} diff --git a/functions/functions5.rs b/functions/functions5.rs new file mode 100644 index 0000000..38ed6f1 --- /dev/null +++ b/functions/functions5.rs @@ -0,0 +1,15 @@ +// functions5.rs +// +// Execute `rustlings hint functions5` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + let answer = square(3); + println!("The square of 3 is {}", answer); +} + +fn square(num: i32) -> i32 { + num * num +} diff --git a/generics/README.md b/generics/README.md new file mode 100644 index 0000000..de46d50 --- /dev/null +++ b/generics/README.md @@ -0,0 +1,11 @@ +# Generics + +Generics is the topic of generalizing types and functionalities to broader cases. +This is extremely useful for reducing code duplication in many ways, but can call for rather involving syntax. +Namely, being generic requires taking great care to specify over which types a generic type is actually considered valid. +The simplest and most common use of generics is for type parameters. + +## Further information + +- [Generic Data Types](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html) +- [Bounds](https://doc.rust-lang.org/rust-by-example/generics/bounds.html) diff --git a/generics/generics1.rs b/generics/generics1.rs new file mode 100644 index 0000000..44af921 --- /dev/null +++ b/generics/generics1.rs @@ -0,0 +1,14 @@ +// generics1.rs +// +// This shopping list program isn't compiling! Use your knowledge of generics to +// fix it. +// +// Execute `rustlings hint generics1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + let mut shopping_list: Vec<&str> = Vec::new(); + shopping_list.push("milk"); +} diff --git a/generics/generics2.rs b/generics/generics2.rs new file mode 100644 index 0000000..5b23181 --- /dev/null +++ b/generics/generics2.rs @@ -0,0 +1,34 @@ +// generics2.rs +// +// This powerful wrapper provides the ability to store a positive integer value. +// Rewrite it using generics so that it supports wrapping ANY type. +// +// Execute `rustlings hint generics2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +struct Wrapper { + value: T, +} + +impl Wrapper { + pub fn new(value: T) -> Self { + Wrapper { value } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn store_u32_in_wrapper() { + assert_eq!(Wrapper::new(42).value, 42); + } + + #[test] + fn store_str_in_wrapper() { + assert_eq!(Wrapper::new("Foo").value, "Foo"); + } +} diff --git a/hashmaps/README.md b/hashmaps/README.md new file mode 100644 index 0000000..80ec144 --- /dev/null +++ b/hashmaps/README.md @@ -0,0 +1,12 @@ +# Hashmaps + +A *hash map* allows you to associate a value with a particular key. +You may also know this by the names [*unordered map* in C++](https://en.cppreference.com/w/cpp/container/unordered_map), +[*dictionary* in Python](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) or an *associative array* in other languages. + +This is the other data structure that we've been talking about before, when +talking about Vecs. + +## Further information + +- [Storing Keys with Associated Values in Hash Maps](https://doc.rust-lang.org/book/ch08-03-hash-maps.html) diff --git a/hashmaps/hashmaps1.rs b/hashmaps/hashmaps1.rs new file mode 100644 index 0000000..d1cf105 --- /dev/null +++ b/hashmaps/hashmaps1.rs @@ -0,0 +1,49 @@ +// hashmaps1.rs +// +// A basket of fruits in the form of a hash map needs to be defined. The key +// represents the name of the fruit and the value represents how many of that +// particular fruit is in the basket. You have to put at least three different +// types of fruits (e.g apple, banana, mango) in the basket and the total count +// of all the fruits should be at least five. +// +// Make me compile and pass the tests! +// +// Execute `rustlings hint hashmaps1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +use std::collections::HashMap; + +fn fruit_basket() -> HashMap { + let mut basket = HashMap::::new(); + + // Two bananas are already given for you :) + basket.insert(String::from("banana"), 2); + basket.insert(String::from("apple"), 2); + basket.insert(String::from("avocado"), 2); + basket.insert(String::from("banana"), 2); + basket.insert(String::from("banana"), 2); + basket.insert(String::from("banana"), 2); + + // TODO: Put more fruits in your basket here. + + basket +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn at_least_three_types_of_fruits() { + let basket = fruit_basket(); + assert!(basket.len() >= 3); + } + + #[test] + fn at_least_five_fruits() { + let basket = fruit_basket(); + assert!(basket.values().sum::() >= 5); + } +} diff --git a/hashmaps/hashmaps2.rs b/hashmaps/hashmaps2.rs new file mode 100644 index 0000000..5bb2991 --- /dev/null +++ b/hashmaps/hashmaps2.rs @@ -0,0 +1,96 @@ +// hashmaps2.rs +// +// We're collecting different fruits to bake a delicious fruit cake. For this, +// we have a basket, which we'll represent in the form of a hash map. The key +// represents the name of each fruit we collect and the value represents how +// many of that particular fruit we have collected. Three types of fruits - +// Apple (4), Mango (2) and Lychee (5) are already in the basket hash map. You +// must add fruit to the basket so that there is at least one of each kind and +// more than 11 in total - we have a lot of mouths to feed. You are not allowed +// to insert any more of these fruits! +// +// Make me pass the tests! +// +// Execute `rustlings hint hashmaps2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +use std::collections::HashMap; + +#[derive(Hash, PartialEq, Eq)] +enum Fruit { + Apple, + Banana, + Mango, + Lychee, + Pineapple, +} + +fn fruit_basket(basket: &mut HashMap) { + let fruit_kinds = vec![ + Fruit::Apple, + Fruit::Banana, + Fruit::Mango, + Fruit::Lychee, + Fruit::Pineapple, + ]; + + for fruit in fruit_kinds { + // TODO: Insert new fruits if they are not already present in the + // basket. Note that you are not allowed to put any type of fruit that's + // already present! + if !basket.contains_key(&fruit) { + basket.insert(fruit, 2); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // Don't modify this function! + fn get_fruit_basket() -> HashMap { + let mut basket = HashMap::::new(); + basket.insert(Fruit::Apple, 4); + basket.insert(Fruit::Mango, 2); + basket.insert(Fruit::Lychee, 5); + + basket + } + + #[test] + fn test_given_fruits_are_not_modified() { + let mut basket = get_fruit_basket(); + fruit_basket(&mut basket); + assert_eq!(*basket.get(&Fruit::Apple).unwrap(), 4); + assert_eq!(*basket.get(&Fruit::Mango).unwrap(), 2); + assert_eq!(*basket.get(&Fruit::Lychee).unwrap(), 5); + } + + #[test] + fn at_least_five_types_of_fruits() { + let mut basket = get_fruit_basket(); + fruit_basket(&mut basket); + let count_fruit_kinds = basket.len(); + assert!(count_fruit_kinds >= 5); + } + + #[test] + fn greater_than_eleven_fruits() { + let mut basket = get_fruit_basket(); + fruit_basket(&mut basket); + let count = basket.values().sum::(); + assert!(count > 11); + } + + #[test] + fn all_fruit_types_in_basket() { + let mut basket = get_fruit_basket(); + fruit_basket(&mut basket); + for amount in basket.values() { + assert_ne!(amount, &0); + } + } +} diff --git a/hashmaps/hashmaps3.rs b/hashmaps/hashmaps3.rs new file mode 100644 index 0000000..6c7139e --- /dev/null +++ b/hashmaps/hashmaps3.rs @@ -0,0 +1,106 @@ +// hashmaps3.rs +// +// A list of scores (one per line) of a soccer match is given. Each line is of +// the form : ",,," +// Example: England,France,4,2 (England scored 4 goals, France 2). +// +// You have to build a scores table containing the name of the team, goals the +// team scored, and goals the team conceded. One approach to build the scores +// table is to use a Hashmap. The solution is partially written to use a +// Hashmap, complete it to pass the test. +// +// Make me pass the tests! +// +// Execute `rustlings hint hashmaps3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +use std::collections::HashMap; + +// A structure to store the goal details of a team. +struct Team { + goals_scored: u8, + goals_conceded: u8, +} + +fn build_scores_table(results: String) -> HashMap { + // The name of the team is the key and its associated struct is the value. + let mut scores: HashMap = HashMap::new(); + + for r in results.lines() { + let v: Vec<&str> = r.split(',').collect(); + let team_1_name = v[0].to_string(); + let team_1_score: u8 = v[2].parse().unwrap(); + let team_2_name = v[1].to_string(); + let team_2_score: u8 = v[3].parse().unwrap(); + // TODO: Populate the scores table with details extracted from the + // current line. Keep in mind that goals scored by team_1 + // will be the number of goals conceded from team_2, and similarly + // goals scored by team_2 will be the number of goals conceded by + // team_1. + + let team_1 = scores.entry(team_1_name.clone()).or_insert(Team { + goals_scored: 0, + goals_conceded: 0, + }); + + *team_1 = Team { + goals_scored: team_1.goals_scored + team_1_score, + goals_conceded: team_1.goals_conceded + team_2_score, + }; + + let team_2 = scores.entry(team_2_name.clone()).or_insert(Team { + goals_scored: 0, + goals_conceded: 0, + }); + + *team_2 = Team { + goals_scored: team_2.goals_scored + team_2_score, + goals_conceded: team_2.goals_conceded + team_1_score, + }; + } + scores +} + +#[cfg(test)] +mod tests { + use super::*; + + fn get_results() -> String { + let results = "".to_string() + + "England,France,4,2\n" + + "France,Italy,3,1\n" + + "Poland,Spain,2,0\n" + + "Germany,England,2,1\n"; + results + } + + #[test] + fn build_scores() { + let scores = build_scores_table(get_results()); + + let mut keys: Vec<&String> = scores.keys().collect(); + keys.sort(); + assert_eq!( + keys, + vec!["England", "France", "Germany", "Italy", "Poland", "Spain"] + ); + } + + #[test] + fn validate_team_score_1() { + let scores = build_scores_table(get_results()); + let team = scores.get("England").unwrap(); + assert_eq!(team.goals_scored, 5); + assert_eq!(team.goals_conceded, 4); + } + + #[test] + fn validate_team_score_2() { + let scores = build_scores_table(get_results()); + let team = scores.get("Spain").unwrap(); + assert_eq!(team.goals_scored, 0); + assert_eq!(team.goals_conceded, 2); + } +} diff --git a/if/README.md b/if/README.md new file mode 100644 index 0000000..b52c392 --- /dev/null +++ b/if/README.md @@ -0,0 +1,7 @@ +# If + +`if`, the most basic (but still surprisingly versatile!) type of control flow, is what you'll learn here. + +## Further information + +- [Control Flow - if expressions](https://doc.rust-lang.org/book/ch03-05-control-flow.html#if-expressions) diff --git a/if/if1.rs b/if/if1.rs new file mode 100644 index 0000000..d705efe --- /dev/null +++ b/if/if1.rs @@ -0,0 +1,38 @@ +// if1.rs +// +// Execute `rustlings hint if1` or use the `hint` watch subcommand for a hint. + +// I AM DONE + +pub fn bigger(a: i32, b: i32) -> i32 { + // Complete this function to return the bigger number! + // Do not use: + // - another function call + // - additional variables + if a > b { + a + } else { + b + } +} + +// Don't mind this for now :) +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ten_is_bigger_than_eight() { + assert_eq!(10, bigger(10, 8)); + } + + #[test] + fn fortytwo_is_bigger_than_thirtytwo() { + assert_eq!(42, bigger(32, 42)); + } + + #[test] + fn equal_numbers() { + assert_eq!(42, bigger(42, 42)); + } +} diff --git a/if/if2.rs b/if/if2.rs new file mode 100644 index 0000000..4cff471 --- /dev/null +++ b/if/if2.rs @@ -0,0 +1,39 @@ +// if2.rs +// +// Step 1: Make me compile! +// Step 2: Get the bar_for_fuzz and default_to_baz tests passing! +// +// Execute `rustlings hint if2` or use the `hint` watch subcommand for a hint. + +// I AM DONE + +pub fn foo_if_fizz(fizzish: &str) -> &str { + if fizzish == "fizz" { + "foo" + } else if fizzish == "fuzz" { + "bar" + } else { + "baz" + } +} + +// No test changes needed! +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn foo_for_fizz() { + assert_eq!(foo_if_fizz("fizz"), "foo") + } + + #[test] + fn bar_for_fuzz() { + assert_eq!(foo_if_fizz("fuzz"), "bar") + } + + #[test] + fn default_to_baz() { + assert_eq!(foo_if_fizz("literally anything"), "baz") + } +} diff --git a/if/if3.rs b/if/if3.rs new file mode 100644 index 0000000..fa13ed0 --- /dev/null +++ b/if/if3.rs @@ -0,0 +1,56 @@ +// if3.rs +// +// Execute `rustlings hint if3` or use the `hint` watch subcommand for a hint. + +// I AM DONE + +pub fn animal_habitat(animal: &str) -> &'static str { + let identifier = if animal == "crab" { + 1 + } else if animal == "gopher" { + 2 + } else if animal == "snake" { + 3 + } else { + 4 + }; + + // DO NOT CHANGE THIS STATEMENT BELOW + let habitat = if identifier == 1 { + "Beach" + } else if identifier == 2 { + "Burrow" + } else if identifier == 3 { + "Desert" + } else { + "Unknown" + }; + + habitat +} + +// No test changes needed. +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn gopher_lives_in_burrow() { + assert_eq!(animal_habitat("gopher"), "Burrow") + } + + #[test] + fn snake_lives_in_desert() { + assert_eq!(animal_habitat("snake"), "Desert") + } + + #[test] + fn crab_lives_on_beach() { + assert_eq!(animal_habitat("crab"), "Beach") + } + + #[test] + fn unknown_animal() { + assert_eq!(animal_habitat("dinosaur"), "Unknown") + } +} diff --git a/intro/README.md b/intro/README.md new file mode 100644 index 0000000..d32e4a8 --- /dev/null +++ b/intro/README.md @@ -0,0 +1,8 @@ +# Intro + +Rust uses the `print!` and `println!` macros to print text to the console. + +## Further information + +- [Hello World](https://doc.rust-lang.org/rust-by-example/hello.html) +- [Formatted print](https://doc.rust-lang.org/rust-by-example/hello/print.html) diff --git a/intro/intro1.rs b/intro/intro1.rs new file mode 100644 index 0000000..b15a6ca --- /dev/null +++ b/intro/intro1.rs @@ -0,0 +1,41 @@ +// intro1.rs +// +// About this `I AM NOT DONE` thing: +// We sometimes encourage you to keep trying things on a given exercise, even +// after you already figured it out. If you got everything working and feel +// ready for the next exercise, remove the `I AM NOT DONE` comment below. +// +// If you're running this using `rustlings watch`: The exercise file will be +// reloaded when you change one of the lines below! Try adding a `println!` +// line, or try changing what it outputs in your terminal. Try removing a +// semicolon and see what happens! +// +// Execute `rustlings hint intro1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + println!("Hello and"); + println!(r#" welcome to... "#); + println!(r#" _ _ _ "#); + println!(r#" _ __ _ _ ___| |_| (_)_ __ __ _ ___ "#); + println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#); + println!(r#" | | | |_| \__ \ |_| | | | | | (_| \__ \ "#); + println!(r#" |_| \__,_|___/\__|_|_|_| |_|\__, |___/ "#); + println!(r#" |___/ "#); + println!(); + println!("This exercise compiles successfully. The remaining exercises contain a compiler"); + println!("or logic error. The central concept behind Rustlings is to fix these errors and"); + println!("solve the exercises. Good luck!"); + println!(); + println!("The source for this exercise is in `exercises/intro/intro1.rs`. Have a look!"); + println!( + "Going forward, the source of the exercises will always be in the success/failure output." + ); + println!(); + println!( + "If you want to use rust-analyzer, Rust's LSP implementation, make sure your editor is set" + ); + println!("up, and then run `rustlings lsp` before continuing.") +} diff --git a/intro/intro2.rs b/intro/intro2.rs new file mode 100644 index 0000000..ca38297 --- /dev/null +++ b/intro/intro2.rs @@ -0,0 +1,12 @@ +// intro2.rs +// +// Make the code print a greeting to the world. +// +// Execute `rustlings hint intro2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + println!("Hello World!"); +} diff --git a/iterators/README.md b/iterators/README.md new file mode 100644 index 0000000..0e8b671 --- /dev/null +++ b/iterators/README.md @@ -0,0 +1,8 @@ +# Iterators + +This section will teach you about Iterators. + +## Further information + +- [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html) +- [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/) diff --git a/iterators/iterators1.rs b/iterators/iterators1.rs new file mode 100644 index 0000000..8303a08 --- /dev/null +++ b/iterators/iterators1.rs @@ -0,0 +1,26 @@ +// iterators1.rs +// +// When performing operations on elements within a collection, iterators are +// essential. This module helps you get familiar with the structure of using an +// iterator and how to go through elements within an iterable collection. +// +// Make me compile by filling in the `???`s +// +// Execute `rustlings hint iterators1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +#[test] +fn main() { + let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"]; + + let mut my_iterable_fav_fruits = my_fav_fruits.iter(); // TODO: Step 1 + + assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana")); + assert_eq!(my_iterable_fav_fruits.next(), Some(&"custard apple")); // TODO: Step 2 + assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado")); + assert_eq!(my_iterable_fav_fruits.next(), Some(&"peach")); // TODO: Step 3 + assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry")); + assert_eq!(my_iterable_fav_fruits.next(), None); // TODO: Step 4 +} diff --git a/iterators/iterators2.rs b/iterators/iterators2.rs new file mode 100644 index 0000000..60b3234 --- /dev/null +++ b/iterators/iterators2.rs @@ -0,0 +1,71 @@ +// iterators2.rs +// +// In this exercise, you'll learn some of the unique advantages that iterators +// can offer. Follow the steps to complete the exercise. +// +// Execute `rustlings hint iterators2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +// Step 1. +// Complete the `capitalize_first` function. +// "hello" -> "Hello" +pub fn capitalize_first(input: &str) -> String { + let mut c = input.chars(); + + match c.next() { + None => String::new(), + Some(first) => first.to_uppercase().to_string() + &input[1..], + } +} + +// Step 2. +// Apply the `capitalize_first` function to a slice of string slices. +// Return a vector of strings. +// ["hello", "world"] -> ["Hello", "World"] +pub fn capitalize_words_vector(words: &[&str]) -> Vec { + words + .iter() + .map(|word| capitalize_first(word)) + .collect::>() +} + +// Step 3. +// Apply the `capitalize_first` function again to a slice of string slices. +// Return a single string. +// ["hello", " ", "world"] -> "Hello World" +pub fn capitalize_words_string(words: &[&str]) -> String { + words + .iter() + .map(|word| capitalize_first(word)) + .collect::>() + .join("") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_success() { + assert_eq!(capitalize_first("hello"), "Hello"); + } + + #[test] + fn test_empty() { + assert_eq!(capitalize_first(""), ""); + } + + #[test] + fn test_iterate_string_vec() { + let words = vec!["hello", "world"]; + assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]); + } + + #[test] + fn test_iterate_into_string() { + let words = vec!["hello", " ", "world"]; + assert_eq!(capitalize_words_string(&words), "Hello World"); + } +} diff --git a/iterators/iterators3.rs b/iterators/iterators3.rs new file mode 100644 index 0000000..dc0ff3c --- /dev/null +++ b/iterators/iterators3.rs @@ -0,0 +1,97 @@ +// iterators3.rs +// +// This is a bigger exercise than most of the others! You can do it! Here is +// your mission, should you choose to accept it: +// 1. Complete the divide function to get the first four tests to pass. +// 2. Get the remaining tests to pass by completing the result_with_list and +// list_of_results functions. +// +// Execute `rustlings hint iterators3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +#[derive(Debug, PartialEq, Eq)] +pub enum DivisionError { + NotDivisible(NotDivisibleError), + DivideByZero, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct NotDivisibleError { + dividend: i32, + divisor: i32, +} + +// Calculate `a` divided by `b` if `a` is evenly divisible by `b`. +// Otherwise, return a suitable error. +pub fn divide(a: i32, b: i32) -> Result { + match (a, b) { + (_, b) if b == 0 => Err(DivisionError::DivideByZero), + (a, b) if a % b != 0 => Err(DivisionError::NotDivisible(NotDivisibleError { + dividend: a, + divisor: b, + })), + (a, b) => Ok(a / b), + } +} + +// Complete the function and return a value of the correct type so the test +// passes. +// Desired output: Ok([1, 11, 1426, 3]) +fn result_with_list() -> Result, DivisionError> { + let numbers = vec![27, 297, 38502, 81]; + numbers.into_iter().map(|n| divide(n, 27)).collect() +} + +// Complete the function and return a value of the correct type so the test +// passes. +// Desired output: [Ok(1), Ok(11), Ok(1426), Ok(3)] +fn list_of_results() -> Vec> { + let numbers = vec![27, 297, 38502, 81]; + numbers.into_iter().map(|n| divide(n, 27)).collect() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_success() { + assert_eq!(divide(81, 9), Ok(9)); + } + + #[test] + fn test_not_divisible() { + assert_eq!( + divide(81, 6), + Err(DivisionError::NotDivisible(NotDivisibleError { + dividend: 81, + divisor: 6 + })) + ); + } + + #[test] + fn test_divide_by_0() { + assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero)); + } + + #[test] + fn test_divide_0_by_something() { + assert_eq!(divide(0, 81), Ok(0)); + } + + #[test] + fn test_result_with_list() { + assert_eq!(format!("{:?}", result_with_list()), "Ok([1, 11, 1426, 3])"); + } + + #[test] + fn test_list_of_results() { + assert_eq!( + format!("{:?}", list_of_results()), + "[Ok(1), Ok(11), Ok(1426), Ok(3)]" + ); + } +} diff --git a/iterators/iterators4.rs b/iterators/iterators4.rs new file mode 100644 index 0000000..4e3de61 --- /dev/null +++ b/iterators/iterators4.rs @@ -0,0 +1,46 @@ +// iterators4.rs +// +// Execute `rustlings hint iterators4` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +pub fn factorial(num: u64) -> u64 { + // Complete this function to return the factorial of num + // Do not use: + // - return + // Try not to use: + // - imperative style loops (for, while) + // - additional variables + // For an extra challenge, don't use: + // - recursion + // Execute `rustlings hint iterators4` for hints. + (1..=num) + .collect::>() + .iter() + .rfold(1, |acc, &x| acc * x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn factorial_of_0() { + assert_eq!(1, factorial(0)); + } + + #[test] + fn factorial_of_1() { + assert_eq!(1, factorial(1)); + } + #[test] + fn factorial_of_2() { + assert_eq!(2, factorial(2)); + } + + #[test] + fn factorial_of_4() { + assert_eq!(24, factorial(4)); + } +} diff --git a/iterators/iterators5.rs b/iterators/iterators5.rs new file mode 100644 index 0000000..cc2c97d --- /dev/null +++ b/iterators/iterators5.rs @@ -0,0 +1,165 @@ +// iterators5.rs +// +// Let's define a simple model to track Rustlings exercise progress. Progress +// will be modelled using a hash map. The name of the exercise is the key and +// the progress is the value. Two counting functions were created to count the +// number of exercises with a given progress. Recreate this counting +// functionality using iterators. Try not to use imperative loops (for, while). +// Only the two iterator methods (count_iterator and count_collection_iterator) +// need to be modified. +// +// Execute `rustlings hint iterators5` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +use std::collections::HashMap; + +#[derive(Clone, Copy, PartialEq, Eq)] +enum Progress { + None, + Some, + Complete, +} + +fn count_for(map: &HashMap, value: Progress) -> usize { + let mut count = 0; + for val in map.values() { + if val == &value { + count += 1; + } + } + count +} + +fn count_iterator(map: &HashMap, value: Progress) -> usize { + // map is a hashmap with String keys and Progress values. + // map = { "variables1": Complete, "from_str": None, ... } + map.values() + .into_iter() + .filter(|&curr_val| *curr_val == value) + .collect::>() + .len() +} + +fn count_collection_for(collection: &[HashMap], value: Progress) -> usize { + let mut count = 0; + for map in collection { + for val in map.values() { + if val == &value { + count += 1; + } + } + } + count +} + +fn count_collection_iterator(collection: &[HashMap], value: Progress) -> usize { + // collection is a slice of hashmaps. + // collection = [{ "variables1": Complete, "from_str": None, ... }, + // { "variables2": Complete, ... }, ... ] + collection + .iter() + .flatten() + .filter(|(_, &curr_val)| curr_val == value) + .collect::>() + .len() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn count_complete() { + let map = get_map(); + assert_eq!(3, count_iterator(&map, Progress::Complete)); + } + + #[test] + fn count_some() { + let map = get_map(); + assert_eq!(1, count_iterator(&map, Progress::Some)); + } + + #[test] + fn count_none() { + let map = get_map(); + assert_eq!(2, count_iterator(&map, Progress::None)); + } + + #[test] + fn count_complete_equals_for() { + let map = get_map(); + let progress_states = vec![Progress::Complete, Progress::Some, Progress::None]; + for progress_state in progress_states { + assert_eq!( + count_for(&map, progress_state), + count_iterator(&map, progress_state) + ); + } + } + + #[test] + fn count_collection_complete() { + let collection = get_vec_map(); + assert_eq!( + 6, + count_collection_iterator(&collection, Progress::Complete) + ); + } + + #[test] + fn count_collection_some() { + let collection = get_vec_map(); + assert_eq!(1, count_collection_iterator(&collection, Progress::Some)); + } + + #[test] + fn count_collection_none() { + let collection = get_vec_map(); + assert_eq!(4, count_collection_iterator(&collection, Progress::None)); + } + + #[test] + fn count_collection_equals_for() { + let progress_states = vec![Progress::Complete, Progress::Some, Progress::None]; + let collection = get_vec_map(); + + for progress_state in progress_states { + assert_eq!( + count_collection_for(&collection, progress_state), + count_collection_iterator(&collection, progress_state) + ); + } + } + + fn get_map() -> HashMap { + use Progress::*; + + let mut map = HashMap::new(); + map.insert(String::from("variables1"), Complete); + map.insert(String::from("functions1"), Complete); + map.insert(String::from("hashmap1"), Complete); + map.insert(String::from("arc1"), Some); + map.insert(String::from("as_ref_mut"), None); + map.insert(String::from("from_str"), None); + + map + } + + fn get_vec_map() -> Vec> { + use Progress::*; + + let map = get_map(); + + let mut other = HashMap::new(); + other.insert(String::from("variables2"), Complete); + other.insert(String::from("functions2"), Complete); + other.insert(String::from("if1"), Complete); + other.insert(String::from("from_into"), None); + other.insert(String::from("try_from_into"), None); + + vec![map, other] + } +} diff --git a/lifetimes/README.md b/lifetimes/README.md new file mode 100644 index 0000000..91373f7 --- /dev/null +++ b/lifetimes/README.md @@ -0,0 +1,22 @@ +# Lifetimes + +Lifetimes tell the compiler how to check whether references live long +enough to be valid in any given situation. For example lifetimes say +"make sure parameter 'a' lives as long as parameter 'b' so that the return +value is valid". + +They are only necessary on borrows, i.e. references, +since copied parameters or moves are owned in their scope and cannot +be referenced outside. Lifetimes mean that calling code of e.g. functions +can be checked to make sure their arguments are valid. Lifetimes are +restrictive of their callers. + +If you'd like to learn more about lifetime annotations, the +[lifetimekata](https://tfpk.github.io/lifetimekata/) project +has a similar style of exercises to Rustlings, but is all about +learning to write lifetime annotations. + +## Further information + +- [Lifetimes (in Rust By Example)](https://doc.rust-lang.org/stable/rust-by-example/scope/lifetime.html) +- [Validating References with Lifetimes](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html) diff --git a/lifetimes/lifetimes1.rs b/lifetimes/lifetimes1.rs new file mode 100644 index 0000000..9167dc6 --- /dev/null +++ b/lifetimes/lifetimes1.rs @@ -0,0 +1,27 @@ +// lifetimes1.rs +// +// The Rust compiler needs to know how to check whether supplied references are +// valid, so that it can let the programmer know if a reference is at risk of +// going out of scope before it is used. Remember, references are borrows and do +// not own their own data. What if their owner goes out of scope? +// +// Execute `rustlings hint lifetimes1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { + if x.len() > y.len() { + x + } else { + y + } +} + +fn main() { + let string1 = String::from("abcd"); + let string2 = "xyz"; + + let result = longest(string1.as_str(), string2); + println!("The longest string is '{}'", result); +} diff --git a/lifetimes/lifetimes2.rs b/lifetimes/lifetimes2.rs new file mode 100644 index 0000000..d09d442 --- /dev/null +++ b/lifetimes/lifetimes2.rs @@ -0,0 +1,27 @@ +// lifetimes2.rs +// +// So if the compiler is just validating the references passed to the annotated +// parameters and the return type, what do we need to change? +// +// Execute `rustlings hint lifetimes2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { + if x.len() > y.len() { + x + } else { + y + } +} + +fn main() { + let string1 = String::from("long string is long"); + let result; + { + let string2 = String::from("xyz"); + result = longest(string1.as_str(), string2.as_str()); + println!("The longest string is '{}'", result); + } +} diff --git a/lifetimes/lifetimes3.rs b/lifetimes/lifetimes3.rs new file mode 100644 index 0000000..1b002ca --- /dev/null +++ b/lifetimes/lifetimes3.rs @@ -0,0 +1,24 @@ +// lifetimes3.rs +// +// Lifetimes are also needed when structs hold references. +// +// Execute `rustlings hint lifetimes3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +struct Book<'a> { + author: &'a str, + title: &'a str, +} + +fn main() { + let name = String::from("Jill Smith"); + let title = String::from("Fish Flying"); + let book = Book { + author: &name, + title: &title, + }; + + println!("{} by {}", book.title, book.author); +} diff --git a/macros/README.md b/macros/README.md new file mode 100644 index 0000000..337816d --- /dev/null +++ b/macros/README.md @@ -0,0 +1,14 @@ +# Macros + +Rust's macro system is very powerful, but also kind of difficult to wrap your +head around. We're not going to teach you how to write your own fully-featured +macros. Instead, we'll show you how to use and create them. + +If you'd like to learn more about writing your own macros, the +[macrokata](https://github.com/tfpk/macrokata) project has a similar style +of exercises to Rustlings, but is all about learning to write Macros. + +## Further information + +- [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html) +- [The Little Book of Rust Macros](https://veykril.github.io/tlborm/) diff --git a/macros/macros1.rs b/macros/macros1.rs new file mode 100644 index 0000000..ff5d979 --- /dev/null +++ b/macros/macros1.rs @@ -0,0 +1,16 @@ +// macros1.rs +// +// Execute `rustlings hint macros1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +macro_rules! my_macro { + () => { + println!("Check out my macro!"); + }; +} + +fn main() { + my_macro!(); +} diff --git a/macros/macros2.rs b/macros/macros2.rs new file mode 100644 index 0000000..60614a3 --- /dev/null +++ b/macros/macros2.rs @@ -0,0 +1,16 @@ +// macros2.rs +// +// Execute `rustlings hint macros2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +macro_rules! my_macro { + () => { + println!("Check out my macro!"); + }; +} + +fn main() { + my_macro!(); +} diff --git a/macros/macros3.rs b/macros/macros3.rs new file mode 100644 index 0000000..c6f0ae8 --- /dev/null +++ b/macros/macros3.rs @@ -0,0 +1,21 @@ +// macros3.rs +// +// Make me compile, without taking the macro out of the module! +// +// Execute `rustlings hint macros3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +#[macro_use] +mod macros { + macro_rules! my_macro { + () => { + println!("Check out my macro!"); + }; + } +} + +fn main() { + my_macro!(); +} diff --git a/macros/macros4.rs b/macros/macros4.rs new file mode 100644 index 0000000..00ad5a7 --- /dev/null +++ b/macros/macros4.rs @@ -0,0 +1,21 @@ +// macros4.rs +// +// Execute `rustlings hint macros4` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +#[rustfmt::skip] +macro_rules! my_macro { + () => { + println!("Check out my macro!"); + }; + ($val:expr) => { + println!("Look at this other macro: {}", $val); + } +} + +fn main() { + my_macro!(); + my_macro!(7777); +} diff --git a/modules/README.md b/modules/README.md new file mode 100644 index 0000000..3dc8a48 --- /dev/null +++ b/modules/README.md @@ -0,0 +1,7 @@ +# Modules + +In this section we'll give you an introduction to Rust's module system. + +## Further information + +- [The Module System](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html) diff --git a/modules/modules1.rs b/modules/modules1.rs new file mode 100644 index 0000000..83815a0 --- /dev/null +++ b/modules/modules1.rs @@ -0,0 +1,22 @@ +// modules1.rs +// +// Execute `rustlings hint modules1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +mod sausage_factory { + // Don't let anybody outside of this module see this! + fn get_secret_recipe() -> String { + String::from("Ginger") + } + + pub fn make_sausage() { + get_secret_recipe(); + println!("sausage!"); + } +} + +fn main() { + sausage_factory::make_sausage(); +} diff --git a/modules/modules2.rs b/modules/modules2.rs new file mode 100644 index 0000000..59f719b --- /dev/null +++ b/modules/modules2.rs @@ -0,0 +1,34 @@ +// modules2.rs +// +// You can bring module paths into scopes and provide new names for them with +// the 'use' and 'as' keywords. Fix these 'use' statements to make the code +// compile. +// +// Execute `rustlings hint modules2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +mod delicious_snacks { + // TODO: Fix these use statements + pub use self::fruits::PEAR as fruit; + pub use self::veggies::CUCUMBER as veggie; + + mod fruits { + pub const PEAR: &'static str = "Pear"; + pub const APPLE: &'static str = "Apple"; + } + + mod veggies { + pub const CUCUMBER: &'static str = "Cucumber"; + pub const CARROT: &'static str = "Carrot"; + } +} + +fn main() { + println!( + "favorite snacks: {} and {}", + delicious_snacks::fruit, + delicious_snacks::veggie + ); +} diff --git a/modules/modules3.rs b/modules/modules3.rs new file mode 100644 index 0000000..34a1bd0 --- /dev/null +++ b/modules/modules3.rs @@ -0,0 +1,21 @@ +// modules3.rs +// +// You can use the 'use' keyword to bring module paths from modules from +// anywhere and especially from the Rust standard library into your scope. Bring +// SystemTime and UNIX_EPOCH from the std::time module. Bonus style points if +// you can do it with one line! +// +// Execute `rustlings hint modules3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +// TODO: Complete this use statement +use std::time::{SystemTime, UNIX_EPOCH}; + +fn main() { + match SystemTime::now().duration_since(UNIX_EPOCH) { + Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), + Err(_) => panic!("SystemTime before UNIX EPOCH!"), + } +} diff --git a/move_semantics/README.md b/move_semantics/README.md new file mode 100644 index 0000000..54ddd8e --- /dev/null +++ b/move_semantics/README.md @@ -0,0 +1,10 @@ +# Move Semantics + +These exercises are adapted from [pnkfelix](https://github.com/pnkfelix)'s [Rust Tutorial](https://pnkfelix.github.io/rust-examples-icfp2014/) -- Thank you Felix!!! + +## Further information + +For this section, the book links are especially important. + +- [Ownership](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html) +- [Reference and borrowing](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html) diff --git a/move_semantics/move_semantics1.rs b/move_semantics/move_semantics1.rs new file mode 100644 index 0000000..722ab1f --- /dev/null +++ b/move_semantics/move_semantics1.rs @@ -0,0 +1,23 @@ +// move_semantics1.rs +// +// Execute `rustlings hint move_semantics1` or use the `hint` watch subcommand +// for a hint. + +// I AM DONE + +#[test] +fn main() { + let vec0 = vec![22, 44, 66]; + + let vec1 = fill_vec(vec0); + + assert_eq!(vec1, vec![22, 44, 66, 88]); +} + +fn fill_vec(vec: Vec) -> Vec { + let mut vec = vec; + + vec.push(88); + + vec +} diff --git a/move_semantics/move_semantics2.rs b/move_semantics/move_semantics2.rs new file mode 100644 index 0000000..d615142 --- /dev/null +++ b/move_semantics/move_semantics2.rs @@ -0,0 +1,26 @@ +// move_semantics2.rs +// +// Make the test pass by finding a way to keep both Vecs separate! +// +// Execute `rustlings hint move_semantics2` or use the `hint` watch subcommand +// for a hint. + +// I AM DONE + +#[test] +fn main() { + let vec0 = vec![22, 44, 66]; + + let vec1 = fill_vec(&vec0); + + assert_eq!(vec0, vec![22, 44, 66]); + assert_eq!(vec1, vec![22, 44, 66, 88]); +} + +fn fill_vec(vec: &Vec) -> Vec { + let mut vec = vec.clone(); + + vec.push(88); + + vec +} diff --git a/move_semantics/move_semantics3.rs b/move_semantics/move_semantics3.rs new file mode 100644 index 0000000..18a533e --- /dev/null +++ b/move_semantics/move_semantics3.rs @@ -0,0 +1,24 @@ +// move_semantics3.rs +// +// Make me compile without adding new lines -- just changing existing lines! (no +// lines with multiple semicolons necessary!) +// +// Execute `rustlings hint move_semantics3` or use the `hint` watch subcommand +// for a hint. + +// I AM DONE + +#[test] +fn main() { + let vec0 = vec![22, 44, 66]; + + let vec1 = fill_vec(vec0); + + assert_eq!(vec1, vec![22, 44, 66, 88]); +} + +fn fill_vec(mut vec: Vec) -> Vec { + vec.push(88); + + vec +} diff --git a/move_semantics/move_semantics4.rs b/move_semantics/move_semantics4.rs new file mode 100644 index 0000000..80f9e3e --- /dev/null +++ b/move_semantics/move_semantics4.rs @@ -0,0 +1,29 @@ +// move_semantics4.rs +// +// Refactor this code so that instead of passing `vec0` into the `fill_vec` +// function, the Vector gets created in the function itself and passed back to +// the main function. +// +// Execute `rustlings hint move_semantics4` or use the `hint` watch subcommand +// for a hint. + +// I AM DONE + +#[test] +fn main() { + let vec0 = vec![22, 44, 66]; + + let vec1 = fill_vec(); + + assert_eq!(vec1, vec![22, 44, 66, 88]); +} + +// `fill_vec()` no longer takes `vec: Vec` as argument - don't change this! +fn fill_vec() -> Vec { + // Instead, let's create and fill the Vec in here - how do you do that? + let mut vec = vec![22, 44, 66]; + + vec.push(88); + + vec +} diff --git a/move_semantics/move_semantics5.rs b/move_semantics/move_semantics5.rs new file mode 100644 index 0000000..bf09f70 --- /dev/null +++ b/move_semantics/move_semantics5.rs @@ -0,0 +1,22 @@ +// move_semantics5.rs +// +// Make me compile only by reordering the lines in `main()`, but without adding, +// changing or removing any of them. +// +// Execute `rustlings hint move_semantics5` or use the `hint` watch subcommand +// for a hint. + +// I AM DONE + +#[test] +fn main() { + let mut x = 100; + + let y = &mut x; + *y += 100; + + let z = &mut x; + *z += 1000; + + assert_eq!(x, 1200); +} diff --git a/move_semantics/move_semantics6.rs b/move_semantics/move_semantics6.rs new file mode 100644 index 0000000..c95781e --- /dev/null +++ b/move_semantics/move_semantics6.rs @@ -0,0 +1,28 @@ +// move_semantics6.rs +// +// You can't change anything except adding or removing references. +// +// Execute `rustlings hint move_semantics6` or use the `hint` watch subcommand +// for a hint. + +// I AM DONE + +fn main() { + let data = "Rust is great!".to_string(); + + get_char(&data); + + string_uppercase(data); +} + +// Should not take ownership +fn get_char(data: &String) -> char { + data.chars().last().unwrap() +} + +// Should take ownership +fn string_uppercase(mut data: String) { + data = data.to_uppercase(); + + println!("{}", data); +} diff --git a/options/README.md b/options/README.md new file mode 100644 index 0000000..bdd3374 --- /dev/null +++ b/options/README.md @@ -0,0 +1,21 @@ +# Options + +Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not. +Option types are very common in Rust code, as they have a number of uses: + +- Initial values +- Return values for functions that are not defined over their entire input range (partial functions) +- Return value for otherwise reporting simple errors, where None is returned on error +- Optional struct fields +- Struct fields that can be loaned or "taken" +- Optional function arguments +- Nullable pointers +- Swapping things out of difficult situations + +## Further Information + +- [Option Enum Format](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-enum-definitions) +- [Option Module Documentation](https://doc.rust-lang.org/std/option/) +- [Option Enum Documentation](https://doc.rust-lang.org/std/option/enum.Option.html) +- [if let](https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html) +- [while let](https://doc.rust-lang.org/rust-by-example/flow_control/while_let.html) diff --git a/options/options1.rs b/options/options1.rs new file mode 100644 index 0000000..fc91dc3 --- /dev/null +++ b/options/options1.rs @@ -0,0 +1,43 @@ +// options1.rs +// +// Execute `rustlings hint options1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +// This function returns how much icecream there is left in the fridge. +// If it's before 10PM, there's 5 pieces left. At 10PM, someone eats them +// all, so there'll be no more left :( +fn maybe_icecream(time_of_day: u16) -> Option { + // We use the 24-hour system here, so 10PM is a value of 22 and 12AM is a + // value of 0 The Option output should gracefully handle cases where + // time_of_day > 23. + // TODO: Complete the function body - remember to return an Option! + match time_of_day { + 0..=21 => Some(5), + 22..=24 => Some(0), + _ => None, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn check_icecream() { + assert_eq!(maybe_icecream(9), Some(5)); + assert_eq!(maybe_icecream(10), Some(5)); + assert_eq!(maybe_icecream(23), Some(0)); + assert_eq!(maybe_icecream(22), Some(0)); + assert_eq!(maybe_icecream(25), None); + } + + #[test] + fn raw_value() { + // TODO: Fix this test. How do you get at the value contained in the + // Option? + let icecreams = maybe_icecream(12); + assert_eq!(icecreams.unwrap(), 5); + } +} diff --git a/options/options2.rs b/options/options2.rs new file mode 100644 index 0000000..d72fd92 --- /dev/null +++ b/options/options2.rs @@ -0,0 +1,42 @@ +// options2.rs +// +// Execute `rustlings hint options2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +#[cfg(test)] +mod tests { + #[test] + fn simple_option() { + let target = "rustlings"; + let optional_target = Some(target); + + // TODO: Make this an if let statement whose value is "Some" type + if let Some(word) = optional_target { + assert_eq!(word, target); + } + } + + #[test] + fn layered_option() { + let range = 10; + let mut optional_integers: Vec> = vec![None]; + + for i in 1..(range + 1) { + optional_integers.push(Some(i)); + } + + let mut cursor = range; + + // TODO: make this a while let statement - remember that vector.pop also + // adds another layer of Option. You can stack `Option`s into + // while let and if let. + while let Some(Some(integer)) = optional_integers.pop() { + assert_eq!(integer, cursor); + cursor -= 1; + } + + assert_eq!(cursor, 0); + } +} diff --git a/options/options3.rs b/options/options3.rs new file mode 100644 index 0000000..83b26a5 --- /dev/null +++ b/options/options3.rs @@ -0,0 +1,21 @@ +// options3.rs +// +// Execute `rustlings hint options3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +struct Point { + x: i32, + y: i32, +} + +fn main() { + let y: Option = Some(Point { x: 100, y: 200 }); + + match y { + Some(ref p) => println!("Co-ordinates are {},{} ", p.x, p.y), + _ => panic!("no match!"), + } + y; // Fix without deleting this line. +} diff --git a/primitive_types/README.md b/primitive_types/README.md new file mode 100644 index 0000000..cea69b0 --- /dev/null +++ b/primitive_types/README.md @@ -0,0 +1,9 @@ +# Primitive Types + +Rust has a couple of basic types that are directly implemented into the +compiler. In this section, we'll go through the most important ones. + +## Further information + +- [Data Types](https://doc.rust-lang.org/stable/book/ch03-02-data-types.html) +- [The Slice Type](https://doc.rust-lang.org/stable/book/ch04-03-slices.html) diff --git a/primitive_types/primitive_types1.rs b/primitive_types/primitive_types1.rs new file mode 100644 index 0000000..255b420 --- /dev/null +++ b/primitive_types/primitive_types1.rs @@ -0,0 +1,20 @@ +// primitive_types1.rs +// +// Fill in the rest of the line that has code missing! No hints, there's no +// tricks, just get used to typing these :) + +// I AM DONE + +fn main() { + // Booleans (`bool`) + + let is_morning: bool = true; + if is_morning { + println!("Good morning!"); + } + + let is_evening: bool = true; // Finish the rest of this line like the example! Or make it be false! + if is_evening { + println!("Good evening!"); + } +} diff --git a/primitive_types/primitive_types2.rs b/primitive_types/primitive_types2.rs new file mode 100644 index 0000000..ab803cb --- /dev/null +++ b/primitive_types/primitive_types2.rs @@ -0,0 +1,32 @@ +// primitive_types2.rs +// +// Fill in the rest of the line that has code missing! No hints, there's no +// tricks, just get used to typing these :) + +// I AM DONE + +fn main() { + // Characters (`char`) + + // Note the _single_ quotes, these are different from the double quotes + // you've been seeing around. + let my_first_initial: char = 'C'; + if my_first_initial.is_alphabetic() { + println!("Alphabetical!"); + } else if my_first_initial.is_numeric() { + println!("Numerical!"); + } else { + println!("Neither alphabetic nor numeric!"); + } + + let your_character: char = '1'; // Finish this line like the example! What's your favorite character? + // Try a letter, try a number, try a special character, try a character + // from a different language than your own, try an emoji! + if your_character.is_alphabetic() { + println!("Alphabetical!"); + } else if your_character.is_numeric() { + println!("Numerical!"); + } else { + println!("Neither alphabetic nor numeric!"); + } +} diff --git a/primitive_types/primitive_types3.rs b/primitive_types/primitive_types3.rs new file mode 100644 index 0000000..eb8b33e --- /dev/null +++ b/primitive_types/primitive_types3.rs @@ -0,0 +1,19 @@ +// primitive_types3.rs +// +// Create an array with at least 100 elements in it where the ??? is. +// +// Execute `rustlings hint primitive_types3` or use the `hint` watch subcommand +// for a hint. + +// I AM DONE + +fn main() { + let a: [u8; 101] = [0; 101]; + + if a.len() >= 100 { + println!("Wow, that's a big array!"); + } else { + println!("Meh, I eat arrays like that for breakfast."); + panic!("Array not big enough, more elements needed") + } +} diff --git a/primitive_types/primitive_types4.rs b/primitive_types/primitive_types4.rs new file mode 100644 index 0000000..192f7f0 --- /dev/null +++ b/primitive_types/primitive_types4.rs @@ -0,0 +1,17 @@ +// primitive_types4.rs +// +// Get a slice out of Array a where the ??? is so that the test passes. +// +// Execute `rustlings hint primitive_types4` or use the `hint` watch subcommand +// for a hint. + +// I AM DONE + +#[test] +fn slice_out_of_array() { + let a = [1, 2, 3, 4, 5]; + + let nice_slice = &a[1..4]; + + assert_eq!([2, 3, 4], nice_slice) +} diff --git a/primitive_types/primitive_types5.rs b/primitive_types/primitive_types5.rs new file mode 100644 index 0000000..25ab352 --- /dev/null +++ b/primitive_types/primitive_types5.rs @@ -0,0 +1,15 @@ +// primitive_types5.rs +// +// Destructure the `cat` tuple so that the println will work. +// +// Execute `rustlings hint primitive_types5` or use the `hint` watch subcommand +// for a hint. + +// I AM DONE + +fn main() { + let cat = ("Furry McFurson", 3.5); + let (name, age) = cat; + + println!("{} is {} years old.", name, age); +} diff --git a/primitive_types/primitive_types6.rs b/primitive_types/primitive_types6.rs new file mode 100644 index 0000000..b32233a --- /dev/null +++ b/primitive_types/primitive_types6.rs @@ -0,0 +1,18 @@ +// primitive_types6.rs +// +// Use a tuple index to access the second element of `numbers`. You can put the +// expression for the second element where ??? is so that the test passes. +// +// Execute `rustlings hint primitive_types6` or use the `hint` watch subcommand +// for a hint. + +// I AM DONE + +#[test] +fn indexing_tuple() { + let numbers = (1, 2, 3); + // Replace below ??? with the tuple indexing syntax. + let second = numbers.1; + + assert_eq!(2, second, "This is not the 2nd number in the tuple!") +} diff --git a/quiz1.rs b/quiz1.rs new file mode 100644 index 0000000..aa99ac6 --- /dev/null +++ b/quiz1.rs @@ -0,0 +1,38 @@ +// quiz1.rs +// +// This is a quiz for the following sections: +// - Variables +// - Functions +// - If +// +// Mary is buying apples. The price of an apple is calculated as follows: +// - An apple costs 2 rustbucks. +// - If Mary buys more than 40 apples, each apple only costs 1 rustbuck! +// Write a function that calculates the price of an order of apples given the +// quantity bought. +// +// No hints this time ;) + +// I AM DONE + +// Put your function here! +fn calculate_price_of_apples(apples_count: u8) -> u8 { + match apples_count { + 0..=40 => apples_count * 2, + _ => apples_count, + } +} + +// Don't modify this function! +#[test] +fn verify_test() { + let price1 = calculate_price_of_apples(35); + let price2 = calculate_price_of_apples(40); + let price3 = calculate_price_of_apples(41); + let price4 = calculate_price_of_apples(65); + + assert_eq!(70, price1); + assert_eq!(80, price2); + assert_eq!(41, price3); + assert_eq!(65, price4); +} diff --git a/quiz2.rs b/quiz2.rs new file mode 100644 index 0000000..82a642d --- /dev/null +++ b/quiz2.rs @@ -0,0 +1,72 @@ +// quiz2.rs +// +// This is a quiz for the following sections: +// - Strings +// - Vecs +// - Move semantics +// - Modules +// - Enums +// +// Let's build a little machine in the form of a function. As input, we're going +// to give a list of strings and commands. These commands determine what action +// is going to be applied to the string. It can either be: +// - Uppercase the string +// - Trim the string +// - Append "bar" to the string a specified amount of times +// The exact form of this will be: +// - The input is going to be a Vector of a 2-length tuple, +// the first element is the string, the second one is the command. +// - The output element is going to be a Vector of strings. +// +// No hints this time! + +// I AM DONE + +pub enum Command { + Uppercase, + Trim, + Append(usize), +} + +mod my_module { + use super::Command; + + // TODO: Complete the function signature! + pub fn transformer(input: Vec<(String, Command)>) -> Vec { + // TODO: Complete the output declaration! + let mut output: Vec = vec![]; + for (string, command) in input.iter() { + // TODO: Complete the function body. You can do it! + match command { + Command::Trim => output.push(string.trim().to_owned()), + Command::Uppercase => output.push(string.to_owned().to_uppercase()), + Command::Append(no_of_bar) => { + let append_str: String = "bar".repeat(*no_of_bar); + output.push(string.to_owned() + &append_str); + } + } + } + output + } +} + +#[cfg(test)] +mod tests { + // TODO: What do we need to import to have `transformer` in scope? + use super::Command; + use crate::my_module::transformer; + + #[test] + fn it_works() { + let output = transformer(vec![ + ("hello".into(), Command::Uppercase), + (" all roads lead to rome! ".into(), Command::Trim), + ("foo".into(), Command::Append(1)), + ("bar".into(), Command::Append(5)), + ]); + assert_eq!(output[0], "HELLO"); + assert_eq!(output[1], "all roads lead to rome!"); + assert_eq!(output[2], "foobar"); + assert_eq!(output[3], "barbarbarbarbarbar"); + } +} diff --git a/quiz3.rs b/quiz3.rs new file mode 100644 index 0000000..407852b --- /dev/null +++ b/quiz3.rs @@ -0,0 +1,68 @@ +// quiz3.rs +// +// This quiz tests: +// - Generics +// - Traits +// +// An imaginary magical school has a new report card generation system written +// in Rust! Currently the system only supports creating report cards where the +// student's grade is represented numerically (e.g. 1.0 -> 5.5). However, the +// school also issues alphabetical grades (A+ -> F-) and needs to be able to +// print both types of report card! +// +// Make the necessary code changes in the struct ReportCard and the impl block +// to support alphabetical report cards. Change the Grade in the second test to +// "A+" to show that your changes allow alphabetical grades. +// +// Execute `rustlings hint quiz3` or use the `hint` watch subcommand for a hint. + +// I AM DONE + +use std::fmt::Display; + +pub struct ReportCard { + pub grade: T, + pub student_name: String, + pub student_age: u8, +} + +impl ReportCard { + pub fn print(&self) -> String { + format!( + "{} ({}) - achieved a grade of {}", + &self.student_name, &self.student_age, &self.grade + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn generate_numeric_report_card() { + let report_card = ReportCard { + grade: 2.1, + student_name: "Tom Wriggle".to_string(), + student_age: 12, + }; + assert_eq!( + report_card.print(), + "Tom Wriggle (12) - achieved a grade of 2.1" + ); + } + + #[test] + fn generate_alphabetic_report_card() { + // TODO: Make sure to change the grade here after you finish the exercise. + let report_card = ReportCard { + grade: "A+".to_string(), + student_name: "Gary Plotter".to_string(), + student_age: 11, + }; + assert_eq!( + report_card.print(), + "Gary Plotter (11) - achieved a grade of A+" + ); + } +} diff --git a/smart_pointers/README.md b/smart_pointers/README.md new file mode 100644 index 0000000..d56d2b6 --- /dev/null +++ b/smart_pointers/README.md @@ -0,0 +1,12 @@ +# Smart Pointers + +In Rust, smart pointers are variables that contain an address in memory and reference some other data, but they also have additional metadata and capabilities. +Smart pointers in Rust often own the data they point to, while references only borrow data. + +## Further Information + +- [Smart Pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html) +- [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html) +- [Rc\, the Reference Counted Smart Pointer](https://doc.rust-lang.org/book/ch15-04-rc.html) +- [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html) +- [Cow Documentation](https://doc.rust-lang.org/std/borrow/enum.Cow.html) diff --git a/smart_pointers/arc1.rs b/smart_pointers/arc1.rs new file mode 100644 index 0000000..0043107 --- /dev/null +++ b/smart_pointers/arc1.rs @@ -0,0 +1,45 @@ +// arc1.rs +// +// In this exercise, we are given a Vec of u32 called "numbers" with values +// ranging from 0 to 99 -- [ 0, 1, 2, ..., 98, 99 ] We would like to use this +// set of numbers within 8 different threads simultaneously. Each thread is +// going to get the sum of every eighth value, with an offset. +// +// The first thread (offset 0), will sum 0, 8, 16, ... +// The second thread (offset 1), will sum 1, 9, 17, ... +// The third thread (offset 2), will sum 2, 10, 18, ... +// ... +// The eighth thread (offset 7), will sum 7, 15, 23, ... +// +// Because we are using threads, our values need to be thread-safe. Therefore, +// we are using Arc. We need to make a change in each of the two TODOs. +// +// Make this code compile by filling in a value for `shared_numbers` where the +// first TODO comment is, and create an initial binding for `child_numbers` +// where the second TODO comment is. Try not to create any copies of the +// `numbers` Vec! +// +// Execute `rustlings hint arc1` or use the `hint` watch subcommand for a hint. + +// I AM DONE + +#![forbid(unused_imports)] // Do not change this, (or the next) line. +use std::sync::Arc; +use std::thread; + +fn main() { + let numbers: Vec<_> = (0..100u32).collect(); + let shared_numbers = Arc::new(numbers); + let mut joinhandles = Vec::new(); + + for offset in 0..8 { + let child_numbers = Arc::clone(&shared_numbers); + joinhandles.push(thread::spawn(move || { + let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum(); + println!("Sum of offset {} is {}", offset, sum); + })); + } + for handle in joinhandles.into_iter() { + handle.join().unwrap(); + } +} diff --git a/smart_pointers/box1.rs b/smart_pointers/box1.rs new file mode 100644 index 0000000..b69a04c --- /dev/null +++ b/smart_pointers/box1.rs @@ -0,0 +1,58 @@ +// box1.rs +// +// At compile time, Rust needs to know how much space a type takes up. This +// becomes problematic for recursive types, where a value can have as part of +// itself another value of the same type. To get around the issue, we can use a +// `Box` - a smart pointer used to store data on the heap, which also allows us +// to wrap a recursive type. +// +// The recursive type we're implementing in this exercise is the `cons list` - a +// data structure frequently found in functional programming languages. Each +// item in a cons list contains two elements: the value of the current item and +// the next item. The last item is a value called `Nil`. +// +// Step 1: use a `Box` in the enum definition to make the code compile +// Step 2: create both empty and non-empty cons lists by replacing `todo!()` +// +// Note: the tests should not be changed +// +// Execute `rustlings hint box1` or use the `hint` watch subcommand for a hint. + +// I AM DONE + +#[derive(PartialEq, Debug)] +pub enum List { + Cons(i32, Box), + Nil, +} + +fn main() { + println!("This is an empty cons list: {:?}", create_empty_list()); + println!( + "This is a non-empty cons list: {:?}", + create_non_empty_list() + ); +} + +pub fn create_empty_list() -> List { + List::Nil +} + +pub fn create_non_empty_list() -> List { + List::Cons(6, Box::new(List::Cons(7, Box::new(List::Nil)))) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_create_empty_list() { + assert_eq!(List::Nil, create_empty_list()) + } + + #[test] + fn test_create_non_empty_list() { + assert_ne!(create_empty_list(), create_non_empty_list()) + } +} diff --git a/smart_pointers/cow1.rs b/smart_pointers/cow1.rs new file mode 100644 index 0000000..7958f65 --- /dev/null +++ b/smart_pointers/cow1.rs @@ -0,0 +1,81 @@ +// cow1.rs +// +// This exercise explores the Cow, or Clone-On-Write type. Cow is a +// clone-on-write smart pointer. It can enclose and provide immutable access to +// borrowed data, and clone the data lazily when mutation or ownership is +// required. The type is designed to work with general borrowed data via the +// Borrow trait. +// +// This exercise is meant to show you what to expect when passing data to Cow. +// Fix the unit tests by checking for Cow::Owned(_) and Cow::Borrowed(_) at the +// TODO markers. +// +// Execute `rustlings hint cow1` or use the `hint` watch subcommand for a hint. + +// I AM DONE + +use std::borrow::Cow; + +fn abs_all<'a, 'b>(input: &'a mut Cow<'b, [i32]>) -> &'a mut Cow<'b, [i32]> { + for i in 0..input.len() { + let v = input[i]; + if v < 0 { + // Clones into a vector if not already owned. + input.to_mut()[i] = -v; + } + } + input +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn reference_mutation() -> Result<(), &'static str> { + // Clone occurs because `input` needs to be mutated. + let slice = [-1, 0, 1]; + let mut input = Cow::from(&slice[..]); + match abs_all(&mut input) { + Cow::Owned(_) => Ok(()), + _ => Err("Expected owned value"), + } + } + + #[test] + fn reference_no_mutation() -> Result<(), &'static str> { + // No clone occurs because `input` doesn't need to be mutated. + let slice = [0, 1, 2]; + let mut input = Cow::from(&slice[..]); + match abs_all(&mut input) { + Cow::Borrowed(_) => Ok(()), + _ => Err("Expected owned value"), + } + } + + #[test] + fn owned_no_mutation() -> Result<(), &'static str> { + // We can also pass `slice` without `&` so Cow owns it directly. In this + // case no mutation occurs and thus also no clone, but the result is + // still owned because it was never borrowed or mutated. + let slice = vec![0, 1, 2]; + let mut input = Cow::from(slice); + match abs_all(&mut input) { + Cow::Owned(_) => Ok(()), + _ => Err("Expected owned value"), + } + } + + #[test] + fn owned_mutation() -> Result<(), &'static str> { + // Of course this is also the case if a mutation does occur. In this + // case the call to `to_mut()` in the abs_all() function returns a + // reference to the same data as before. + let slice = vec![-1, 0, 1]; + let mut input = Cow::from(slice); + match abs_all(&mut input) { + Cow::Owned(_) => Ok(()), + _ => Err("Expected owned value"), + } + } +} diff --git a/smart_pointers/rc1.rs b/smart_pointers/rc1.rs new file mode 100644 index 0000000..f901abf --- /dev/null +++ b/smart_pointers/rc1.rs @@ -0,0 +1,105 @@ +// rc1.rs +// +// In this exercise, we want to express the concept of multiple owners via the +// Rc type. This is a model of our solar system - there is a Sun type and +// multiple Planets. The Planets take ownership of the sun, indicating that they +// revolve around the sun. +// +// Make this code compile by using the proper Rc primitives to express that the +// sun has multiple owners. +// +// Execute `rustlings hint rc1` or use the `hint` watch subcommand for a hint. + +// I AM DONE + +use std::rc::Rc; + +#[derive(Debug)] +struct Sun {} + +#[derive(Debug)] +enum Planet { + Mercury(Rc), + Venus(Rc), + Earth(Rc), + Mars(Rc), + Jupiter(Rc), + Saturn(Rc), + Uranus(Rc), + Neptune(Rc), +} + +impl Planet { + fn details(&self) { + println!("Hi from {:?}!", self) + } +} + +#[test] +fn main() { + let sun = Rc::new(Sun {}); + println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference + + let mercury = Planet::Mercury(Rc::clone(&sun)); + println!("reference count = {}", Rc::strong_count(&sun)); // 2 references + mercury.details(); + + let venus = Planet::Venus(Rc::clone(&sun)); + println!("reference count = {}", Rc::strong_count(&sun)); // 3 references + venus.details(); + + let earth = Planet::Earth(Rc::clone(&sun)); + println!("reference count = {}", Rc::strong_count(&sun)); // 4 references + earth.details(); + + let mars = Planet::Mars(Rc::clone(&sun)); + println!("reference count = {}", Rc::strong_count(&sun)); // 5 references + mars.details(); + + let jupiter = Planet::Jupiter(Rc::clone(&sun)); + println!("reference count = {}", Rc::strong_count(&sun)); // 6 references + jupiter.details(); + + // TODO + let saturn = Planet::Saturn(Rc::clone(&sun)); + println!("reference count = {}", Rc::strong_count(&sun)); // 7 references + saturn.details(); + + // TODO + let uranus = Planet::Uranus(Rc::clone(&sun)); + println!("reference count = {}", Rc::strong_count(&sun)); // 8 references + uranus.details(); + + // TODO + let neptune = Planet::Neptune(Rc::clone(&sun)); + println!("reference count = {}", Rc::strong_count(&sun)); // 9 references + neptune.details(); + + assert_eq!(Rc::strong_count(&sun), 9); + + drop(neptune); + println!("reference count = {}", Rc::strong_count(&sun)); // 8 references + + drop(uranus); + println!("reference count = {}", Rc::strong_count(&sun)); // 7 references + + drop(saturn); + println!("reference count = {}", Rc::strong_count(&sun)); // 6 references + + drop(jupiter); + println!("reference count = {}", Rc::strong_count(&sun)); // 5 references + + drop(mars); + println!("reference count = {}", Rc::strong_count(&sun)); // 4 references + + drop(earth); + println!("reference count = {}", Rc::strong_count(&sun)); // 3 references + + drop(mercury); + println!("reference count = {}", Rc::strong_count(&sun)); // 2 references + + drop(venus); + println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference + + assert_eq!(Rc::strong_count(&sun), 1); +} diff --git a/strings/README.md b/strings/README.md new file mode 100644 index 0000000..fa2104c --- /dev/null +++ b/strings/README.md @@ -0,0 +1,9 @@ +# Strings + +Rust has two string types, a string slice (`&str`) and an owned string (`String`). +We're not going to dictate when you should use which one, but we'll show you how +to identify and create them, as well as use them. + +## Further information + +- [Strings](https://doc.rust-lang.org/book/ch08-02-strings.html) diff --git a/strings/strings1.rs b/strings/strings1.rs new file mode 100644 index 0000000..561e033 --- /dev/null +++ b/strings/strings1.rs @@ -0,0 +1,17 @@ +// strings1.rs +// +// Make me compile without changing the function signature! +// +// Execute `rustlings hint strings1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + let answer = current_favorite_color(); + println!("My current favorite color is {}", answer); +} + +fn current_favorite_color() -> String { + "blue".to_owned() +} diff --git a/strings/strings2.rs b/strings/strings2.rs new file mode 100644 index 0000000..d46536e --- /dev/null +++ b/strings/strings2.rs @@ -0,0 +1,21 @@ +// strings2.rs +// +// Make me compile without changing the function signature! +// +// Execute `rustlings hint strings2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + let word = String::from("green"); // Try not changing this line :) + if is_a_color_word(&word) { + println!("That is a color word I know!"); + } else { + println!("That is not a color word I know."); + } +} + +fn is_a_color_word(attempt: &str) -> bool { + attempt == "green" || attempt == "blue" || attempt == "red" +} diff --git a/strings/strings3.rs b/strings/strings3.rs new file mode 100644 index 0000000..dc39dc4 --- /dev/null +++ b/strings/strings3.rs @@ -0,0 +1,51 @@ +// strings3.rs +// +// Execute `rustlings hint strings3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn trim_me(input: &str) -> String { + // TODO: Remove whitespace from both ends of a string! + input.trim_start().trim_end().to_owned() +} + +fn compose_me(input: &str) -> String { + // TODO: Add " world!" to the string! There's multiple ways to do this! + input.to_owned() + " world!" +} + +fn replace_me(input: &str) -> String { + // TODO: Replace "cars" in the string with "balloons"! + input.replace("cars", "balloons") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn trim_a_string() { + assert_eq!(trim_me("Hello! "), "Hello!"); + assert_eq!(trim_me(" What's up!"), "What's up!"); + assert_eq!(trim_me(" Hola! "), "Hola!"); + } + + #[test] + fn compose_a_string() { + assert_eq!(compose_me("Hello"), "Hello world!"); + assert_eq!(compose_me("Goodbye"), "Goodbye world!"); + } + + #[test] + fn replace_a_string() { + assert_eq!( + replace_me("I think cars are cool"), + "I think balloons are cool" + ); + assert_eq!( + replace_me("I love to look at cars"), + "I love to look at balloons" + ); + } +} diff --git a/strings/strings4.rs b/strings/strings4.rs new file mode 100644 index 0000000..e82c4cd --- /dev/null +++ b/strings/strings4.rs @@ -0,0 +1,30 @@ +// strings4.rs +// +// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your +// task is to call one of these two functions on each value depending on what +// you think each value is. That is, add either `string_slice` or `string` +// before the parentheses on each line. If you're right, it will compile! +// +// No hints this time! + +// I AM DONE + +fn string_slice(arg: &str) { + println!("{}", arg); +} +fn string(arg: String) { + println!("{}", arg); +} + +fn main() { + string_slice("blue"); + string("red".to_string()); + string(String::from("hi")); + string("rust is fun!".to_owned()); + string("nice weather".into()); + string(format!("Interpolation {}", "Station")); + string_slice(&String::from("abc")[0..1]); + string_slice(" hello there ".trim()); + string("Happy Monday!".to_string().replace("Mon", "Tues")); + string("mY sHiFt KeY iS sTiCkY".to_lowercase()); +} diff --git a/structs/README.md b/structs/README.md new file mode 100644 index 0000000..3fc1fdc --- /dev/null +++ b/structs/README.md @@ -0,0 +1,8 @@ +# Structs + +Rust has three struct types: a classic C struct, a tuple struct, and a unit struct. + +## Further information + +- [Structures](https://doc.rust-lang.org/book/ch05-01-defining-structs.html) +- [Method Syntax](https://doc.rust-lang.org/book/ch05-03-method-syntax.html) diff --git a/structs/structs1.rs b/structs/structs1.rs new file mode 100644 index 0000000..517d529 --- /dev/null +++ b/structs/structs1.rs @@ -0,0 +1,57 @@ +// structs1.rs +// +// Address all the TODOs to make the tests pass! +// +// Execute `rustlings hint structs1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +struct ColorClassicStruct { + red: u8, + green: u8, + blue: u8, +} + +struct ColorTupleStruct(u8, u8, u8); + +#[derive(Debug)] +struct UnitLikeStruct; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn classic_c_structs() { + // TODO: Instantiate a classic c struct! + let green = ColorClassicStruct { + red: 0, + green: 255, + blue: 0, + }; + + assert_eq!(green.red, 0); + assert_eq!(green.green, 255); + assert_eq!(green.blue, 0); + } + + #[test] + fn tuple_structs() { + // TODO: Instantiate a tuple struct! + let green = ColorTupleStruct(0, 255, 0); + + assert_eq!(green.0, 0); + assert_eq!(green.1, 255); + assert_eq!(green.2, 0); + } + + #[test] + fn unit_structs() { + // TODO: Instantiate a unit-like struct! + let unit_like_struct = UnitLikeStruct; + let message = format!("{:?}s are fun!", unit_like_struct); + + assert_eq!(message, "UnitLikeStructs are fun!"); + } +} diff --git a/structs/structs2.rs b/structs/structs2.rs new file mode 100644 index 0000000..4442b4b --- /dev/null +++ b/structs/structs2.rs @@ -0,0 +1,58 @@ +// structs2.rs +// +// Address all the TODOs to make the tests pass! +// +// Execute `rustlings hint structs2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +#[derive(Debug)] +struct Order { + name: String, + year: u32, + made_by_phone: bool, + made_by_mobile: bool, + made_by_email: bool, + item_number: u32, + count: u32, +} + +fn create_order_template() -> Order { + Order { + name: String::from("Bob"), + year: 2019, + made_by_phone: false, + made_by_mobile: false, + made_by_email: true, + item_number: 123, + count: 0, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn your_order() { + let order_template = create_order_template(); + // TODO: Create your own order using the update syntax and template above! + let your_order = Order { + name: String::from("Hacker in Rust"), + year: 2019, + made_by_phone: false, + made_by_mobile: false, + made_by_email: true, + item_number: 123, + count: 1, + }; + assert_eq!(your_order.name, "Hacker in Rust"); + assert_eq!(your_order.year, order_template.year); + assert_eq!(your_order.made_by_phone, order_template.made_by_phone); + assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile); + assert_eq!(your_order.made_by_email, order_template.made_by_email); + assert_eq!(your_order.item_number, order_template.item_number); + assert_eq!(your_order.count, 1); + } +} diff --git a/structs/structs3.rs b/structs/structs3.rs new file mode 100644 index 0000000..7f366f9 --- /dev/null +++ b/structs/structs3.rs @@ -0,0 +1,88 @@ +// structs3.rs +// +// Structs contain data, but can also have logic. In this exercise we have +// defined the Package struct and we want to test some logic attached to it. +// Make the code compile and the tests pass! +// +// Execute `rustlings hint structs3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +#[derive(Debug)] +struct Package { + sender_country: String, + recipient_country: String, + weight_in_grams: u32, +} + +impl Package { + fn new(sender_country: String, recipient_country: String, weight_in_grams: u32) -> Package { + if weight_in_grams < 10 { + // This is not how you should handle errors in Rust, + // but we will learn about error handling later. + panic!("Can not ship a package with weight below 10 grams.") + } else { + Package { + sender_country, + recipient_country, + weight_in_grams, + } + } + } + + fn is_international(&self) -> bool { + self.sender_country != self.recipient_country + } + + fn get_fees(&self, cents_per_gram: u32) -> u32 { + self.weight_in_grams * cents_per_gram + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn fail_creating_weightless_package() { + let sender_country = String::from("Spain"); + let recipient_country = String::from("Austria"); + + Package::new(sender_country, recipient_country, 5); + } + + #[test] + fn create_international_package() { + let sender_country = String::from("Spain"); + let recipient_country = String::from("Russia"); + + let package = Package::new(sender_country, recipient_country, 1200); + + assert!(package.is_international()); + } + + #[test] + fn create_local_package() { + let sender_country = String::from("Canada"); + let recipient_country = sender_country.clone(); + + let package = Package::new(sender_country, recipient_country, 1200); + + assert!(!package.is_international()); + } + + #[test] + fn calculate_transport_fees() { + let sender_country = String::from("Spain"); + let recipient_country = String::from("Spain"); + + let cents_per_gram = 3; + + let package = Package::new(sender_country, recipient_country, 1500); + + assert_eq!(package.get_fees(cents_per_gram), 4500); + assert_eq!(package.get_fees(cents_per_gram * 2), 9000); + } +} diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..27c6818 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,7 @@ +# Tests + +Going out of order from the book to cover tests -- many of the following exercises will ask you to make tests pass! + +## Further information + +- [Writing Tests](https://doc.rust-lang.org/book/ch11-01-writing-tests.html) diff --git a/tests/tests1.rs b/tests/tests1.rs new file mode 100644 index 0000000..48134d7 --- /dev/null +++ b/tests/tests1.rs @@ -0,0 +1,21 @@ +// tests1.rs +// +// Tests are important to ensure that your code does what you think it should +// do. Tests can be run on this file with the following command: rustlings run +// tests1 +// +// This test has a problem with it -- make the test compile! Make the test pass! +// Make the test fail! +// +// Execute `rustlings hint tests1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +#[cfg(test)] +mod tests { + #[test] + fn you_can_assert() { + assert!(true == true); + } +} diff --git a/tests/tests2.rs b/tests/tests2.rs new file mode 100644 index 0000000..07d6b6c --- /dev/null +++ b/tests/tests2.rs @@ -0,0 +1,18 @@ +// tests2.rs +// +// This test has a problem with it -- make the test compile! Make the test pass! +// Make the test fail! +// +// Execute `rustlings hint tests2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +#[cfg(test)] +mod tests { + #[test] + fn you_can_assert_eq() { + let x = 5; + assert_eq!(x, 5); + } +} diff --git a/tests/tests3.rs b/tests/tests3.rs new file mode 100644 index 0000000..57b0ce2 --- /dev/null +++ b/tests/tests3.rs @@ -0,0 +1,29 @@ +// tests3.rs +// +// This test isn't testing our function -- make it do that in such a way that +// the test passes. Then write a second test that tests whether we get the +// result we expect to get when we call `is_even(5)`. +// +// Execute `rustlings hint tests3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +pub fn is_even(num: i32) -> bool { + num % 2 == 0 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_true_when_even() { + assert!(is_even(2) == true); + } + + #[test] + fn is_false_when_odd() { + assert!(is_even(3) == false); + } +} diff --git a/tests/tests4.rs b/tests/tests4.rs new file mode 100644 index 0000000..6bdcf19 --- /dev/null +++ b/tests/tests4.rs @@ -0,0 +1,50 @@ +// tests4.rs +// +// Make sure that we're testing for the correct conditions! +// +// Execute `rustlings hint tests4` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +struct Rectangle { + width: i32, + height: i32, +} + +impl Rectangle { + // Only change the test functions themselves + pub fn new(width: i32, height: i32) -> Self { + if width <= 0 || height <= 0 { + panic!("Rectangle width and height cannot be negative!") + } + Rectangle { width, height } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn correct_width_and_height() { + // This test should check if the rectangle is the size that we pass into its constructor + let rect = Rectangle::new(10, 20); + assert_eq!(rect.width, 10); // check width + assert_eq!(rect.height, 20); // check height + } + + #[test] + #[should_panic()] + fn negative_width() { + // This test should check if program panics when we try to create rectangle with negative width + let _rect = Rectangle::new(-10, 10); + } + + #[test] + #[should_panic()] + fn negative_height() { + // This test should check if program panics when we try to create rectangle with negative height + let _rect = Rectangle::new(10, -10); + } +} diff --git a/threads/README.md b/threads/README.md new file mode 100644 index 0000000..dbe6664 --- /dev/null +++ b/threads/README.md @@ -0,0 +1,9 @@ +# Threads + +In most current operating systems, an executed program's code is run in a process, and the operating system manages multiple processes at once. +Within your program, you can also have independent parts that run simultaneously. The features that run these independent parts are called threads. + +## Further information + +- [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) +- [Using Threads to Run Code Simultaneously](https://doc.rust-lang.org/book/ch16-01-threads.html) diff --git a/threads/threads1.rs b/threads/threads1.rs new file mode 100644 index 0000000..c6ce4a0 --- /dev/null +++ b/threads/threads1.rs @@ -0,0 +1,40 @@ +// threads1.rs +// +// This program spawns multiple threads that each run for at least 250ms, and +// each thread returns how much time they took to complete. The program should +// wait until all the spawned threads have finished and should collect their +// return values into a vector. +// +// Execute `rustlings hint threads1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +use std::thread; +use std::time::{Duration, Instant}; + +fn main() { + let mut handles = vec![]; + for i in 0..10 { + handles.push(thread::spawn(move || { + let start = Instant::now(); + thread::sleep(Duration::from_millis(250)); + println!("thread {} is complete", i); + start.elapsed().as_millis() + })); + } + + let mut results: Vec = vec![]; + for handle in handles { + results.push(handle.join().unwrap()); + } + + if results.len() != 10 { + panic!("Oh no! All the spawned threads did not finish!"); + } + + println!(); + for (i, result) in results.into_iter().enumerate() { + println!("thread {} took {}ms", i, result); + } +} diff --git a/threads/threads2.rs b/threads/threads2.rs new file mode 100644 index 0000000..2ec8dd1 --- /dev/null +++ b/threads/threads2.rs @@ -0,0 +1,43 @@ +// threads2.rs +// +// Building on the last exercise, we want all of the threads to complete their +// work but this time the spawned threads need to be in charge of updating a +// shared value: JobStatus.jobs_completed +// +// Execute `rustlings hint threads2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; + +struct JobStatus { + jobs_completed: u32, +} + +fn main() { + let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 })); + + let mut handles = vec![]; + + for _ in 0..10 { + let status_shared = Arc::clone(&status); + + let handle = thread::spawn(move || { + thread::sleep(Duration::from_millis(250)); + // TODO: You must take an action before you update a shared value + status_shared.lock().unwrap().jobs_completed += 1; + }); + + handles.push(handle); + } + for handle in handles { + handle.join().unwrap(); + // TODO: Print the value of the JobStatus.jobs_completed. Did you notice + // anything interesting in the output? Do you have to 'join' on all the + // handles? + println!("jobs completed {}", status.lock().unwrap().jobs_completed) + } +} diff --git a/threads/threads3.rs b/threads/threads3.rs new file mode 100644 index 0000000..ee6f6c6 --- /dev/null +++ b/threads/threads3.rs @@ -0,0 +1,74 @@ +// threads3.rs +// +// Execute `rustlings hint threads3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +use std::sync::mpsc; +use std::sync::Arc; +use std::thread; +use std::time::Duration; + +struct Queue { + length: u32, + first_half: Vec, + second_half: Vec, +} + +impl Queue { + fn new() -> Self { + Queue { + length: 10, + first_half: vec![1, 2, 3, 4, 5], + second_half: vec![6, 7, 8, 9, 10], + } + } +} + +fn send_tx(q: Queue, tx: mpsc::Sender) -> () { + let qc = Arc::new(q); + let qc1 = Arc::clone(&qc); + let qc2 = Arc::clone(&qc); + + let tx_cloned = tx.clone(); + + thread::spawn(move || { + for val in &qc1.first_half { + println!("sending {:?}", val); + + tx_cloned.send(*val).unwrap(); + + thread::sleep(Duration::from_secs(1)); + } + }); + + thread::spawn(move || { + for val in &qc2.second_half { + println!("sending {:?}", val); + + tx.send(*val).unwrap(); + + thread::sleep(Duration::from_secs(1)); + } + }); +} + +#[test] +fn main() { + let (tx, rx) = mpsc::channel(); + let queue = Queue::new(); + let queue_length = queue.length; + + send_tx(queue, tx); + + let mut total_received: u32 = 0; + + for received in rx { + println!("Got: {}", received); + total_received += 1; + } + + println!("total numbers received: {}", total_received); + assert_eq!(total_received, queue_length) +} diff --git a/traits/README.md b/traits/README.md new file mode 100644 index 0000000..ac87c64 --- /dev/null +++ b/traits/README.md @@ -0,0 +1,19 @@ +# Traits + +A trait is a collection of methods. + +Data types can implement traits. To do so, the methods making up the trait are defined for the data type. For example, the `String` data type implements the `From<&str>` trait. This allows a user to write `String::from("hello")`. + +In this way, traits are somewhat similar to Java interfaces and C++ abstract classes. + +Some additional common Rust traits include: + +- `Clone` (the `clone` method) +- `Display` (which allows formatted display via `{}`) +- `Debug` (which allows formatted display via `{:?}`) + +Because traits indicate shared behavior between data types, they are useful when writing generics. + +## Further information + +- [Traits](https://doc.rust-lang.org/book/ch10-02-traits.html) diff --git a/traits/traits1.rs b/traits/traits1.rs new file mode 100644 index 0000000..614b613 --- /dev/null +++ b/traits/traits1.rs @@ -0,0 +1,45 @@ +// traits1.rs +// +// Time to implement some traits! Your task is to implement the trait +// `AppendBar` for the type `String`. The trait AppendBar has only one function, +// which appends "Bar" to any object implementing this trait. +// +// Execute `rustlings hint traits1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +trait AppendBar { + fn append_bar(self) -> Self; +} + +impl AppendBar for String { + // TODO: Implement `AppendBar` for type `String`. + fn append_bar(self) -> Self { + self + "Bar" + } +} + +fn main() { + let s = String::from("Foo"); + let s = s.append_bar(); + println!("s: {}", s); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_foo_bar() { + assert_eq!(String::from("Foo").append_bar(), String::from("FooBar")); + } + + #[test] + fn is_bar_bar() { + assert_eq!( + String::from("").append_bar().append_bar(), + String::from("BarBar") + ); + } +} diff --git a/traits/traits2.rs b/traits/traits2.rs new file mode 100644 index 0000000..8aa0b7c --- /dev/null +++ b/traits/traits2.rs @@ -0,0 +1,35 @@ +// traits2.rs +// +// Your task is to implement the trait `AppendBar` for a vector of strings. To +// implement this trait, consider for a moment what it means to 'append "Bar"' +// to a vector of strings. +// +// No boiler plate code this time, you can do this! +// +// Execute `rustlings hint traits2` or use the `hint` watch subcommand for a hint. + +// I AM DONE + +trait AppendBar { + fn append_bar(self) -> Self; +} + +// TODO: Implement trait `AppendBar` for a vector of strings. +impl AppendBar for Vec { + fn append_bar(mut self) -> Self { + self.push(String::from("Bar")); + self + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_vec_pop_eq_bar() { + let mut foo = vec![String::from("Foo")].append_bar(); + assert_eq!(foo.pop().unwrap(), String::from("Bar")); + assert_eq!(foo.pop().unwrap(), String::from("Foo")); + } +} diff --git a/traits/traits3.rs b/traits/traits3.rs new file mode 100644 index 0000000..b7342d7 --- /dev/null +++ b/traits/traits3.rs @@ -0,0 +1,44 @@ +// traits3.rs +// +// Your task is to implement the Licensed trait for both structures and have +// them return the same information without writing the same function twice. +// +// Consider what you can add to the Licensed trait. +// +// Execute `rustlings hint traits3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +pub trait Licensed { + fn licensing_info(&self) -> String { + "Some information".to_string() + } +} + +struct SomeSoftware { + version_number: i32, +} + +struct OtherSoftware { + version_number: String, +} + +impl Licensed for SomeSoftware {} // Don't edit this line +impl Licensed for OtherSoftware {} // Don't edit this line + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_licensing_info_the_same() { + let licensing_info = String::from("Some information"); + let some_software = SomeSoftware { version_number: 1 }; + let other_software = OtherSoftware { + version_number: "v2.0.0".to_string(), + }; + assert_eq!(some_software.licensing_info(), licensing_info); + assert_eq!(other_software.licensing_info(), licensing_info); + } +} diff --git a/traits/traits4.rs b/traits/traits4.rs new file mode 100644 index 0000000..7b4bd6a --- /dev/null +++ b/traits/traits4.rs @@ -0,0 +1,49 @@ +// traits4.rs +// +// Your task is to replace the '??' sections so the code compiles. +// +// Don't change any line other than the marked one. +// +// Execute `rustlings hint traits4` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +pub trait Licensed { + fn licensing_info(&self) -> String { + "some information".to_string() + } +} + +struct SomeSoftware {} + +struct OtherSoftware {} + +impl Licensed for SomeSoftware {} +impl Licensed for OtherSoftware {} + +// YOU MAY ONLY CHANGE THE NEXT LINE +fn compare_license_types(software: impl Licensed, software_two: impl Licensed) -> bool { + software.licensing_info() == software_two.licensing_info() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn compare_license_information() { + let some_software = SomeSoftware {}; + let other_software = OtherSoftware {}; + + assert!(compare_license_types(some_software, other_software)); + } + + #[test] + fn compare_license_information_backwards() { + let some_software = SomeSoftware {}; + let other_software = OtherSoftware {}; + + assert!(compare_license_types(other_software, some_software)); + } +} diff --git a/traits/traits5.rs b/traits/traits5.rs new file mode 100644 index 0000000..4fc052a --- /dev/null +++ b/traits/traits5.rs @@ -0,0 +1,40 @@ +// traits5.rs +// +// Your task is to replace the '??' sections so the code compiles. +// +// Don't change any line other than the marked one. +// +// Execute `rustlings hint traits5` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +pub trait SomeTrait { + fn some_function(&self) -> bool { + true + } +} + +pub trait OtherTrait { + fn other_function(&self) -> bool { + true + } +} + +struct SomeStruct {} +struct OtherStruct {} + +impl SomeTrait for SomeStruct {} +impl OtherTrait for SomeStruct {} +impl SomeTrait for OtherStruct {} +impl OtherTrait for OtherStruct {} + +// YOU MAY ONLY CHANGE THE NEXT LINE +fn some_func(item: impl SomeTrait + OtherTrait) -> bool { + item.some_function() && item.other_function() +} + +fn main() { + some_func(SomeStruct {}); + some_func(OtherStruct {}); +} diff --git a/variables/README.md b/variables/README.md new file mode 100644 index 0000000..7964ff2 --- /dev/null +++ b/variables/README.md @@ -0,0 +1,9 @@ +# Variables + +In Rust, variables are immutable by default. +When a variable is immutable, once a value is bound to a name, you can’t change that value. +You can make them mutable by adding `mut` in front of the variable name. + +## Further information + +- [Variables and Mutability](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html) diff --git a/variables/variables1.rs b/variables/variables1.rs new file mode 100644 index 0000000..ba90630 --- /dev/null +++ b/variables/variables1.rs @@ -0,0 +1,13 @@ +// variables1.rs +// +// Make me compile! +// +// Execute `rustlings hint variables1` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + let x = 5; + println!("x has the value {}", x); +} diff --git a/variables/variables2.rs b/variables/variables2.rs new file mode 100644 index 0000000..df508fc --- /dev/null +++ b/variables/variables2.rs @@ -0,0 +1,15 @@ +// variables2.rs +// +// Execute `rustlings hint variables2` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + let x: u8 = 0; + if x == 10 { + println!("x is ten!"); + } else { + println!("x is not ten!"); + } +} diff --git a/variables/variables3.rs b/variables/variables3.rs new file mode 100644 index 0000000..cb18d2d --- /dev/null +++ b/variables/variables3.rs @@ -0,0 +1,11 @@ +// variables3.rs +// +// Execute `rustlings hint variables3` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + let x: i32 = 0; + println!("Number {}", x); +} diff --git a/variables/variables4.rs b/variables/variables4.rs new file mode 100644 index 0000000..d5ea009 --- /dev/null +++ b/variables/variables4.rs @@ -0,0 +1,13 @@ +// variables4.rs +// +// Execute `rustlings hint variables4` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + let mut x = 3; + println!("Number {}", x); + x = 5; // don't change this line + println!("Number {}", x); +} diff --git a/variables/variables5.rs b/variables/variables5.rs new file mode 100644 index 0000000..aa2b79c --- /dev/null +++ b/variables/variables5.rs @@ -0,0 +1,13 @@ +// variables5.rs +// +// Execute `rustlings hint variables5` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +fn main() { + let number = "T-H-R-E-E"; // don't change this line + println!("Spell a Number : {}", number); + let number = 3; // don't rename this variable + println!("Number plus two is : {}", number + 2); +} diff --git a/variables/variables6.rs b/variables/variables6.rs new file mode 100644 index 0000000..0aa912d --- /dev/null +++ b/variables/variables6.rs @@ -0,0 +1,11 @@ +// variables6.rs +// +// Execute `rustlings hint variables6` or use the `hint` watch subcommand for a +// hint. + +// I AM DONE + +const NUMBER: u8 = 3; +fn main() { + println!("Number {}", NUMBER); +} diff --git a/vecs/README.md b/vecs/README.md new file mode 100644 index 0000000..8ff9b85 --- /dev/null +++ b/vecs/README.md @@ -0,0 +1,17 @@ +# Vectors + +Vectors are one of the most-used Rust data structures. In other programming +languages, they'd simply be called Arrays, but since Rust operates on a +bit of a lower level, an array in Rust is stored on the stack (meaning it +can't grow or shrink, and the size needs to be known at compile time), +and a Vector is stored in the heap (where these restrictions do not apply). + +Vectors are a bit of a later chapter in the book, but we think that they're +useful enough to talk about them a bit earlier. We shall be talking about +the other useful data structure, hash maps, later. + +## Further information + +- [Storing Lists of Values with Vectors](https://doc.rust-lang.org/stable/book/ch08-01-vectors.html) +- [`iter_mut`](https://doc.rust-lang.org/std/primitive.slice.html#method.iter_mut) +- [`map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map) diff --git a/vecs/vecs1.rs b/vecs/vecs1.rs new file mode 100644 index 0000000..6aa4aed --- /dev/null +++ b/vecs/vecs1.rs @@ -0,0 +1,28 @@ +// vecs1.rs +// +// Your task is to create a `Vec` which holds the exact same elements as in the +// array `a`. +// +// Make me compile and pass the test! +// +// Execute `rustlings hint vecs1` or use the `hint` watch subcommand for a hint. + +// I AM DONE + +fn array_and_vec() -> ([i32; 4], Vec) { + let a = [10, 20, 30, 40]; // a plain array + let v = vec![10, 20, 30, 40]; // TODO: declare your vector here with the macro for vectors + + (a, v) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_array_and_vec_similarity() { + let (a, v) = array_and_vec(); + assert_eq!(a, v[..]); + } +} diff --git a/vecs/vecs2.rs b/vecs/vecs2.rs new file mode 100644 index 0000000..371fee8 --- /dev/null +++ b/vecs/vecs2.rs @@ -0,0 +1,46 @@ +// vecs2.rs +// +// A Vec of even numbers is given. Your task is to complete the loop so that +// each number in the Vec is multiplied by 2. +// +// Make me pass the test! +// +// Execute `rustlings hint vecs2` or use the `hint` watch subcommand for a hint. + +// I AM DONE + +fn vec_loop(mut v: Vec) -> Vec { + for element in v.iter_mut() { + // TODO: Fill this up so that each element in the Vec `v` is + // multiplied by 2. + *element *= 2; + } + + // At this point, `v` should be equal to [4, 8, 12, 16, 20]. + v +} + +fn vec_map(v: &Vec) -> Vec { + v.iter().map(|element| *element * 2).collect() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_vec_loop() { + let v: Vec = (1..).filter(|x| x % 2 == 0).take(5).collect(); + let ans = vec_loop(v.clone()); + + assert_eq!(ans, v.iter().map(|x| x * 2).collect::>()); + } + + #[test] + fn test_vec_map() { + let v: Vec = (1..).filter(|x| x % 2 == 0).take(5).collect(); + let ans = vec_map(&v); + + assert_eq!(ans, v.iter().map(|x| x * 2).collect::>()); + } +}