From 2dc93caddad43821743e4903d89b355df58d7a49 Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Thu, 24 Jun 2021 21:33:41 -0500 Subject: [PATCH 01/32] 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 a7dc080b95e49146fbaafe6922a6de2f8cb1582a Mon Sep 17 00:00:00 2001 From: ana Date: Tue, 21 Sep 2021 10:36:11 +0200 Subject: [PATCH 02/32] 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 03/32] 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 04/32] 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 05/32] 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 06/32] 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 07/32] 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 08/32] 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 09/32] 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 10/32] 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 11/32] 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 12/32] 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 13/32] 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 14/32] 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 15/32] 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 16/32] 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 17/32] 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 18/32] 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 19/32] 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 20/32] 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 21/32] 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 22/32] 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 23/32] 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 24/32] 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 25/32] 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]] From 1663a16eade6ca646b6ed061735f7982434d530d Mon Sep 17 00:00:00 2001 From: xuesong Date: Mon, 18 Oct 2021 19:57:12 +0800 Subject: [PATCH 26/32] fix(traits1): rename test functions to snake case (#854) Co-authored-by: zhangshaozhi --- exercises/advanced_errors/advanced_errs2.rs | 1 - exercises/traits/traits1.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/exercises/advanced_errors/advanced_errs2.rs b/exercises/advanced_errors/advanced_errs2.rs index d9d44d06..54e669fd 100644 --- a/exercises/advanced_errors/advanced_errs2.rs +++ b/exercises/advanced_errors/advanced_errs2.rs @@ -64,7 +64,6 @@ impl Display for ParseClimateError { match self { NoCity => write!(f, "no city name"), ParseFloat(e) => write!(f, "error parsing temperature: {}", e), - _ => write!(f, "unhandled error!"), } } } diff --git a/exercises/traits/traits1.rs b/exercises/traits/traits1.rs index 2ef9e11b..15e08f24 100644 --- a/exercises/traits/traits1.rs +++ b/exercises/traits/traits1.rs @@ -29,12 +29,12 @@ mod tests { use super::*; #[test] - fn is_FooBar() { + fn is_foo_bar() { assert_eq!(String::from("Foo").append_bar(), String::from("FooBar")); } #[test] - fn is_BarBar() { + fn is_bar_bar() { assert_eq!( String::from("").append_bar().append_bar(), String::from("BarBar") From b24b295d88d0f5598c5b0fe0ff926d29ab3c5828 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 18 Oct 2021 11:57:33 +0000 Subject: [PATCH 27/32] 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 6e5ce3f6..a3ef758d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-110-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-111-orange.svg?style=flat-square)](#contributors-) # rustlings πŸ¦€β€οΈ @@ -314,6 +314,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
frogtd

πŸ–‹
Zhenghao Lu

πŸ–‹
Fredrik Enestad

πŸ–‹ +
xuesong

πŸ–‹ From 71da9068e71ee395a30083dfc516e7dc110a2a8f Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 18 Oct 2021 11:57:34 +0000 Subject: [PATCH 28/32] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index fe18385f..d7c7d465 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1020,6 +1020,15 @@ "contributions": [ "content" ] + }, + { + "login": "xuesongbj", + "name": "xuesong", + "avatar_url": "https://avatars.githubusercontent.com/u/18476085?v=4", + "profile": "http://xuesong.pydevops.com", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From 359f81dd0bf5cc82016c56d374b38bf4de8f5893 Mon Sep 17 00:00:00 2001 From: ana Date: Fri, 29 Oct 2021 14:27:36 +0200 Subject: [PATCH 29/32] chore: upgrade edition to 2021 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3b2a85a7..30032695 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "rustlings" version = "4.6.0" authors = ["anastasie ", "Carol (Nichols || Goulding) "] -edition = "2018" +edition = "2021" [dependencies] argh = "0.1.4" From d1ee2daf14f19105e6db3f9c610f44293d688532 Mon Sep 17 00:00:00 2001 From: Michael Walsh <48160144+MpdWalsh@users.noreply.github.com> Date: Sat, 30 Oct 2021 16:55:58 -0600 Subject: [PATCH 30/32] fix(structs3.rs): assigned value to cents_per_gram in test Intended to simplify the lesson by removing the need to figure out what the value is meant to be based on the tests. Previous commits (https://github.com/rust-lang/rustlings/commit/9ca08b8f2b09366e97896a4a8cf9ff3bb4d54380 and https://github.com/rust-lang/rustlings/commit/114b54cbdb977234b39e5f180d937c14c78bb8b2#diff-ce1c232ff0ddaff909351bb84cb5bff423b5b9e04f21fd4db7ffe443e598e174) removed the mathematical complexity, and I feel this addition is a needed change to further streamline the exercise. --- exercises/structs/structs3.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/structs/structs3.rs b/exercises/structs/structs3.rs index b3aa2825..1a81531c 100644 --- a/exercises/structs/structs3.rs +++ b/exercises/structs/structs3.rs @@ -73,7 +73,7 @@ mod tests { let sender_country = String::from("Spain"); let recipient_country = String::from("Spain"); - let cents_per_gram = ???; + let cents_per_gram = 3; let package = Package::new(sender_country, recipient_country, 1500); From e08b6cf3ef157dd7dc65b920b36723a4c480179c Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 31 Oct 2021 16:25:35 +0000 Subject: [PATCH 31/32] 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 a3ef758d..c0ba6ce9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-111-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-112-orange.svg?style=flat-square)](#contributors-) # rustlings πŸ¦€β€οΈ @@ -315,6 +315,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Zhenghao Lu

πŸ–‹
Fredrik Enestad

πŸ–‹
xuesong

πŸ–‹ +
Michael Walsh

πŸ’» From cb661896a21aa00d46b894cdc4a7632f7569479c Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 31 Oct 2021 16:25:36 +0000 Subject: [PATCH 32/32] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index d7c7d465..cda03778 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1029,6 +1029,15 @@ "contributions": [ "content" ] + }, + { + "login": "MpdWalsh", + "name": "Michael Walsh", + "avatar_url": "https://avatars.githubusercontent.com/u/48160144?v=4", + "profile": "https://github.com/MpdWalsh", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 8,