diff --git a/.all-contributorsrc b/.all-contributorsrc
index 0917089a..9e2f307f 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -1569,6 +1569,141 @@
"contributions": [
"content"
]
+ },
+ {
+ "login": "gasparitiago",
+ "name": "Tiago De Gaspari",
+ "avatar_url": "https://avatars.githubusercontent.com/u/3237254?v=4",
+ "profile": "https://github.com/gasparitiago",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "skaunov",
+ "name": "skaunov",
+ "avatar_url": "https://avatars.githubusercontent.com/u/65976143?v=4",
+ "profile": "https://github.com/skaunov",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "cj81499",
+ "name": "Cal Jacobson",
+ "avatar_url": "https://avatars.githubusercontent.com/u/9152032?v=4",
+ "profile": "http://caljacobson.dev",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "duchonic",
+ "name": "Duchoud Nicolas",
+ "avatar_url": "https://avatars.githubusercontent.com/u/34117620?v=4",
+ "profile": "https://github.com/duchonic",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "gfaugere",
+ "name": "Gaëtan Faugère",
+ "avatar_url": "https://avatars.githubusercontent.com/u/11901979?v=4",
+ "profile": "https://github.com/gfaugere",
+ "contributions": [
+ "tool"
+ ]
+ },
+ {
+ "login": "bhbuehler",
+ "name": "bhbuehler",
+ "avatar_url": "https://avatars.githubusercontent.com/u/25541343?v=4",
+ "profile": "https://github.com/bhbuehler",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "nyurik",
+ "name": "Yuri Astrakhan",
+ "avatar_url": "https://avatars.githubusercontent.com/u/1641515?v=4",
+ "profile": "https://github.com/nyurik",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "azzamsa",
+ "name": "azzamsa",
+ "avatar_url": "https://avatars.githubusercontent.com/u/17734314?v=4",
+ "profile": "http://azzamsa.com",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "mvanschellebeeck",
+ "name": "mvanschellebeeck",
+ "avatar_url": "https://avatars.githubusercontent.com/u/17671052?v=4",
+ "profile": "https://github.com/mvanschellebeeck",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "aaarkid",
+ "name": "Arkid",
+ "avatar_url": "https://avatars.githubusercontent.com/u/39987510?v=4",
+ "profile": "https://github.com/aaarkid",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "tfpk",
+ "name": "Tom Kunc",
+ "avatar_url": "https://avatars.githubusercontent.com/u/10906982?v=4",
+ "profile": "http://tfpk.dev",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "mfurak",
+ "name": "Marek FurΓ‘k",
+ "avatar_url": "https://avatars.githubusercontent.com/u/38523093?v=4",
+ "profile": "https://github.com/mfurak",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "winterqt",
+ "name": "Winter",
+ "avatar_url": "https://avatars.githubusercontent.com/u/78392041?v=4",
+ "profile": "https://winter.cafe",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "MoritzBoehme",
+ "name": "Moritz BΓΆhme",
+ "avatar_url": "https://avatars.githubusercontent.com/u/42215704?v=4",
+ "profile": "https://moritzboeh.me",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "craymel",
+ "name": "craymel",
+ "avatar_url": "https://avatars.githubusercontent.com/u/71062756?v=4",
+ "profile": "https://github.com/craymel",
+ "contributions": [
+ "content"
+ ]
}
],
"contributorsPerLine": 8,
@@ -1576,5 +1711,6 @@
"projectOwner": "rust-lang",
"repoType": "github",
"repoHost": "https://github.com",
- "skipCi": true
+ "skipCi": true,
+ "commitConvention": "angular"
}
diff --git a/.gitignore b/.gitignore
index 623e11d6..05318167 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,7 +7,8 @@ exercises/clippy/Cargo.toml
exercises/clippy/Cargo.lock
rust-project.json
.idea
-.vscode
+.vscode/*
+!.vscode/extensions.json
*.iml
*.o
rustlings/
\ No newline at end of file
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 00000000..b85de749
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,5 @@
+{
+ "recommendations": [
+ "rust-lang.rust-analyzer"
+ ]
+}
diff --git a/AUTHORS.md b/AUTHORS.md
index 29d330d2..44d8a0ff 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -9,221 +9,242 @@ authors.
diff --git a/Cargo.toml b/Cargo.toml
index dadded68..3f5b253d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,10 @@
[package]
name = "rustlings"
version = "5.2.1"
-authors = ["Liv ", "Carol (Nichols || Goulding) "]
+authors = [
+ "Liv ",
+ "Carol (Nichols || Goulding) ",
+]
edition = "2021"
[dependencies]
diff --git a/README.md b/README.md
index 9b619d6f..38972a4b 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,19 @@ curl -L https://raw.githubusercontent.com/rust-lang/rustlings/main/install.sh |
This will install Rustlings and give you access to the `rustlings` command. Run it to get started!
+### Nix
+Basically: Clone the repository at the latest tag, finally run `nix develop` or `nix-shell`.
+
+```bash
+# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.2.1)
+git clone -b 5.2.1 --depth 1 https://github.com/rust-lang/rustlings
+cd rustlings
+# if nix version > 2.3
+nix develop
+# if nix version <= 2.3
+nix-shell
+```
+
## Windows
In PowerShell (Run as Administrator), set `ExecutionPolicy` to `RemoteSigned`:
@@ -126,7 +139,7 @@ After every couple of sections, there will be a quiz that'll test your knowledge
## Enabling `rust-analyzer`
-Run the command `rustlings lsp` which will generate a `rust-project.json` at the root of the project, this allows [rust-analyzer](https://rust-analyzer.github.io/) to parse each exercise.
+Run the command `rustlings lsp` which will generate a `rust-project.json` at the root of the project, this allows [rust-analyzer](https://rust-analyzer.github.io/) to parse each exercise.
## Continuing On
diff --git a/exercises/conversions/as_ref_mut.rs b/exercises/conversions/as_ref_mut.rs
index 9f479739..c9eed7d0 100644
--- a/exercises/conversions/as_ref_mut.rs
+++ b/exercises/conversions/as_ref_mut.rs
@@ -17,7 +17,7 @@ fn char_counter(arg: T) -> usize {
arg.as_ref().chars().count()
}
-// Squares a number using AsMut. Add the trait bound as is appropriate and
+// Squares a number using as_mut(). Add the trait bound as is appropriate and
// implement the function body.
fn num_sq(arg: &mut T) {
???
diff --git a/exercises/error_handling/errors5.rs b/exercises/error_handling/errors5.rs
index 2ba8f903..6da06ef3 100644
--- a/exercises/error_handling/errors5.rs
+++ b/exercises/error_handling/errors5.rs
@@ -7,7 +7,7 @@
// For now, think of the `Box` type as an "I want anything that does ???" type, which, given
// Rust's usual standards for runtime safety, should strike you as somewhat lenient!
-// In short, this particular use case for boxes is for when you want to own a value and you care only that it is a
+// In short, this particular use case for boxes is for when you want to own a value and you care only that it is a
// type which implements a particular trait. To do so, The Box is declared as of type Box where Trait is the trait
// the compiler looks for on any value used in that context. For this exercise, that context is the potential errors
// which can be returned in a Result.
@@ -46,7 +46,7 @@ impl PositiveNonzeroInteger {
match value {
x if x < 0 => Err(CreationError::Negative),
x if x == 0 => Err(CreationError::Zero),
- x => Ok(PositiveNonzeroInteger(x as u64))
+ x => Ok(PositiveNonzeroInteger(x as u64)),
}
}
}
diff --git a/exercises/error_handling/errors6.rs b/exercises/error_handling/errors6.rs
index 1306fb03..8097b490 100644
--- a/exercises/error_handling/errors6.rs
+++ b/exercises/error_handling/errors6.rs
@@ -16,7 +16,7 @@ use std::num::ParseIntError;
#[derive(PartialEq, Debug)]
enum ParsePosNonzeroError {
Creation(CreationError),
- ParseInt(ParseIntError)
+ ParseInt(ParseIntError),
}
impl ParsePosNonzeroError {
@@ -27,14 +27,11 @@ impl ParsePosNonzeroError {
// fn from_parseint...
}
-fn parse_pos_nonzero(s: &str)
- -> Result
-{
+fn parse_pos_nonzero(s: &str) -> Result {
// TODO: change this to return an appropriate error instead of panicking
// when `parse()` returns an error.
let x: i64 = s.parse().unwrap();
- PositiveNonzeroInteger::new(x)
- .map_err(ParsePosNonzeroError::from_creation)
+ PositiveNonzeroInteger::new(x).map_err(ParsePosNonzeroError::from_creation)
}
// Don't change anything below this line.
@@ -53,7 +50,7 @@ impl PositiveNonzeroInteger {
match value {
x if x < 0 => Err(CreationError::Negative),
x if x == 0 => Err(CreationError::Zero),
- x => Ok(PositiveNonzeroInteger(x as u64))
+ x => Ok(PositiveNonzeroInteger(x as u64)),
}
}
}
diff --git a/exercises/macros/README.md b/exercises/macros/README.md
index 31a941b7..e34bc3a8 100644
--- a/exercises/macros/README.md
+++ b/exercises/macros/README.md
@@ -4,6 +4,10 @@ Rust's macro system is very powerful, but also kind of difficult to wrap your
head around. We're not going to teach you how to write your own fully-featured
macros. Instead, we'll show you how to use and create them.
+If you'd like to learn more about writing your own macros, the
+[macrokata](https://github.com/tfpk/macrokata) project has a similar style
+of exercises to Rustlings, but is all about learning to write Macros.
+
## Further information
- [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html)
diff --git a/exercises/quiz2.rs b/exercises/quiz2.rs
index 0082b003..d0df0f42 100644
--- a/exercises/quiz2.rs
+++ b/exercises/quiz2.rs
@@ -16,7 +16,7 @@
// - The input is going to be a Vector of a 2-length tuple,
// the first element is the string, the second one is the command.
// - The output element is going to be a Vector of strings.
-// Execute `rustlings hint quiz2` or use the `hint` watch subcommand for a hint.
+// No hints this time!
pub enum Command {
Uppercase,
diff --git a/exercises/structs/structs3.rs b/exercises/structs/structs3.rs
index c29e1ab3..a91c3d56 100644
--- a/exercises/structs/structs3.rs
+++ b/exercises/structs/structs3.rs
@@ -82,5 +82,6 @@ mod tests {
let package = Package::new(sender_country, recipient_country, 1500);
assert_eq!(package.get_fees(cents_per_gram), 4500);
+ assert_eq!(package.get_fees(cents_per_gram * 2), 9000);
}
}
diff --git a/exercises/threads/threads2.rs b/exercises/threads/threads2.rs
index d0f8578f..ada3d14a 100644
--- a/exercises/threads/threads2.rs
+++ b/exercises/threads/threads2.rs
@@ -17,7 +17,7 @@ fn main() {
let status = Arc::new(JobStatus { jobs_completed: 0 });
let mut handles = vec![];
for _ in 0..10 {
- let status_shared = status.clone();
+ let status_shared = Arc::clone(&status);
let handle = thread::spawn(move || {
thread::sleep(Duration::from_millis(250));
// TODO: You must take an action before you update a shared value
diff --git a/exercises/threads/threads3.rs b/exercises/threads/threads3.rs
index 27e99088..9e9f285a 100644
--- a/exercises/threads/threads3.rs
+++ b/exercises/threads/threads3.rs
@@ -26,8 +26,8 @@ impl Queue {
fn send_tx(q: Queue, tx: mpsc::Sender) -> () {
let qc = Arc::new(q);
- let qc1 = qc.clone();
- let qc2 = qc.clone();
+ let qc1 = Arc::clone(&qc);
+ let qc2 = Arc::clone(&qc);
thread::spawn(move || {
for val in &qc1.first_half {
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 00000000..ceb62c6d
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,60 @@
+{
+ "nodes": {
+ "flake-compat": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1650374568,
+ "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "rev": "b4a34015c698c7793d592d66adbab377907a2be8",
+ "type": "github"
+ },
+ "original": {
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "type": "github"
+ }
+ },
+ "flake-utils": {
+ "locked": {
+ "lastModified": 1659877975,
+ "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1666629043,
+ "narHash": "sha256-Yoq6Ut2F3Ol73yO9hG93x6ts5c4F5BhKTbcF3DtBEAw=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "b39fd6e4edef83cb4a135ebef98751ce23becc33",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-compat": "flake-compat",
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 00000000..15c82b77
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,53 @@
+{
+ description = "Small exercises to get you used to reading and writing Rust code";
+
+ inputs = {
+ flake-compat = {
+ url = "github:edolstra/flake-compat";
+ flake = false;
+ };
+ flake-utils.url = "github:numtide/flake-utils";
+ nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
+ };
+
+ outputs = { self, flake-utils, nixpkgs, ... }:
+ flake-utils.lib.eachDefaultSystem (system:
+ let
+ pkgs = nixpkgs.legacyPackages.${system};
+ rustlings =
+ pkgs.rustPlatform.buildRustPackage {
+ name = "rustlings";
+ version = "5.2.1";
+
+ src = with pkgs.lib; cleanSourceWith {
+ src = self;
+ # a function that returns a bool determining if the path should be included in the cleaned source
+ filter = path: type:
+ let
+ # filename
+ baseName = builtins.baseNameOf (toString path);
+ # path from root directory
+ path' = builtins.replaceStrings [ "${self}/" ] [ "" ] path;
+ # checks if path is in the directory
+ inDirectory = directory: hasPrefix directory path';
+ in
+ inDirectory "src" ||
+ inDirectory "tests" ||
+ hasPrefix "Cargo" baseName ||
+ baseName == "info.toml";
+ };
+
+ cargoLock.lockFile = ./Cargo.lock;
+ };
+ in
+ {
+ devShell = pkgs.mkShell {
+ buildInputs = with pkgs; [
+ cargo
+ rustc
+ rust-analyzer
+ rustlings
+ ];
+ };
+ });
+}
diff --git a/info.toml b/info.toml
index 6feeb186..df3820d2 100644
--- a/info.toml
+++ b/info.toml
@@ -386,11 +386,9 @@ name = "structs3"
path = "exercises/structs/structs3.rs"
mode = "test"
hint = """
-The new method needs to panic if the weight is physically impossible :), how do we do that in Rust?
-
For is_international: What makes a package international? Seems related to the places it goes through right?
-For calculate_transport_fees: Bigger is more expensive usually, we don't have size, but something may fit the bill here :)
+For get_fees: This method takes an additional argument, is there a field in the Package struct that this relates to?
Have a look in The Book, to find out more about method implementations: https://doc.rust-lang.org/book/ch05-03-method-syntax.html"""
@@ -416,8 +414,8 @@ path = "exercises/enums/enums3.rs"
mode = "test"
hint = """
As a first step, you can define enums to compile this code without errors.
-and then create a match expression in `process()`.
-Note that you need to deconstruct some message variants
+and then create a match expression in `process()`.
+Note that you need to deconstruct some message variants
in the match expression to get value in the variant."""
# STRINGS
@@ -449,7 +447,7 @@ path = "exercises/strings/strings3.rs"
mode = "test"
hint = """
There's tons of useful standard library functions for strings. Let's try and use some of
-them!
+them: !
For the compose_me method: You can either use the `format!` macro, or convert the string
slice into an owned string, which you can then freely extend."""
@@ -476,7 +474,7 @@ name = "modules2"
path = "exercises/modules/modules2.rs"
mode = "compile"
hint = """
-The delicious_snacks module is trying to present an external interface that is
+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` statements to fit the uses in main and
find the one keyword missing for both constants."""
@@ -623,12 +621,12 @@ path = "exercises/error_handling/errors5.rs"
mode = "compile"
hint = """
There are two different possible `Result` types produced within `main()`, which are
-propagated using `?` operators. How do we declare a return type from `main()` that allows both?
+propagated using `?` operators. How do we declare a return type from `main()` that allows both?
Under the hood, the `?` operator calls `From::from` on the error value to convert it to a boxed
trait object, a `Box`. This boxed trait object is polymorphic, and since all
-errors implement the `error:Error` trait, we can capture lots of different errors in one "Box"
-object.
+errors implement the `error::Error` trait, we can capture lots of different errors in one "Box"
+object.
Check out this section of the book:
https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
@@ -818,9 +816,9 @@ Step 1:
We need to apply something to the collection `my_fav_fruits` before we start to go through
it. What could that be? Take a look at the struct definition for a vector for inspiration:
https://doc.rust-lang.org/std/vec/struct.Vec.html.
-Step 2 & step 2.1:
+Step 2 & step 3:
Very similar to the lines above and below. You've got this!
-Step 3:
+Step 4:
An iterator goes through all elements in a collection, but what if we've run out of
elements? What should we expect here? If you're stuck, take a look at
https://doc.rust-lang.org/std/iter/trait.Iterator.html for some ideas.
@@ -862,7 +860,7 @@ case is a vector of integers and the failure case is a DivisionError.
The list_of_results function needs to return a vector of results.
-See https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect for how
+See https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect for how
the `FromIterator` trait is used in `collect()`. This trait is REALLY powerful! It
can make the solution to this exercise infinitely easier."""
@@ -964,12 +962,12 @@ name = "threads1"
path = "exercises/threads/threads1.rs"
mode = "compile"
hint = """
-`JoinHandle` is a struct that is returned from a spawned thread:
+`JoinHandle` is a struct that is returned from a spawned thread:
https://doc.rust-lang.org/std/thread/fn.spawn.html
-A challenge with multi-threaded applications is that the main thread can
+A challenge with multi-threaded applications is that the main thread can
finish before the spawned threads are completed.
-https://doc.rust-lang.org/book/ch16-01-threads.html#waiting-for-all-threads-to-finish-using-join-handle
+https://doc.rust-lang.org/book/ch16-01-threads.html#waiting-for-all-threads-to-finish-using-join-handles
Collect the JoinHandles and wait for them to finish.
https://doc.rust-lang.org/std/thread/struct.JoinHandle.html
@@ -1077,7 +1075,7 @@ mathematical constants in the rust standard library.
https://doc.rust-lang.org/stable/std/f32/consts/index.html
We may be tempted to use our own approximations for certain mathematical constants,
-but clippy recognizes those imprecise mathematical constants as a source of
+but clippy recognizes those imprecise mathematical constants as a source of
potential error.
See the suggestions of the clippy warning in compile output and use the
appropriate replacement constant from std::f32::consts..."""
diff --git a/shell.nix b/shell.nix
new file mode 100644
index 00000000..fa2a56c7
--- /dev/null
+++ b/shell.nix
@@ -0,0 +1,6 @@
+(import (let lock = builtins.fromJSON (builtins.readFile ./flake.lock);
+in fetchTarball {
+ url =
+ "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
+ sha256 = lock.nodes.flake-compat.locked.narHash;
+}) { src = ./.; }).shellNix
diff --git a/src/exercise.rs b/src/exercise.rs
index 4be3a2cc..c0dae34e 100644
--- a/src/exercise.rs
+++ b/src/exercise.rs
@@ -20,7 +20,7 @@ fn temp_file() -> String {
.filter(|c| c.is_alphanumeric())
.collect();
- format!("./temp_{}_{}", process::id(), thread_id)
+ format!("./temp_{}_{thread_id}", process::id())
}
// The mode of the exercise.
diff --git a/src/main.rs b/src/main.rs
index cd79d9ff..bf8503d0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -121,12 +121,12 @@ fn main() {
let args: Args = argh::from_env();
if args.version {
- println!("v{}", VERSION);
+ println!("v{VERSION}");
std::process::exit(0);
}
if args.nested.is_none() {
- println!("\n{}\n", WELCOME);
+ println!("\n{WELCOME}\n");
}
if !Path::new("info.toml").exists() {
@@ -150,7 +150,7 @@ fn main() {
let verbose = args.nocapture;
let command = args.nested.unwrap_or_else(|| {
- println!("{}\n", DEFAULT_OUT);
+ println!("{DEFAULT_OUT}\n");
std::process::exit(0);
});
match command {
@@ -179,11 +179,11 @@ fn main() {
};
if solve_cond && (filter_cond || subargs.filter.is_none()) {
let line = if subargs.paths {
- format!("{}\n", fname)
+ format!("{fname}\n")
} else if subargs.names {
format!("{}\n", e.name)
} else {
- format!("{:<17}\t{:<46}\t{:<7}\n", e.name, fname, status)
+ format!("{:<17}\t{fname:<46}\t{status:<7}\n", e.name)
};
// Somehow using println! leads to the binary panicking
// when its output is piped.
@@ -202,7 +202,7 @@ fn main() {
});
let percentage_progress = exercises_done as f32 / exercises.len() as f32 * 100.0;
println!(
- "Progress: You completed {} / {} exercises ({:.2} %).",
+ "Progress: You completed {} / {} exercises ({:.1} %).",
exercises_done,
exercises.len(),
percentage_progress
@@ -266,7 +266,7 @@ fn main() {
"{emoji} All exercises completed! {emoji}",
emoji = Emoji("π", "β
")
);
- println!("\n{}\n", FENISH_LINE);
+ println!("\n{FENISH_LINE}\n");
}
Ok(WatchStatus::Unfinished) => {
println!("We hope you're enjoying learning about Rust!");
@@ -289,7 +289,7 @@ fn spawn_watch_shell(
let input = input.trim();
if input == "hint" {
if let Some(hint) = &*failed_exercise_hint.lock().unwrap() {
- println!("{}", hint);
+ println!("{hint}");
}
} else if input == "clear" {
println!("\x1B[2J\x1B[1;1H");
@@ -306,10 +306,10 @@ fn spawn_watch_shell(
println!("Watch mode automatically re-evaluates the current exercise");
println!("when you edit a file's contents.")
} else {
- println!("unknown command: {}", input);
+ println!("unknown command: {input}");
}
}
- Err(error) => println!("error reading command: {}", error),
+ Err(error) => println!("error reading command: {error}"),
}
});
}
@@ -329,7 +329,7 @@ fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
.iter()
.find(|e| e.name == name)
.unwrap_or_else(|| {
- println!("No exercise found for '{}'!", name);
+ println!("No exercise found for '{name}'!");
std::process::exit(1)
})
}
@@ -392,7 +392,7 @@ 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),
+ Err(e) => println!("watch error: {e:?}"),
}
// Check if we need to exit
if should_quit.load(Ordering::SeqCst) {
diff --git a/src/run.rs b/src/run.rs
index 826f00a6..1e2e56cf 100644
--- a/src/run.rs
+++ b/src/run.rs
@@ -35,7 +35,7 @@ pub fn reset(exercise: &Exercise) -> Result<(), ()> {
// This is strictly for non-test binaries, so output is displayed
fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
let progress_bar = ProgressBar::new_spinner();
- progress_bar.set_message(format!("Compiling {}...", exercise));
+ progress_bar.set_message(format!("Compiling {exercise}..."));
progress_bar.enable_steady_tick(100);
let compilation_result = exercise.compile();
@@ -52,7 +52,7 @@ fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
}
};
- progress_bar.set_message(format!("Running {}...", exercise));
+ progress_bar.set_message(format!("Running {exercise}..."));
let result = compilation.run();
progress_bar.finish_and_clear();
diff --git a/src/verify.rs b/src/verify.rs
index 6f877831..97471b8f 100644
--- a/src/verify.rs
+++ b/src/verify.rs
@@ -16,7 +16,7 @@ pub fn verify<'a>(
let (num_done, total) = progress;
let bar = ProgressBar::new(total as u64);
bar.set_style(ProgressStyle::default_bar()
- .template("Progress: [{bar:60.green/red}] {pos}/{len}")
+ .template("Progress: [{bar:60.green/red}] {pos}/{len} {msg}")
.progress_chars("#>-")
);
bar.set_position(num_done as u64);
@@ -29,6 +29,8 @@ pub fn verify<'a>(
if !compile_result.unwrap_or(false) {
return Err(exercise);
}
+ let percentage = num_done as f32 / total as f32 * 100.0;
+ bar.set_message(format!("({:.1} %)", percentage));
bar.inc(1);
}
Ok(())
@@ -48,7 +50,7 @@ pub fn test(exercise: &Exercise, verbose: bool) -> Result<(), ()> {
// Invoke the rust compiler without running the resulting binary
fn compile_only(exercise: &Exercise) -> Result {
let progress_bar = ProgressBar::new_spinner();
- progress_bar.set_message(format!("Compiling {}...", exercise));
+ progress_bar.set_message(format!("Compiling {exercise}..."));
progress_bar.enable_steady_tick(100);
let _ = compile(exercise, &progress_bar)?;
@@ -60,12 +62,12 @@ fn compile_only(exercise: &Exercise) -> Result {
// Compile the given Exercise and run the resulting binary in an interactive mode
fn compile_and_run_interactively(exercise: &Exercise) -> Result {
let progress_bar = ProgressBar::new_spinner();
- progress_bar.set_message(format!("Compiling {}...", exercise));
+ progress_bar.set_message(format!("Compiling {exercise}..."));
progress_bar.enable_steady_tick(100);
let compilation = compile(exercise, &progress_bar)?;
- progress_bar.set_message(format!("Running {}...", exercise));
+ progress_bar.set_message(format!("Running {exercise}..."));
let result = compilation.run();
progress_bar.finish_and_clear();
@@ -86,7 +88,7 @@ fn compile_and_run_interactively(exercise: &Exercise) -> Result {
// the output if verbose is set to true
fn compile_and_test(exercise: &Exercise, run_mode: RunMode, verbose: bool) -> Result {
let progress_bar = ProgressBar::new_spinner();
- progress_bar.set_message(format!("Testing {}...", exercise));
+ progress_bar.set_message(format!("Testing {exercise}..."));
progress_bar.enable_steady_tick(100);
let compilation = compile(exercise, &progress_bar)?;
@@ -165,16 +167,16 @@ fn prompt_for_completion(exercise: &Exercise, prompt_output: Option) ->
println!();
if no_emoji {
- println!("~*~ {} ~*~", success_msg)
+ println!("~*~ {success_msg} ~*~")
} else {
- println!("π π {} π π", success_msg)
+ println!("π π {success_msg} π π")
}
println!();
if let Some(output) = prompt_output {
println!("Output:");
println!("{}", separator());
- println!("{}", output);
+ println!("{output}");
println!("{}", separator());
println!();
}