From 2dc93caddad43821743e4903d89b355df58d7a49 Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Thu, 24 Jun 2021 21:33:41 -0500 Subject: [PATCH 01/39] fix(from_str, try_from_into): custom error types Remove the use of trait objects as errors from `from_str` and `try_from_into`; they seem to have caused a lot of confusion in practice. (Also, it's considered best practice to use custom error types instead of boxed errors in library code.) Instead, use custom error enums, and update hints accordingly. Hints also provide some guidance about converting errors, which could be covered more completely in a future advanced errors section. Also move from_str to directly after the similar exercise `from_into`, for the sake of familiarity when solving. --- exercises/conversions/from_str.rs | 56 ++++++++++++++----- exercises/conversions/try_from_into.rs | 74 ++++++++++++++++++-------- info.toml | 53 ++++++++++-------- 3 files changed, 127 insertions(+), 56 deletions(-) diff --git a/exercises/conversions/from_str.rs b/exercises/conversions/from_str.rs index 4beebacd..6e9e699d 100644 --- a/exercises/conversions/from_str.rs +++ b/exercises/conversions/from_str.rs @@ -1,16 +1,31 @@ -// This does practically the same thing that TryFrom<&str> does. +// 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 -use std::error; +use std::num::ParseIntError; use std::str::FromStr; -#[derive(Debug)] +#[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 NOT DONE // Steps: @@ -24,7 +39,7 @@ struct Person { // If everything goes well, then return a Result of a Person object impl FromStr for Person { - type Err = Box; + type Err = ParsePersonError; fn from_str(s: &str) -> Result { } } @@ -40,7 +55,7 @@ mod tests { #[test] fn empty_input() { - assert!("".parse::().is_err()); + assert_eq!("".parse::(), Err(ParsePersonError::Empty)); } #[test] fn good_input() { @@ -52,41 +67,56 @@ mod tests { } #[test] fn missing_age() { - assert!("John,".parse::().is_err()); + assert!(matches!( + "John,".parse::(), + Err(ParsePersonError::ParseInt(_)) + )); } #[test] fn invalid_age() { - assert!("John,twenty".parse::().is_err()); + assert!(matches!( + "John,twenty".parse::(), + Err(ParsePersonError::ParseInt(_)) + )); } #[test] fn missing_comma_and_age() { - assert!("John".parse::().is_err()); + assert_eq!("John".parse::(), Err(ParsePersonError::BadLen)); } #[test] fn missing_name() { - assert!(",1".parse::().is_err()); + assert_eq!(",1".parse::(), Err(ParsePersonError::NoName)); } #[test] fn missing_name_and_age() { - assert!(",".parse::().is_err()); + assert!(matches!( + ",".parse::(), + Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_)) + )); } #[test] fn missing_name_and_invalid_age() { - assert!(",one".parse::().is_err()); + assert!(matches!( + ",one".parse::(), + Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_)) + )); } #[test] fn trailing_comma() { - assert!("John,32,".parse::().is_err()); + assert_eq!("John,32,".parse::(), Err(ParsePersonError::BadLen)); } #[test] fn trailing_comma_and_some_string() { - assert!("John,32,man".parse::().is_err()); + assert_eq!( + "John,32,man".parse::(), + Err(ParsePersonError::BadLen) + ); } } diff --git a/exercises/conversions/try_from_into.rs b/exercises/conversions/try_from_into.rs index c0b5d986..b8ec4455 100644 --- a/exercises/conversions/try_from_into.rs +++ b/exercises/conversions/try_from_into.rs @@ -1,9 +1,9 @@ +// 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 use std::convert::{TryFrom, TryInto}; -use std::error; #[derive(Debug, PartialEq)] struct Color { @@ -12,12 +12,21 @@ struct Color { 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 NOT 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. +// 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! @@ -25,20 +34,23 @@ struct Color { // Tuple implementation impl TryFrom<(i16, i16, i16)> for Color { - type Error = Box; - fn try_from(tuple: (i16, i16, i16)) -> Result {} + type Error = IntoColorError; + fn try_from(tuple: (i16, i16, i16)) -> Result { + } } // Array implementation impl TryFrom<[i16; 3]> for Color { - type Error = Box; - fn try_from(arr: [i16; 3]) -> Result {} + type Error = IntoColorError; + fn try_from(arr: [i16; 3]) -> Result { + } } // Slice implementation impl TryFrom<&[i16]> for Color { - type Error = Box; - fn try_from(slice: &[i16]) -> Result {} + type Error = IntoColorError; + fn try_from(slice: &[i16]) -> Result { + } } fn main() { @@ -46,15 +58,15 @@ fn main() { let c1 = Color::try_from((183, 65, 14)); println!("{:?}", c1); - // Since From is implemented for Color, we should be able to use Into + // 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 `from` function + // With slice we should use `try_from` function let c3 = Color::try_from(&v[..]); println!("{:?}", c3); - // or take slice within round brackets and use Into + // or take slice within round brackets and use TryInto let c4: Result = (&v[..]).try_into(); println!("{:?}", c4); } @@ -65,15 +77,24 @@ mod tests { #[test] fn test_tuple_out_of_range_positive() { - assert!(Color::try_from((256, 1000, 10000)).is_err()); + assert_eq!( + Color::try_from((256, 1000, 10000)), + Err(IntoColorError::IntConversion) + ); } #[test] fn test_tuple_out_of_range_negative() { - assert!(Color::try_from((-1, -10, -256)).is_err()); + assert_eq!( + Color::try_from((-1, -10, -256)), + Err(IntoColorError::IntConversion) + ); } #[test] fn test_tuple_sum() { - assert!(Color::try_from((-1, 255, 255)).is_err()); + assert_eq!( + Color::try_from((-1, 255, 255)), + Err(IntoColorError::IntConversion) + ); } #[test] fn test_tuple_correct() { @@ -91,17 +112,17 @@ mod tests { #[test] fn test_array_out_of_range_positive() { let c: Result = [1000, 10000, 256].try_into(); - assert!(c.is_err()); + assert_eq!(c, Err(IntoColorError::IntConversion)); } #[test] fn test_array_out_of_range_negative() { let c: Result = [-10, -256, -1].try_into(); - assert!(c.is_err()); + assert_eq!(c, Err(IntoColorError::IntConversion)); } #[test] fn test_array_sum() { let c: Result = [-1, 255, 255].try_into(); - assert!(c.is_err()); + assert_eq!(c, Err(IntoColorError::IntConversion)); } #[test] fn test_array_correct() { @@ -119,17 +140,26 @@ mod tests { #[test] fn test_slice_out_of_range_positive() { let arr = [10000, 256, 1000]; - assert!(Color::try_from(&arr[..]).is_err()); + assert_eq!( + Color::try_from(&arr[..]), + Err(IntoColorError::IntConversion) + ); } #[test] fn test_slice_out_of_range_negative() { let arr = [-256, -1, -10]; - assert!(Color::try_from(&arr[..]).is_err()); + assert_eq!( + Color::try_from(&arr[..]), + Err(IntoColorError::IntConversion) + ); } #[test] fn test_slice_sum() { let arr = [-1, 255, 255]; - assert!(Color::try_from(&arr[..]).is_err()); + assert_eq!( + Color::try_from(&arr[..]), + Err(IntoColorError::IntConversion) + ); } #[test] fn test_slice_correct() { @@ -148,11 +178,11 @@ mod tests { #[test] fn test_slice_excess_length() { let v = vec![0, 0, 0, 0]; - assert!(Color::try_from(&v[..]).is_err()); + assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen)); } #[test] fn test_slice_insufficient_length() { let v = vec![0, 0]; - assert!(Color::try_from(&v[..]).is_err()); + assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen)); } } diff --git a/info.toml b/info.toml index ab4dc933..f5af8840 100644 --- a/info.toml +++ b/info.toml @@ -925,6 +925,27 @@ mode = "test" hint = """ Follow the steps provided right before the `From` implementation""" +[[exercises]] +name = "from_str" +path = "exercises/conversions/from_str.rs" +mode = "test" +hint = """ +The implementation of FromStr should return an Ok with a Person object, +or an Err with an error if the string is not valid. + +This is almost like the `from_into` exercise, but returning errors instead +of falling back to a default value. + +Hint: Look at the test cases to see which error variants to return. + +Another hint: You can use the `map_err` method of `Result` with a function +or a closure to wrap the error from `parse::`. + +Yet another hint: If you would like to propagate errors by using the `?` +operator in your solution, you might want to look at +https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reenter_question_mark.html +""" + [[exercises]] name = "try_from_into" path = "exercises/conversions/try_from_into.rs" @@ -933,17 +954,19 @@ hint = """ Follow the steps provided right before the `TryFrom` implementation. You can also use the example at https://doc.rust-lang.org/std/convert/trait.TryFrom.html -You might want to look back at the exercise errors5 (or its hints) to remind -yourself about how `Box` works. +Hint: Is there an implementation of `TryFrom` in the standard library that +can both do the required integer conversion and check the range of the input? -If you're trying to return a string as an error, note that neither `str` -nor `String` implements `error::Error`. However, there is an implementation -of `From<&str>` for `Box`. This means you can use `.into()` or -the `?` operator to convert your string into the correct error type. +Another hint: Look at the test cases to see which error variants to return. -If you're having trouble with using the `?` operator to convert an error string, -recall that `?` works to convert `Err(something)` into the appropriate error -type for returning from the function.""" +Yet another hint: You can use the `map_err` or `or` methods of `Result` to +convert errors. + +Yet another hint: If you would like to propagate errors by using the `?` +operator in your solution, you might want to look at +https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reenter_question_mark.html + +Challenge: Can you make the `TryFrom` implementations generic over many integer types?""" [[exercises]] name = "as_ref_mut" @@ -951,15 +974,3 @@ path = "exercises/conversions/as_ref_mut.rs" mode = "test" hint = """ Add AsRef as a trait bound to the functions.""" - -[[exercises]] -name = "from_str" -path = "exercises/conversions/from_str.rs" -mode = "test" -hint = """ -The implementation of FromStr should return an Ok with a Person object, -or an Err with an error if the string is not valid. -This is almost like the `try_from_into` exercise. - -If you're having trouble with returning the correct error type, see the -hints for try_from_into.""" From 03131a3d35d9842598150f9da817f7cc26e2669a Mon Sep 17 00:00:00 2001 From: Damian <54457902+dbednar230@users.noreply.github.com> Date: Tue, 24 Aug 2021 03:48:51 -0500 Subject: [PATCH 02/39] fix(quiz1): Fix inconsistent wording (#826) The second test expects the function to return 80 when there is an order of 40 apples, but the current wording implies returning 40 will pass as well --- exercises/quiz1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/quiz1.rs b/exercises/quiz1.rs index 3af1293d..985cd97c 100644 --- a/exercises/quiz1.rs +++ b/exercises/quiz1.rs @@ -4,7 +4,7 @@ // - Functions // Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy -// more than 40 at once, each apple only costs 1! Write a function that calculates +// 40 or more at once, each apple only costs 1! Write a function that calculates // the price of an order of apples given the quantity bought. No hints this time! // I AM NOT DONE From ba8f97f4188e516102852cf2b595774b3b0fb0bc Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 24 Aug 2021 08:49:23 +0000 Subject: [PATCH 03/39] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7313c8e1..6ae6979e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-100-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-101-orange.svg?style=flat-square)](#contributors-) # rustlings πŸ¦€β€οΈ @@ -302,6 +302,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Ivan Nerazumov

πŸ“–
lauralindzey

πŸ“–
Rakshit Sinha

πŸ–‹ +
Damian

πŸ–‹ From 380587f12024a4d62c254d6e1cb08e1ec488caea Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 24 Aug 2021 08:49:24 +0000 Subject: [PATCH 04/39] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 85c66703..22df6a56 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -929,6 +929,15 @@ "contributions": [ "content" ] + }, + { + "login": "dbednar230", + "name": "Damian", + "avatar_url": "https://avatars.githubusercontent.com/u/54457902?v=4", + "profile": "https://github.com/dbednar230", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From 1cd9328a5872f1d6a95b02824e1af33a423c047a Mon Sep 17 00:00:00 2001 From: Ben Armstead Date: Tue, 24 Aug 2021 12:06:30 +0000 Subject: [PATCH 05/39] fix(cli): remove unnecessary borrows (#829) * Update dependencies * Format better and remove unnecessary borrows --- Cargo.lock | 114 ++++++++++++++++++++++++------------------------ src/exercise.rs | 2 +- src/main.rs | 2 +- src/verify.rs | 16 +++---- 4 files changed, 68 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d291c169..57b211be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,19 +1,21 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aho-corasick" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] [[package]] name = "argh" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91792f088f87cdc7a2cfb1d617fa5ea18d7f1dc22ef0e1b5f82f3157cdc522be" +checksum = "2e7317a549bc17c5278d9e72bb6e62c6aa801ac2567048e39ebc1c194249323e" dependencies = [ "argh_derive", "argh_shared", @@ -21,9 +23,9 @@ dependencies = [ [[package]] name = "argh_derive" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4eb0c0c120ad477412dc95a4ce31e38f2113e46bd13511253f79196ca68b067" +checksum = "60949c42375351e9442e354434b0cba2ac402c1237edf673cac3a4bf983b8d3c" dependencies = [ "argh_shared", "heck", @@ -34,9 +36,9 @@ dependencies = [ [[package]] name = "argh_shared" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "781f336cc9826dbaddb9754cb5db61e64cab4f69668bd19dcc4a0394a86f4cb1" +checksum = "8a61eb019cb8f415d162cb9f12130ee6bbe9168b7d953c17f4ad049e4051ca00" [[package]] name = "assert_cmd" @@ -69,9 +71,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cfg-if" @@ -156,9 +158,9 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" dependencies = [ "cfg-if 1.0.0", "libc", @@ -218,18 +220,18 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "heck" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -269,9 +271,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" dependencies = [ "cfg-if 1.0.0", ] @@ -287,9 +289,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "kernel32-sys" @@ -315,15 +317,15 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" +checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5" [[package]] name = "lock_api" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" dependencies = [ "scopeguard", ] @@ -339,9 +341,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.3.4" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "mio" @@ -405,9 +407,9 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "notify" -version = "4.0.16" +version = "4.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2599080e87c9bd051ddb11b10074f4da7b1223298df65d4c2ec5bcf309af1533" +checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" dependencies = [ "bitflags", "filetime", @@ -466,9 +468,9 @@ dependencies = [ [[package]] name = "predicates" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb433456c1a57cc93554dea3ce40b4c19c4057e41c55d4a0f3d84ea71c325aa" +checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df" dependencies = [ "difference", "float-cmp", @@ -485,9 +487,9 @@ checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451" [[package]] name = "predicates-tree" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f553275e5721409451eb85e15fd9a860a6e5ab4496eb215987502b5f5391f2" +checksum = "d7dd0fd014130206c9352efbdc92be592751b2b9274dff685348341082c6ea3d" dependencies = [ "predicates-core", "treeline", @@ -495,9 +497,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" dependencies = [ "unicode-xid", ] @@ -513,18 +515,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.6" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.4.6" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", @@ -533,9 +535,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.23" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rustlings" @@ -576,18 +578,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.125" +version = "1.0.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "d1f72836d2aa753853178eda473a3b9d8e4eefdaf20523b919677e6de489f8f1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "e57ae87ad533d9a56427558b516d0adac283614e347abf85b0dc0cbbf0a249f3" dependencies = [ "proc-macro2", "quote", @@ -596,9 +598,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" dependencies = [ "itoa", "ryu", @@ -607,9 +609,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" [[package]] name = "smallvec" @@ -619,9 +621,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.70" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883" +checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7" dependencies = [ "proc-macro2", "quote", @@ -630,9 +632,9 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ca8ced750734db02076f44132d802af0b33b09942331f4459dde8636fd2406" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" dependencies = [ "libc", "winapi 0.3.9", @@ -664,9 +666,9 @@ checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" @@ -676,9 +678,9 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "walkdir" diff --git a/src/exercise.rs b/src/exercise.rs index d934cfd3..53457ace 100644 --- a/src/exercise.rs +++ b/src/exercise.rs @@ -162,7 +162,7 @@ path = "{}.rs""#, if cmd.status.success() { Ok(CompiledExercise { - exercise: &self, + exercise: self, _handle: FileHandle, }) } else { diff --git a/src/main.rs b/src/main.rs index c8ebc68b..1e343478 100644 --- a/src/main.rs +++ b/src/main.rs @@ -203,7 +203,7 @@ fn main() { Subcommands::Run(subargs) => { let exercise = find_exercise(&subargs.name, &exercises); - run(&exercise, verbose).unwrap_or_else(|_| std::process::exit(1)); + run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1)); } Subcommands::Hint(subargs) => { diff --git a/src/verify.rs b/src/verify.rs index b98598a8..fd59fa51 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -14,9 +14,9 @@ pub fn verify<'a>( ) -> Result<(), &'a Exercise> { for exercise in start_at { let compile_result = match exercise.mode { - Mode::Test => compile_and_test(&exercise, RunMode::Interactive, verbose), - Mode::Compile => compile_and_run_interactively(&exercise), - Mode::Clippy => compile_only(&exercise), + Mode::Test => compile_and_test(exercise, RunMode::Interactive, verbose), + Mode::Compile => compile_and_run_interactively(exercise), + Mode::Clippy => compile_only(exercise), }; if !compile_result.unwrap_or(false) { return Err(exercise); @@ -42,11 +42,11 @@ fn compile_only(exercise: &Exercise) -> Result { progress_bar.set_message(format!("Compiling {}...", exercise).as_str()); progress_bar.enable_steady_tick(100); - let _ = compile(&exercise, &progress_bar)?; + let _ = compile(exercise, &progress_bar)?; progress_bar.finish_and_clear(); success!("Successfully compiled {}!", exercise); - Ok(prompt_for_completion(&exercise, None)) + Ok(prompt_for_completion(exercise, None)) } // Compile the given Exercise and run the resulting binary in an interactive mode @@ -55,7 +55,7 @@ fn compile_and_run_interactively(exercise: &Exercise) -> Result { progress_bar.set_message(format!("Compiling {}...", exercise).as_str()); progress_bar.enable_steady_tick(100); - let compilation = compile(&exercise, &progress_bar)?; + let compilation = compile(exercise, &progress_bar)?; progress_bar.set_message(format!("Running {}...", exercise).as_str()); let result = compilation.run(); @@ -73,7 +73,7 @@ fn compile_and_run_interactively(exercise: &Exercise) -> Result { success!("Successfully ran {}!", exercise); - Ok(prompt_for_completion(&exercise, Some(output.stdout))) + Ok(prompt_for_completion(exercise, Some(output.stdout))) } // Compile the given Exercise as a test harness and display @@ -94,7 +94,7 @@ fn compile_and_test(exercise: &Exercise, run_mode: RunMode, verbose: bool) -> Re } success!("Successfully tested {}", &exercise); if let RunMode::Interactive = run_mode { - Ok(prompt_for_completion(&exercise, None)) + Ok(prompt_for_completion(exercise, None)) } else { Ok(true) } From 2f0ff258b1c3780971d9b7896d8ede7848fefcdb Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 24 Aug 2021 12:06:44 +0000 Subject: [PATCH 06/39] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ae6979e..c867258c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-101-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-102-orange.svg?style=flat-square)](#contributors-) # rustlings πŸ¦€β€οΈ @@ -303,6 +303,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
lauralindzey

πŸ“–
Rakshit Sinha

πŸ–‹
Damian

πŸ–‹ +
Ben Armstead

πŸ’» From a64dbdcc043ae907c003ff940b43f0315283899d Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 24 Aug 2021 12:06:45 +0000 Subject: [PATCH 07/39] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 22df6a56..7816a0b8 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -938,6 +938,15 @@ "contributions": [ "content" ] + }, + { + "login": "benarmstead", + "name": "Ben Armstead", + "avatar_url": "https://avatars.githubusercontent.com/u/70973680?v=4", + "profile": "https://benarmstead.co.uk", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 8, From 96fc3017642b1b4b224390320111c6e305c736a3 Mon Sep 17 00:00:00 2001 From: diannasoriel Date: Thu, 26 Aug 2021 10:30:18 +0200 Subject: [PATCH 08/39] chore(quiz1): revert wording --- exercises/quiz1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/quiz1.rs b/exercises/quiz1.rs index 985cd97c..3af1293d 100644 --- a/exercises/quiz1.rs +++ b/exercises/quiz1.rs @@ -4,7 +4,7 @@ // - Functions // Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy -// 40 or more at once, each apple only costs 1! Write a function that calculates +// more than 40 at once, each apple only costs 1! Write a function that calculates // the price of an order of apples given the quantity bought. No hints this time! // I AM NOT DONE From dfd2fab4f33d1bf59e2e5ee03123c0c9a67a9481 Mon Sep 17 00:00:00 2001 From: anuk909 <34924662+anuk909@users.noreply.github.com> Date: Fri, 3 Sep 2021 11:41:12 +0300 Subject: [PATCH 09/39] feat(modules): update exercises, add modules3 (#822) Co-authored-by: diannasoriel --- exercises/README.md | 2 +- exercises/modules/README.md | 2 +- exercises/modules/modules1.rs | 6 ++++++ exercises/modules/modules2.rs | 8 ++++++-- exercises/modules/modules3.rs | 18 ++++++++++++++++++ info.toml | 18 +++++++++++++----- 6 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 exercises/modules/modules3.rs diff --git a/exercises/README.md b/exercises/README.md index eebbd0bb..73754db5 100644 --- a/exercises/README.md +++ b/exercises/README.md @@ -9,7 +9,7 @@ | primitive_types | Β§4.3 | | structs | Β§5.1 | | enums | Β§6 | -| modules | Β§7.2 | +| modules | Β§7 | | collections | Β§8.1, Β§8.3 | | strings | Β§8.2 | | error_handling | Β§9 | diff --git a/exercises/modules/README.md b/exercises/modules/README.md index 6582b000..3dc8a482 100644 --- a/exercises/modules/README.md +++ b/exercises/modules/README.md @@ -4,4 +4,4 @@ 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-02-defining-modules-to-control-scope-and-privacy.html) +- [The Module System](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html) diff --git a/exercises/modules/modules1.rs b/exercises/modules/modules1.rs index 812dfeef..1a2bd0dd 100644 --- a/exercises/modules/modules1.rs +++ b/exercises/modules/modules1.rs @@ -4,7 +4,13 @@ // I AM NOT DONE mod sausage_factory { + // Don't let anybody outside of this module see this! + fn get_secret_recipe() -> String { + String::from("Ginger") + } + fn make_sausage() { + get_secret_recipe(); println!("sausage!"); } } diff --git a/exercises/modules/modules2.rs b/exercises/modules/modules2.rs index fde439d1..687bb788 100644 --- a/exercises/modules/modules2.rs +++ b/exercises/modules/modules2.rs @@ -1,11 +1,15 @@ // modules2.rs +// You can bring module paths into scopes and provide new names for them with the +// 'use' and 'as' keywords. Fix these 'use' statments to make the code compile. // Make me compile! Execute `rustlings hint modules2` for hints :) // I AM NOT DONE mod delicious_snacks { - use self::fruits::PEAR as fruit; - use self::veggies::CUCUMBER as veggie; + + // TODO: Fix these use statments + use self::fruits::PEAR as ??? + use self::veggies::CUCUMBER as ??? mod fruits { pub const PEAR: &'static str = "Pear"; diff --git a/exercises/modules/modules3.rs b/exercises/modules/modules3.rs new file mode 100644 index 00000000..8eed77df --- /dev/null +++ b/exercises/modules/modules3.rs @@ -0,0 +1,18 @@ +// 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! +// Make me compile! Execute `rustlings hint modules3` for hints :) + +// I AM NOT DONE + +// TODO: Complete this use statement +use ??? + +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/info.toml b/info.toml index d5008ede..0f68d059 100644 --- a/info.toml +++ b/info.toml @@ -362,11 +362,19 @@ name = "modules2" path = "exercises/modules/modules2.rs" mode = "compile" hint = """ -The delicious_snacks module is trying to present an external -interface (the `fruit` and `veggie` constants) that is different than -its internal structure (the `fruits` and `veggies` modules and -associated constants). It's almost there except for one keyword missing for -each constant.""" +The delicious_snacks module is trying to present an external interface that is +different than its internal structure (the `fruits` and `veggies` modules and +associated constants). Complete the `use` statemants to fit the uses in main and +find the one keyword missing for both constants.""" + +[[exercises]] +name = "modules3" +path = "exercises/modules/modules3.rs" +mode = "compile" +hint = """ +UNIX_EPOCH and SystemTime are declared in the std::time module. Add a use statement +for these two to bring them into scope. You can use nested paths or the glob +operator to bring these two in using only one line.""" # COLLECTIONS From 5423f1be29abc97a5659cac05a819a36d62182f5 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 3 Sep 2021 08:41:42 +0000 Subject: [PATCH 10/39] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c867258c..608bba9b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-102-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-103-orange.svg?style=flat-square)](#contributors-) # rustlings πŸ¦€β€οΈ @@ -304,6 +304,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Rakshit Sinha

πŸ–‹
Damian

πŸ–‹
Ben Armstead

πŸ’» +
anuk909

πŸ–‹ πŸ’» From 44d8047249bc4c32ccc1cbc5de848caea0df8c2f Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 3 Sep 2021 08:41:43 +0000 Subject: [PATCH 11/39] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 7816a0b8..03e8dd1c 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -947,6 +947,16 @@ "contributions": [ "code" ] + }, + { + "login": "anuk909", + "name": "anuk909", + "avatar_url": "https://avatars.githubusercontent.com/u/34924662?v=4", + "profile": "https://github.com/anuk909", + "contributions": [ + "content", + "code" + ] } ], "contributorsPerLine": 8, From 1c3beb0a59178c950dc05fe8ee2346b017429ae0 Mon Sep 17 00:00:00 2001 From: granddaifuku <49578068+granddaifuku@users.noreply.github.com> Date: Mon, 6 Sep 2021 23:32:39 +0900 Subject: [PATCH 12/39] fix(modules2): fix typo (#835) --- exercises/modules/modules2.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/modules/modules2.rs b/exercises/modules/modules2.rs index 687bb788..87f0c458 100644 --- a/exercises/modules/modules2.rs +++ b/exercises/modules/modules2.rs @@ -1,13 +1,13 @@ // modules2.rs // You can bring module paths into scopes and provide new names for them with the -// 'use' and 'as' keywords. Fix these 'use' statments to make the code compile. +// 'use' and 'as' keywords. Fix these 'use' statements to make the code compile. // Make me compile! Execute `rustlings hint modules2` for hints :) // I AM NOT DONE mod delicious_snacks { - // TODO: Fix these use statments + // TODO: Fix these use statements use self::fruits::PEAR as ??? use self::veggies::CUCUMBER as ??? From 6c41adef63d777a90bf2a80f0abb5efeb872f52b Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 14:33:03 +0000 Subject: [PATCH 13/39] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 608bba9b..e28a4815 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-103-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-104-orange.svg?style=flat-square)](#contributors-) # rustlings πŸ¦€β€οΈ @@ -305,6 +305,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Damian

πŸ–‹
Ben Armstead

πŸ’»
anuk909

πŸ–‹ πŸ’» +
granddaifuku

πŸ–‹ From de22b132731bd6f9bae6d0a90707d29e9d3bc389 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 14:33:05 +0000 Subject: [PATCH 14/39] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 03e8dd1c..5a932d94 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -957,6 +957,15 @@ "content", "code" ] + }, + { + "login": "granddaifuku", + "name": "granddaifuku", + "avatar_url": "https://avatars.githubusercontent.com/u/49578068?v=4", + "profile": "https://granddaifuku.com/", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From 6efa7d5d1554f8973346e9e15dbd5268306a2458 Mon Sep 17 00:00:00 2001 From: "joakim.kartveit" Date: Thu, 9 Sep 2021 15:53:05 +0200 Subject: [PATCH 15/39] Added ignore for .iml files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 06de8710..253f8f33 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ exercises/clippy/Cargo.toml exercises/clippy/Cargo.lock .idea .vscode +*.iml From a7dc080b95e49146fbaafe6922a6de2f8cb1582a Mon Sep 17 00:00:00 2001 From: ana Date: Tue, 21 Sep 2021 10:36:11 +0200 Subject: [PATCH 16/39] feat: add more watch commands Includes: - quit, to quit the shell instead of having to press Cmd/Ctrl-C or Cmd/Ctrl-D - help, to display an overview of all the commands available in watch mode. Closes #842. --- src/main.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 1e343478..06b41770 100644 --- a/src/main.rs +++ b/src/main.rs @@ -264,7 +264,7 @@ fn main() { fn spawn_watch_shell(failed_exercise_hint: &Arc>>) { let failed_exercise_hint = Arc::clone(failed_exercise_hint); - println!("Type 'hint' or open the corresponding README.md file to get help or type 'clear' to clear the screen."); + println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here."); thread::spawn(move || loop { let mut input = String::new(); match io::stdin().read_line(&mut input) { @@ -276,6 +276,18 @@ fn spawn_watch_shell(failed_exercise_hint: &Arc>>) { } } else if input.eq("clear") { println!("\x1B[2J\x1B[1;1H"); + } else if input.eq("quit") { + println!("Bye!"); + std::process::exit(0); + } else if input.eq("help") { + println!("Commands available to you in watch mode:"); + println!(" hint - prints the current exercise's hint"); + println!(" clear - clears the screen"); + println!(" quit - quits watch mode"); + println!(" help - displays this help message"); + println!(""); + println!("Watch mode automatically re-evaluates the current exercise"); + println!("when you edit a file's contents.") } else { println!("unknown command: {}", input); } From 0a11bad71402b5403143d642f439f57931278c07 Mon Sep 17 00:00:00 2001 From: Weilet <32561597+Weilet@users.noreply.github.com> Date: Tue, 21 Sep 2021 16:43:44 +0800 Subject: [PATCH 17/39] feat(quiz1): add default function name in comment (#838) --- exercises/quiz1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/quiz1.rs b/exercises/quiz1.rs index 3af1293d..b13b9284 100644 --- a/exercises/quiz1.rs +++ b/exercises/quiz1.rs @@ -10,7 +10,7 @@ // I AM NOT DONE // Put your function here! -// fn ..... { +// fn calculate_apple_price { // Don't modify this function! #[test] From fe726f5bcafd35c56b66c9b17a962b7a5cab5ece Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 21 Sep 2021 08:44:03 +0000 Subject: [PATCH 18/39] docs: update README.md [skip ci] --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e28a4815..af0cbb8f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-104-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-105-orange.svg?style=flat-square)](#contributors-) # rustlings πŸ¦€β€οΈ @@ -307,6 +307,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
anuk909

πŸ–‹ πŸ’»
granddaifuku

πŸ–‹ + +
Weilet

πŸ–‹ + From 9ddd4ca33a4cb2a6b02b03a574682c92de5d7253 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 21 Sep 2021 08:44:04 +0000 Subject: [PATCH 19/39] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 5a932d94..8811aef5 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -966,6 +966,15 @@ "contributions": [ "content" ] + }, + { + "login": "Weilet", + "name": "Weilet", + "avatar_url": "https://avatars.githubusercontent.com/u/32561597?v=4", + "profile": "https://weilet.me", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From 06d5c0973a3dffa3c6c6f70acb775d4c6630323c Mon Sep 17 00:00:00 2001 From: LIU JIE Date: Tue, 21 Sep 2021 17:50:15 +0800 Subject: [PATCH 20/39] fix(cli): typo in exercise.rs (#848) --- src/exercise.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/exercise.rs b/src/exercise.rs index 53457ace..ec694df9 100644 --- a/src/exercise.rs +++ b/src/exercise.rs @@ -133,7 +133,7 @@ path = "{}.rs""#, "Failed to write πŸ“Ž Clippy πŸ“Ž Cargo.toml file." }; fs::write(CLIPPY_CARGO_TOML_PATH, cargo_toml).expect(cargo_toml_error_msg); - // To support the ability to run the clipy exercises, build + // To support the ability to run the clippy exercises, build // an executable, in addition to running clippy. With a // compilation failure, this would silently fail. But we expect // clippy to reflect the same failure while compiling later. From 9ef63c0b9b892dd572a76db9c95947e77f82eb3c Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 21 Sep 2021 09:50:31 +0000 Subject: [PATCH 21/39] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index af0cbb8f..94ab10f8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-105-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-106-orange.svg?style=flat-square)](#contributors-) # rustlings πŸ¦€β€οΈ @@ -309,6 +309,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Weilet

πŸ–‹ +
LIU JIE

πŸ–‹ From e9c0ca6be2a73c4dc890f2ebeaaec8aeaad06650 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 21 Sep 2021 09:50:32 +0000 Subject: [PATCH 22/39] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 8811aef5..44d24396 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -975,6 +975,15 @@ "contributions": [ "content" ] + }, + { + "login": "Millione", + "name": "LIU JIE", + "avatar_url": "https://avatars.githubusercontent.com/u/38575932?v=4", + "profile": "https://github.com/Millione", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From 3352b5a4d380df65763b4e64fc9e8938a3adfd80 Mon Sep 17 00:00:00 2001 From: ana Date: Fri, 24 Sep 2021 13:04:30 +0200 Subject: [PATCH 23/39] chore: improve println! usage --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 06b41770..d01a8273 100644 --- a/src/main.rs +++ b/src/main.rs @@ -285,7 +285,7 @@ fn spawn_watch_shell(failed_exercise_hint: &Arc>>) { println!(" clear - clears the screen"); println!(" quit - quits watch mode"); println!(" help - displays this help message"); - println!(""); + println!(); println!("Watch mode automatically re-evaluates the current exercise"); println!("when you edit a file's contents.") } else { From 1caef0b43494c8b8cdd6c9260147e70d510f1aca Mon Sep 17 00:00:00 2001 From: Antoine Busch Date: Tue, 14 Sep 2021 20:34:40 +1000 Subject: [PATCH 24/39] feat: Add "quit" command to `rustlings watch` closes: #842 --- src/main.rs | 122 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 50 deletions(-) diff --git a/src/main.rs b/src/main.rs index d01a8273..30096dfe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,8 @@ use std::fs; use std::io::{self, prelude::*}; use std::path::Path; use std::process::{Command, Stdio}; -use std::sync::mpsc::channel; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc::{RecvTimeoutError, channel}; use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; @@ -217,52 +218,60 @@ fn main() { } Subcommands::Watch(_subargs) => { - if let Err(e) = watch(&exercises, verbose) { - println!( - "Error: Could not watch your progress. Error message was {:?}.", - e - ); - println!("Most likely you've run out of disk space or your 'inotify limit' has been reached."); - std::process::exit(1); + match watch(&exercises, verbose) { + Err(e) => { + println!( + "Error: Could not watch your progress. Error message was {:?}.", + e + ); + println!("Most likely you've run out of disk space or your 'inotify limit' has been reached."); + std::process::exit(1); + } + Ok(WatchStatus::Finished) => { + println!( + "{emoji} All exercises completed! {emoji}", + emoji = Emoji("πŸŽ‰", "β˜…") + ); + println!(); + println!("+----------------------------------------------------+"); + println!("| You made it to the Fe-nish line! |"); + println!("+-------------------------- ------------------------+"); + println!(" \\/ "); + println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); + println!(" β–’β–’β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–’β–’ "); + println!(" β–’β–’β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–’β–’ "); + println!(" β–‘β–‘β–’β–’β–’β–’β–‘β–‘β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–‘β–‘β–’β–’β–’β–’ "); + println!(" β–“β–“β–“β–“β–“β–“β–“β–“ β–“β–“ β–“β–“β–ˆβ–ˆ β–“β–“ β–“β–“β–ˆβ–ˆ β–“β–“ β–“β–“β–“β–“β–“β–“β–“β–“ "); + println!(" β–’β–’β–’β–’ β–’β–’ β–ˆβ–ˆβ–ˆβ–ˆ β–’β–’ β–ˆβ–ˆβ–ˆβ–ˆ β–’β–’β–‘β–‘ β–’β–’β–’β–’ "); + println!(" β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’ "); + println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–“β–“β–“β–“β–“β–“β–’β–’β–’β–’β–’β–’β–’β–’β–“β–“β–’β–’β–“β–“β–’β–’β–’β–’β–’β–’β–’β–’ "); + println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ "); + println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ "); + println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); + println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); + println!(" β–’β–’ β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ β–’β–’ "); + println!(" β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ "); + println!(" β–’β–’ β–’β–’ β–’β–’ β–’β–’ "); + println!(); + println!("We hope you enjoyed learning about the various aspects of Rust!"); + println!( + "If you noticed any issues, please don't hesitate to report them to our repo." + ); + println!("You can also contribute your own exercises to help the greater community!"); + println!(); + println!("Before reporting an issue or contributing, please read our guidelines:"); + println!("https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md"); + } + Ok(WatchStatus::Unfinished) => { + println!("We hope you're enjoying learning about Rust!"); + println!("If you want to continue working on the exercises at a later point, you can simply run `rustlings watch` again"); + } } - println!( - "{emoji} All exercises completed! {emoji}", - emoji = Emoji("πŸŽ‰", "β˜…") - ); - println!(); - println!("+----------------------------------------------------+"); - println!("| You made it to the Fe-nish line! |"); - println!("+-------------------------- ------------------------+"); - println!(" \\/ "); - println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); - println!(" β–’β–’β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–’β–’ "); - println!(" β–’β–’β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–’β–’ "); - println!(" β–‘β–‘β–’β–’β–’β–’β–‘β–‘β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–‘β–‘β–’β–’β–’β–’ "); - println!(" β–“β–“β–“β–“β–“β–“β–“β–“ β–“β–“ β–“β–“β–ˆβ–ˆ β–“β–“ β–“β–“β–ˆβ–ˆ β–“β–“ β–“β–“β–“β–“β–“β–“β–“β–“ "); - println!(" β–’β–’β–’β–’ β–’β–’ β–ˆβ–ˆβ–ˆβ–ˆ β–’β–’ β–ˆβ–ˆβ–ˆβ–ˆ β–’β–’β–‘β–‘ β–’β–’β–’β–’ "); - println!(" β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’ "); - println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–“β–“β–“β–“β–“β–“β–’β–’β–’β–’β–’β–’β–’β–’β–“β–“β–’β–’β–“β–“β–’β–’β–’β–’β–’β–’β–’β–’ "); - println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ "); - println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ "); - println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); - println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); - println!(" β–’β–’ β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ β–’β–’ "); - println!(" β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ "); - println!(" β–’β–’ β–’β–’ β–’β–’ β–’β–’ "); - println!(); - println!("We hope you enjoyed learning about the various aspects of Rust!"); - println!( - "If you noticed any issues, please don't hesitate to report them to our repo." - ); - println!("You can also contribute your own exercises to help the greater community!"); - println!(); - println!("Before reporting an issue or contributing, please read our guidelines:"); - println!("https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md"); } } } -fn spawn_watch_shell(failed_exercise_hint: &Arc>>) { +fn spawn_watch_shell(failed_exercise_hint: &Arc>>, should_quit: Arc) { let failed_exercise_hint = Arc::clone(failed_exercise_hint); println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here."); thread::spawn(move || loop { @@ -270,15 +279,15 @@ fn spawn_watch_shell(failed_exercise_hint: &Arc>>) { match io::stdin().read_line(&mut input) { Ok(_) => { let input = input.trim(); - if input.eq("hint") { + if input == "hint" { if let Some(hint) = &*failed_exercise_hint.lock().unwrap() { println!("{}", hint); } - } else if input.eq("clear") { + } else if input == "clear" { println!("\x1B[2J\x1B[1;1H"); } else if input.eq("quit") { + should_quit.store(true, Ordering::SeqCst); println!("Bye!"); - std::process::exit(0); } else if input.eq("help") { println!("Commands available to you in watch mode:"); println!(" hint - prints the current exercise's hint"); @@ -318,7 +327,12 @@ fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise { } } -fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> { +enum WatchStatus { + Finished, + Unfinished, +} + +fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result { /* Clears the terminal with an ANSI escape code. Works in UNIX and newer Windows terminals. */ fn clear_screen() { @@ -326,6 +340,7 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> { } let (tx, rx) = channel(); + let should_quit = Arc::new(AtomicBool::new(false)); let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?; watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?; @@ -334,12 +349,12 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> { let to_owned_hint = |t: &Exercise| t.hint.to_owned(); let failed_exercise_hint = match verify(exercises.iter(), verbose) { - Ok(_) => return Ok(()), + Ok(_) => return Ok(WatchStatus::Finished), Err(exercise) => Arc::new(Mutex::new(Some(to_owned_hint(exercise)))), }; - spawn_watch_shell(&failed_exercise_hint); + spawn_watch_shell(&failed_exercise_hint, Arc::clone(&should_quit)); loop { - match rx.recv() { + match rx.recv_timeout(Duration::from_secs(1)) { Ok(event) => match event { DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => { if b.extension() == Some(OsStr::new("rs")) && b.exists() { @@ -355,7 +370,7 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> { ); clear_screen(); match verify(pending_exercises, verbose) { - Ok(_) => return Ok(()), + Ok(_) => return Ok(WatchStatus::Finished), Err(exercise) => { let mut failed_exercise_hint = failed_exercise_hint.lock().unwrap(); *failed_exercise_hint = Some(to_owned_hint(exercise)); @@ -365,8 +380,15 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> { } _ => {} }, + Err(RecvTimeoutError::Timeout) => { + // the timeout expired, just check the `should_quit` variable below then loop again + } Err(e) => println!("watch error: {:?}", e), } + // Check if we need to exit + if should_quit.load(Ordering::SeqCst) { + return Ok(WatchStatus::Unfinished); + } } } From c4b59aa593fc4ae952f69133068cb8f8f5ac0866 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 25 Sep 2021 08:47:55 +0000 Subject: [PATCH 25/39] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 94ab10f8..8435a107 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-106-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-107-orange.svg?style=flat-square)](#contributors-) # rustlings πŸ¦€β€οΈ @@ -310,6 +310,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Weilet

πŸ–‹
LIU JIE

πŸ–‹ +
Antoine BΓΌsch

πŸ’» From a1b9c50f36513ce8f8ba26dfdaec2bb427fffeb6 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 25 Sep 2021 08:47:56 +0000 Subject: [PATCH 26/39] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 44d24396..345a7ec9 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -984,6 +984,15 @@ "contributions": [ "content" ] + }, + { + "login": "abusch", + "name": "Antoine BΓΌsch", + "avatar_url": "https://avatars.githubusercontent.com/u/506344?v=4", + "profile": "https://github.com/abusch", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 8, From d75759e829fdcd64ef071cf4b6eae2a011a7718b Mon Sep 17 00:00:00 2001 From: frogtd <31412003+frogtd@users.noreply.github.com> Date: Sat, 25 Sep 2021 04:52:18 -0400 Subject: [PATCH 27/39] fix(move_semantics5): change &mut *y to &mut x (#814) Instead of having to explain why ```rs let mut x = 100; let y = &mut x; let mut z_owned = *y; let z = &mut z_owned; *y += 100; *z += 1000; ``` and ```rs let mut x = 100; let y = &mut x; let z = &mut *y; *y += 100; *z += 1000; ``` are different, you still get the point across about having only one mutable reference. As it stands, this exercise does too much (dereferencing and having only one mutable reference), and by doing so confuses people. Example of someone being confused by this: --- exercises/move_semantics/move_semantics5.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/move_semantics/move_semantics5.rs b/exercises/move_semantics/move_semantics5.rs index 5449e951..1afe16c5 100644 --- a/exercises/move_semantics/move_semantics5.rs +++ b/exercises/move_semantics/move_semantics5.rs @@ -8,7 +8,7 @@ fn main() { let mut x = 100; let y = &mut x; - let z = &mut *y; + let z = &mut x; *y += 100; *z += 1000; assert_eq!(x, 1200); From e106d7a4f4d375fd8648cde25e4e7a1c4c6bdeac Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 25 Sep 2021 08:53:04 +0000 Subject: [PATCH 28/39] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8435a107..ac1d84d3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-107-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-108-orange.svg?style=flat-square)](#contributors-) # rustlings πŸ¦€β€οΈ @@ -311,6 +311,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Weilet

πŸ–‹
LIU JIE

πŸ–‹
Antoine BΓΌsch

πŸ’» +
frogtd

πŸ–‹ From ab5ecbee7a8fab44867cd18ab030dc9de7185360 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 25 Sep 2021 08:53:05 +0000 Subject: [PATCH 29/39] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 345a7ec9..d18743c2 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -993,6 +993,15 @@ "contributions": [ "code" ] + }, + { + "login": "frogtd", + "name": "frogtd", + "avatar_url": "https://avatars.githubusercontent.com/u/31412003?v=4", + "profile": "https://frogtd.com/", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From 882d535ba8628d5e0b37e8664b3e2f26260b2671 Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Wed, 9 Jun 2021 23:26:10 -0500 Subject: [PATCH 30/39] feat: add advanced_errs1 New section and exercise to demonstrate the `From` trait for errors and its usefulness with the `?` operator. --- exercises/advanced_errors/advanced_errs1.rs | 98 +++++++++++++++++++++ info.toml | 20 +++++ 2 files changed, 118 insertions(+) create mode 100644 exercises/advanced_errors/advanced_errs1.rs diff --git a/exercises/advanced_errors/advanced_errs1.rs b/exercises/advanced_errors/advanced_errs1.rs new file mode 100644 index 00000000..4bc7b635 --- /dev/null +++ b/exercises/advanced_errors/advanced_errs1.rs @@ -0,0 +1,98 @@ +// advanced_errs1.rs + +// Remember back in errors6, we had multiple mapping functions so that we +// could translate lower-level errors into our custom error type using +// `map_err()`? What if we could use the `?` operator directly instead? + +// Make this code compile! Execute `rustlings hint advanced_errs1` for +// hints :) + +// I AM NOT DONE + +use std::num::ParseIntError; +use std::str::FromStr; + +// This is a custom error type that we will be using in the `FromStr` +// implementation. +#[derive(PartialEq, Debug)] +enum ParsePosNonzeroError { + Creation(CreationError), + ParseInt(ParseIntError), +} + +impl From for ParsePosNonzeroError { + fn from(e: CreationError) -> Self { + // TODO: complete this implementation so that the `?` operator will + // work for `CreationError` + } +} + +// TODO: implement another instance of the `From` trait here so that the +// `?` operator will work in the other place in the `FromStr` +// implementation below. + +// Don't change anything below this line. + +impl FromStr for PositiveNonzeroInteger { + type Err = ParsePosNonzeroError; + fn from_str(s: &str) -> Result { + let x: i64 = s.parse()?; + Ok(PositiveNonzeroInteger::new(x)?) + } +} + +#[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!( + PositiveNonzeroInteger::from_str("not a number"), + Err(ParsePosNonzeroError::ParseInt(_)) + )); + } + + #[test] + fn test_negative() { + assert_eq!( + PositiveNonzeroInteger::from_str("-555"), + Err(ParsePosNonzeroError::Creation(CreationError::Negative)) + ); + } + + #[test] + fn test_zero() { + assert_eq!( + PositiveNonzeroInteger::from_str("0"), + Err(ParsePosNonzeroError::Creation(CreationError::Zero)) + ); + } + + #[test] + fn test_positive() { + let x = PositiveNonzeroInteger::new(42); + assert!(x.is_ok()); + assert_eq!(PositiveNonzeroInteger::from_str("42"), Ok(x.unwrap())); + } +} diff --git a/info.toml b/info.toml index f5af8840..8e24b7db 100644 --- a/info.toml +++ b/info.toml @@ -974,3 +974,23 @@ path = "exercises/conversions/as_ref_mut.rs" mode = "test" hint = """ Add AsRef as a trait bound to the functions.""" + +# ADVANCED ERRORS + +[[exercises]] +name = "advanced_errs1" +path = "exercises/advanced_errors/advanced_errs1.rs" +mode = "test" +hint = """ +This exercise uses an updated version of the code in errors6. The parsing +code is now in an implementation of the `FromStr` trait. Note that the +parsing code uses `?` directly, without any calls to `map_err()`. There is +one partial implementation of the `From` trait example that you should +complete. + +Details: The `?` operator calls `From::from()` on the error type to convert +it to the error type of the return type of the surrounding function. + +Hint: You will need to write another implementation of `From` that has a +different input type. +""" From abd6b70c72dc6426752ff41f09160b839e5c449e Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Fri, 25 Jun 2021 16:52:10 -0500 Subject: [PATCH 31/39] feat: add advanced_errs2 New exercise to demonstrate traits that make it easier for other code to consume our custom error types. --- exercises/advanced_errors/advanced_errs2.rs | 203 ++++++++++++++++++++ info.toml | 32 +++ 2 files changed, 235 insertions(+) create mode 100644 exercises/advanced_errors/advanced_errs2.rs diff --git a/exercises/advanced_errors/advanced_errs2.rs b/exercises/advanced_errors/advanced_errs2.rs new file mode 100644 index 00000000..d9d44d06 --- /dev/null +++ b/exercises/advanced_errors/advanced_errs2.rs @@ -0,0 +1,203 @@ +// advanced_errs2.rs + +// This exercise demonstrates a few traits that are useful for custom error +// types to implement, especially so that other code can consume the custom +// error type more usefully. + +// Make this compile, and make the tests pass! +// Execute `rustlings hint advanced_errs2` for hints. + +// Steps: +// 1. Implement a missing trait so that `main()` will compile. +// 2. Complete the partial implementation of `From` for +// `ParseClimateError`. +// 3. Handle the missing error cases in the `FromStr` implementation for +// `Climate`. +// 4. Complete the partial implementation of `Display` for +// `ParseClimateError`. + +// I AM NOT DONE + +use std::error::Error; +use std::fmt::{self, Display, Formatter}; +use std::num::{ParseFloatError, ParseIntError}; +use std::str::FromStr; + +// This is the custom error type that we will be using for the parser for +// `Climate`. +#[derive(Debug, PartialEq)] +enum ParseClimateError { + Empty, + BadLen, + NoCity, + ParseInt(ParseIntError), + ParseFloat(ParseFloatError), +} + +// This `From` implementation allows the `?` operator to work on +// `ParseIntError` values. +impl From for ParseClimateError { + fn from(e: ParseIntError) -> Self { + Self::ParseInt(e) + } +} + +// This `From` implementation allows the `?` operator to work on +// `ParseFloatError` values. +impl From for ParseClimateError { + fn from(e: ParseFloatError) -> Self { + // TODO: Complete this function + } +} + +// TODO: Implement a missing trait so that `main()` below will compile. It +// is not necessary to implement any methods inside the missing trait. + +// The `Display` trait allows for other code to obtain the error formatted +// as a user-visible string. +impl Display for ParseClimateError { + // TODO: Complete this function so that it produces the correct strings + // for each error variant. + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + // Imports the variants to make the following code more compact. + use ParseClimateError::*; + match self { + NoCity => write!(f, "no city name"), + ParseFloat(e) => write!(f, "error parsing temperature: {}", e), + _ => write!(f, "unhandled error!"), + } + } +} + +#[derive(Debug, PartialEq)] +struct Climate { + city: String, + year: u32, + temp: f32, +} + +// Parser for `Climate`. +// 1. Split the input string into 3 fields: city, year, temp. +// 2. Return an error if the string is empty or has the wrong number of +// fields. +// 3. Return an error if the city name is empty. +// 4. Parse the year as a `u32` and return an error if that fails. +// 5. Parse the temp as a `f32` and return an error if that fails. +// 6. Return an `Ok` value containing the completed `Climate` value. +impl FromStr for Climate { + type Err = ParseClimateError; + // TODO: Complete this function by making it handle the missing error + // cases. + fn from_str(s: &str) -> Result { + let v: Vec<_> = s.split(',').collect(); + let (city, year, temp) = match &v[..] { + [city, year, temp] => (city.to_string(), year, temp), + _ => return Err(ParseClimateError::BadLen), + }; + let year: u32 = year.parse()?; + let temp: f32 = temp.parse()?; + Ok(Climate { city, year, temp }) + } +} + +// Don't change anything below this line (other than to enable ignored +// tests). + +fn main() -> Result<(), Box> { + println!("{:?}", "Hong Kong,1999,25.7".parse::()?); + println!("{:?}", "".parse::()?); + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn test_empty() { + let res = "".parse::(); + assert_eq!(res, Err(ParseClimateError::Empty)); + assert_eq!(res.unwrap_err().to_string(), "empty input"); + } + #[test] + fn test_short() { + let res = "Boston,1991".parse::(); + assert_eq!(res, Err(ParseClimateError::BadLen)); + assert_eq!(res.unwrap_err().to_string(), "incorrect number of fields"); + } + #[test] + fn test_long() { + let res = "Paris,1920,17.2,extra".parse::(); + assert_eq!(res, Err(ParseClimateError::BadLen)); + assert_eq!(res.unwrap_err().to_string(), "incorrect number of fields"); + } + #[test] + fn test_no_city() { + let res = ",1997,20.5".parse::(); + assert_eq!(res, Err(ParseClimateError::NoCity)); + assert_eq!(res.unwrap_err().to_string(), "no city name"); + } + #[test] + fn test_parse_int_neg() { + let res = "Barcelona,-25,22.3".parse::(); + assert!(matches!(res, Err(ParseClimateError::ParseInt(_)))); + let err = res.unwrap_err(); + if let ParseClimateError::ParseInt(ref inner) = err { + assert_eq!( + err.to_string(), + format!("error parsing year: {}", inner.to_string()) + ); + } else { + unreachable!(); + }; + } + #[test] + fn test_parse_int_bad() { + let res = "Beijing,foo,15.0".parse::(); + assert!(matches!(res, Err(ParseClimateError::ParseInt(_)))); + let err = res.unwrap_err(); + if let ParseClimateError::ParseInt(ref inner) = err { + assert_eq!( + err.to_string(), + format!("error parsing year: {}", inner.to_string()) + ); + } else { + unreachable!(); + }; + } + #[test] + fn test_parse_float() { + let res = "Manila,2001,bar".parse::(); + assert!(matches!(res, Err(ParseClimateError::ParseFloat(_)))); + let err = res.unwrap_err(); + if let ParseClimateError::ParseFloat(ref inner) = err { + assert_eq!( + err.to_string(), + format!("error parsing temperature: {}", inner.to_string()) + ); + } else { + unreachable!(); + }; + } + #[test] + fn test_parse_good() { + let res = "Munich,2015,23.1".parse::(); + assert_eq!( + res, + Ok(Climate { + city: "Munich".to_string(), + year: 2015, + temp: 23.1, + }) + ); + } + #[test] + #[ignore] + fn test_downcast() { + let res = "SΓ£o Paulo,-21,28.5".parse::(); + assert!(matches!(res, Err(ParseClimateError::ParseInt(_)))); + let err = res.unwrap_err(); + let inner: Option<&(dyn Error + 'static)> = err.source(); + assert!(inner.is_some()); + assert!(inner.unwrap().is::()); + } +} diff --git a/info.toml b/info.toml index 8e24b7db..1b8c65d2 100644 --- a/info.toml +++ b/info.toml @@ -994,3 +994,35 @@ it to the error type of the return type of the surrounding function. Hint: You will need to write another implementation of `From` that has a different input type. """ + +[[exercises]] +name = "advanced_errs2" +path = "exercises/advanced_errors/advanced_errs2.rs" +mode = "test" +hint = """ +This exercise demonstrates a few traits that are useful for custom error +types to implement. These traits make it easier for other code to consume +the custom error type. + +Follow the steps in the comment near the top of the file. You will have to +supply a missing trait implementation, and complete a few incomplete ones. + +You may find these pages to be helpful references: +https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/define_error_type.html +https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/boxing_errors.html +https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/wrap_error.html + +Hint: What trait must our error type have for `main()` to return the return +type that it returns? + +Another hint: It's not necessary to implement any methods inside the missing +trait. (Some methods have default implementations that are supplied by the +trait.) + +Another hint: Consult the tests to determine which error variants (and which +error message text) to produce for certain error conditions. + +Challenge: There is one test that is marked `#[ignore]`. Can you supply the +missing code that will make it pass? You may want to consult the standard +library documentation for a certain trait for more hints. +""" From d57c1830280b2dbc1b9fe2ac3f48b51add591412 Mon Sep 17 00:00:00 2001 From: ana Date: Sat, 25 Sep 2021 11:23:05 +0200 Subject: [PATCH 32/39] release: 4.6.0 --- CHANGELOG.md | 26 ++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 +- src/main.rs | 109 ++++++++++++++++++++++++++------------------------- 5 files changed, 86 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67b8cdc3..fcc39e42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,29 @@ + +## 4.6.0 (2021-09-25) + + +#### Features + +* add advanced_errs2 ([abd6b70c](https://github.com/rust-lang/rustlings/commit/abd6b70c72dc6426752ff41f09160b839e5c449e)) +* add advanced_errs1 ([882d535b](https://github.com/rust-lang/rustlings/commit/882d535ba8628d5e0b37e8664b3e2f26260b2671)) +* Add a farewell message when quitting `watch` ([1caef0b4](https://github.com/rust-lang/rustlings/commit/1caef0b43494c8b8cdd6c9260147e70d510f1aca)) +* add more watch commands ([a7dc080b](https://github.com/rust-lang/rustlings/commit/a7dc080b95e49146fbaafe6922a6de2f8cb1582a), closes [#842](https://github.com/rust-lang/rustlings/issues/842)) +* **modules:** update exercises, add modules3 (#822) ([dfd2fab4](https://github.com/rust-lang/rustlings/commit/dfd2fab4f33d1bf59e2e5ee03123c0c9a67a9481)) +* **quiz1:** add default function name in comment (#838) ([0a11bad7](https://github.com/rust-lang/rustlings/commit/0a11bad71402b5403143d642f439f57931278c07)) + +#### Bug Fixes + +* Correct small typo in exercises/conversions/from_str.rs ([86cc8529](https://github.com/rust-lang/rustlings/commit/86cc85295ae36948963ae52882e285d7e3e29323)) +* **cli:** typo in exercise.rs (#848) ([06d5c097](https://github.com/rust-lang/rustlings/commit/06d5c0973a3dffa3c6c6f70acb775d4c6630323c)) +* **from_str, try_from_into:** custom error types ([2dc93cad](https://github.com/rust-lang/rustlings/commit/2dc93caddad43821743e4903d89b355df58d7a49)) +* **modules2:** fix typo (#835) ([1c3beb0a](https://github.com/rust-lang/rustlings/commit/1c3beb0a59178c950dc05fe8ee2346b017429ae0)) +* **move_semantics5:** + * change &mut *y to &mut x (#814) ([d75759e8](https://github.com/rust-lang/rustlings/commit/d75759e829fdcd64ef071cf4b6eae2a011a7718b)) + * Clarify instructions ([df25684c](https://github.com/rust-lang/rustlings/commit/df25684cb79f8413915e00b5efef29369849cef1)) +* **quiz1:** Fix inconsistent wording (#826) ([03131a3d](https://github.com/rust-lang/rustlings/commit/03131a3d35d9842598150f9da817f7cc26e2669a)) + + + ## 4.5.0 (2021-07-07) diff --git a/Cargo.lock b/Cargo.lock index 57b211be..e536d1b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -541,7 +541,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rustlings" -version = "4.5.0" +version = "4.6.0" dependencies = [ "argh", "assert_cmd", diff --git a/Cargo.toml b/Cargo.toml index 615a09c3..3b2a85a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustlings" -version = "4.5.0" +version = "4.6.0" authors = ["anastasie ", "Carol (Nichols || Goulding) "] edition = "2018" diff --git a/README.md b/README.md index ac1d84d3..18e0b73a 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,8 @@ When you get a permission denied message then you have to exclude the directory Basically: Clone the repository at the latest tag, run `cargo install`. ```bash -# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 4.5.0) -git clone -b 4.5.0 --depth 1 https://github.com/rust-lang/rustlings +# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 4.6.0) +git clone -b 4.6.0 --depth 1 https://github.com/rust-lang/rustlings cd rustlings cargo install --force --path . ``` diff --git a/src/main.rs b/src/main.rs index 30096dfe..32e7bba2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use std::io::{self, prelude::*}; use std::path::Path; use std::process::{Command, Stdio}; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::mpsc::{RecvTimeoutError, channel}; +use std::sync::mpsc::{channel, RecvTimeoutError}; use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; @@ -24,7 +24,7 @@ mod run; mod verify; // In sync with crate version -const VERSION: &str = "4.5.0"; +const VERSION: &str = "4.6.0"; #[derive(FromArgs, PartialEq, Debug)] /// Rustlings is a collection of small exercises to get you used to writing and reading Rust code @@ -217,61 +217,64 @@ fn main() { verify(&exercises, verbose).unwrap_or_else(|_| std::process::exit(1)); } - Subcommands::Watch(_subargs) => { - match watch(&exercises, verbose) { - Err(e) => { - println!( - "Error: Could not watch your progress. Error message was {:?}.", - e - ); - println!("Most likely you've run out of disk space or your 'inotify limit' has been reached."); - std::process::exit(1); - } - Ok(WatchStatus::Finished) => { - println!( - "{emoji} All exercises completed! {emoji}", - emoji = Emoji("πŸŽ‰", "β˜…") - ); - println!(); - println!("+----------------------------------------------------+"); - println!("| You made it to the Fe-nish line! |"); - println!("+-------------------------- ------------------------+"); - println!(" \\/ "); - println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); - println!(" β–’β–’β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–’β–’ "); - println!(" β–’β–’β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–’β–’ "); - println!(" β–‘β–‘β–’β–’β–’β–’β–‘β–‘β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–‘β–‘β–’β–’β–’β–’ "); - println!(" β–“β–“β–“β–“β–“β–“β–“β–“ β–“β–“ β–“β–“β–ˆβ–ˆ β–“β–“ β–“β–“β–ˆβ–ˆ β–“β–“ β–“β–“β–“β–“β–“β–“β–“β–“ "); - println!(" β–’β–’β–’β–’ β–’β–’ β–ˆβ–ˆβ–ˆβ–ˆ β–’β–’ β–ˆβ–ˆβ–ˆβ–ˆ β–’β–’β–‘β–‘ β–’β–’β–’β–’ "); - println!(" β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’ "); - println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–“β–“β–“β–“β–“β–“β–’β–’β–’β–’β–’β–’β–’β–’β–“β–“β–’β–’β–“β–“β–’β–’β–’β–’β–’β–’β–’β–’ "); - println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ "); - println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ "); - println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); - println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); - println!(" β–’β–’ β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ β–’β–’ "); - println!(" β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ "); - println!(" β–’β–’ β–’β–’ β–’β–’ β–’β–’ "); - println!(); - println!("We hope you enjoyed learning about the various aspects of Rust!"); - println!( - "If you noticed any issues, please don't hesitate to report them to our repo." - ); - println!("You can also contribute your own exercises to help the greater community!"); - println!(); - println!("Before reporting an issue or contributing, please read our guidelines:"); - println!("https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md"); - } - Ok(WatchStatus::Unfinished) => { - println!("We hope you're enjoying learning about Rust!"); - println!("If you want to continue working on the exercises at a later point, you can simply run `rustlings watch` again"); - } + Subcommands::Watch(_subargs) => match watch(&exercises, verbose) { + Err(e) => { + println!( + "Error: Could not watch your progress. Error message was {:?}.", + e + ); + println!("Most likely you've run out of disk space or your 'inotify limit' has been reached."); + std::process::exit(1); } - } + Ok(WatchStatus::Finished) => { + println!( + "{emoji} All exercises completed! {emoji}", + emoji = Emoji("πŸŽ‰", "β˜…") + ); + println!(); + println!("+----------------------------------------------------+"); + println!("| You made it to the Fe-nish line! |"); + println!("+-------------------------- ------------------------+"); + println!(" \\/ "); + println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); + println!(" β–’β–’β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–’β–’ "); + println!(" β–’β–’β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–’β–’ "); + println!(" β–‘β–‘β–’β–’β–’β–’β–‘β–‘β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–‘β–‘β–’β–’β–’β–’ "); + println!(" β–“β–“β–“β–“β–“β–“β–“β–“ β–“β–“ β–“β–“β–ˆβ–ˆ β–“β–“ β–“β–“β–ˆβ–ˆ β–“β–“ β–“β–“β–“β–“β–“β–“β–“β–“ "); + println!(" β–’β–’β–’β–’ β–’β–’ β–ˆβ–ˆβ–ˆβ–ˆ β–’β–’ β–ˆβ–ˆβ–ˆβ–ˆ β–’β–’β–‘β–‘ β–’β–’β–’β–’ "); + println!(" β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’ "); + println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–“β–“β–“β–“β–“β–“β–’β–’β–’β–’β–’β–’β–’β–’β–“β–“β–’β–’β–“β–“β–’β–’β–’β–’β–’β–’β–’β–’ "); + println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ "); + println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ "); + println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); + println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); + println!(" β–’β–’ β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ β–’β–’ "); + println!(" β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ "); + println!(" β–’β–’ β–’β–’ β–’β–’ β–’β–’ "); + println!(); + println!("We hope you enjoyed learning about the various aspects of Rust!"); + println!( + "If you noticed any issues, please don't hesitate to report them to our repo." + ); + println!( + "You can also contribute your own exercises to help the greater community!" + ); + println!(); + println!("Before reporting an issue or contributing, please read our guidelines:"); + println!("https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md"); + } + Ok(WatchStatus::Unfinished) => { + println!("We hope you're enjoying learning about Rust!"); + println!("If you want to continue working on the exercises at a later point, you can simply run `rustlings watch` again"); + } + }, } } -fn spawn_watch_shell(failed_exercise_hint: &Arc>>, should_quit: Arc) { +fn spawn_watch_shell( + failed_exercise_hint: &Arc>>, + should_quit: Arc, +) { let failed_exercise_hint = Arc::clone(failed_exercise_hint); println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here."); thread::spawn(move || loop { From bf33829da240375d086f96267fc2e02fa6b07001 Mon Sep 17 00:00:00 2001 From: Zhenghao Lu <54395432+EmisonLu@users.noreply.github.com> Date: Mon, 27 Sep 2021 16:03:28 +0800 Subject: [PATCH 33/39] fix(structs3): remove redundant 'return' (#852) --- exercises/structs/structs3.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/structs/structs3.rs b/exercises/structs/structs3.rs index a80d0625..b3aa2825 100644 --- a/exercises/structs/structs3.rs +++ b/exercises/structs/structs3.rs @@ -18,11 +18,11 @@ impl Package { if weight_in_grams <= 0 { // Something goes here... } else { - return Package { + Package { sender_country, recipient_country, weight_in_grams, - }; + } } } From fed4fe78bbc0f4a9dbace1a556811a9f506237b6 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 27 Sep 2021 08:03:46 +0000 Subject: [PATCH 34/39] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 18e0b73a..1c3709cc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-108-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-109-orange.svg?style=flat-square)](#contributors-) # rustlings πŸ¦€β€οΈ @@ -312,6 +312,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
LIU JIE

πŸ–‹
Antoine BΓΌsch

πŸ’»
frogtd

πŸ–‹ +
Zhenghao Lu

πŸ–‹ From e3cfaa246dbef9ebea5ca020bdbaf018194b4974 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 27 Sep 2021 08:03:47 +0000 Subject: [PATCH 35/39] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index d18743c2..21089c52 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1002,6 +1002,15 @@ "contributions": [ "content" ] + }, + { + "login": "EmisonLu", + "name": "Zhenghao Lu", + "avatar_url": "https://avatars.githubusercontent.com/u/54395432?v=4", + "profile": "https://github.com/EmisonLu", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From 46c28d5cef3d8446b5a356b19d8dbc725f91a3a0 Mon Sep 17 00:00:00 2001 From: Fredrik Enestad Date: Thu, 30 Sep 2021 10:18:36 +0200 Subject: [PATCH 36/39] fix(move_semantics5): correct typo (#857) --- exercises/move_semantics/move_semantics5.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/move_semantics/move_semantics5.rs b/exercises/move_semantics/move_semantics5.rs index 1afe16c5..c4704f9e 100644 --- a/exercises/move_semantics/move_semantics5.rs +++ b/exercises/move_semantics/move_semantics5.rs @@ -1,5 +1,5 @@ // move_semantics5.rs -// Make me compile only be reordering the lines in `main()`, but without +// Make me compile only by reordering the lines in `main()`, but without // adding, changing or removing any of them. // Execute `rustlings hint move_semantics5` for hints :) From 574bbffe0b11b5426970e4710a2275776690e85e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 30 Sep 2021 08:18:52 +0000 Subject: [PATCH 37/39] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c3709cc..6e5ce3f6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-109-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-110-orange.svg?style=flat-square)](#contributors-) # rustlings πŸ¦€β€οΈ @@ -313,6 +313,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Antoine BΓΌsch

πŸ’»
frogtd

πŸ–‹
Zhenghao Lu

πŸ–‹ +
Fredrik Enestad

πŸ–‹ From ae54c17b6a5ca63705192011d11d371bb51eee97 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 30 Sep 2021 08:18:53 +0000 Subject: [PATCH 38/39] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 21089c52..fe18385f 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1011,6 +1011,15 @@ "contributions": [ "content" ] + }, + { + "login": "fredr", + "name": "Fredrik Enestad", + "avatar_url": "https://avatars.githubusercontent.com/u/762956?v=4", + "profile": "https://soundtrackyourbrand.com", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From 1c0fe3cbcca85f90b3985985b8e265ee872a2ab2 Mon Sep 17 00:00:00 2001 From: rlch Date: Sat, 2 Oct 2021 23:59:23 +1000 Subject: [PATCH 39/39] fix: few spelling mistakes --- info.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info.toml b/info.toml index 21406630..5eece6d7 100644 --- a/info.toml +++ b/info.toml @@ -364,7 +364,7 @@ mode = "compile" hint = """ The delicious_snacks module is trying to present an external interface that is different than its internal structure (the `fruits` and `veggies` modules and -associated constants). Complete the `use` statemants to fit the uses in main and +associated constants). Complete the `use` statements to fit the uses in main and find the one keyword missing for both constants.""" [[exercises]]