diff --git a/.all-contributorsrc b/.all-contributorsrc
index 0df89f7e..f2033dcd 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -1488,6 +1488,60 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "nico-vromans",
+ "name": "Nico Vromans",
+ "avatar_url": "https://avatars.githubusercontent.com/u/48183857?v=4",
+ "profile": "https://github.com/nico-vromans",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "vostok92",
+ "name": "vostok92",
+ "avatar_url": "https://avatars.githubusercontent.com/u/540339?v=4",
+ "profile": "https://github.com/vostok92",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "magnusrodseth",
+ "name": "Magnus RΓΈdseth",
+ "avatar_url": "https://avatars.githubusercontent.com/u/59113973?v=4",
+ "profile": "http://magnusrodseth.vercel.app",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "rubiesonthesky",
+ "name": "rubiesonthesky",
+ "avatar_url": "https://avatars.githubusercontent.com/u/2591240?v=4",
+ "profile": "https://github.com/rubiesonthesky",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "GabrielBianconi",
+ "name": "Gabriel Bianconi",
+ "avatar_url": "https://avatars.githubusercontent.com/u/1275491?v=4",
+ "profile": "http://www.gabrielbianconi.com/",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "Kodylow",
+ "name": "Kody Low",
+ "avatar_url": "https://avatars.githubusercontent.com/u/74332828?v=4",
+ "profile": "https://github.com/Kodylow",
+ "contributions": [
+ "content"
+ ]
}
],
"contributorsPerLine": 8,
diff --git a/AUTHORS.md b/AUTHORS.md
index 9648f33c..8edf09bf 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -212,6 +212,12 @@ authors.
Brian Fakhoury π
Markus Boehme π»
+ Nico Vromans π
+ vostok92 π
+ Magnus RΓΈdseth π
+ rubiesonthesky π
+ Gabriel Bianconi π
+ Kody Low π
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8aae3138..0b15cf99 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,62 @@
+
+## 5.2.0 (2022-08-27)
+
+#### Added
+
+- Added a `reset` command
+
+#### Changed
+
+- **options2**: Convert the exercise to use tests
+
+#### Fixed
+
+- **threads3**: Fixed a typo
+- **quiz1**: Adjusted the explanations to be consistent with
+ the tests
+
+
+## 5.1.1 (2022-08-17)
+
+#### Bug Fixes
+
+- Fixed an incorrect assertion in options1
+
+
+## 5.1.0 (2022-08-16)
+
+#### Features
+
+- Added a new `rc1` exercise.
+- Added a new `cow1` exercise.
+
+#### Bug Fixes
+
+- **variables5**: Corrected reference to previous exercise
+- **functions4**: Fixed line number reference
+- **strings3**: Clarified comment wording
+- **traits4, traits5**: Fixed line number reference
+- **traits5**:
+ - Fixed typo in "parameter"
+ - Made exercise prefer a traits-based solution
+- **lifetimes2**: Improved hint
+- **threads3**: Fixed typo in hint
+- **box1**: Replaced `unimplemented!` with `todo!`
+- **errors5**: Provided an explanation for usage of `Box`
+- **quiz2**: Fixed a typo
+- **macros**: Updated the macros book link
+- **options1**:
+ - Removed unused code
+ - Added more granular tests
+- Fixed some comment syntax shenanigans in info.toml
+
+#### Housekeeping
+
+- Fixed a typo in .editorconfig
+- Fixed a typo in integration_tests.rs
+- Clarified manual installation instructions using `cargo install --path .`
+- Added a link to our Zulip in the readme file
+
## 5.0.0 (2022-07-16)
diff --git a/Cargo.lock b/Cargo.lock
index 862a8a2e..2370e8dc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -459,7 +459,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rustlings"
-version = "5.0.0"
+version = "5.1.1"
dependencies = [
"argh",
"assert_cmd",
diff --git a/Cargo.toml b/Cargo.toml
index 910b5389..25cd7bfe 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "rustlings"
-version = "5.0.0"
+version = "5.2.0"
authors = ["Liv ", "Carol (Nichols || Goulding) "]
edition = "2021"
diff --git a/README.md b/README.md
index afa55c86..2392ba9d 100644
--- a/README.md
+++ b/README.md
@@ -57,8 +57,8 @@ If you get a permission denied message, you might have to exclude the directory
Basically: Clone the repository at the latest tag, run `cargo install --path .`.
```bash
-# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.0.0)
-git clone -b 5.0.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 5.1.1)
+git clone -b 5.1.1 --depth 1 https://github.com/rust-lang/rustlings
cd rustlings
cargo install --force --path .
```
@@ -154,6 +154,10 @@ Now you should be done!
See [CONTRIBUTING.md](./CONTRIBUTING.md).
+Development-focused discussion about Rustlings happens in the [**rustlings** stream](https://rust-lang.zulipchat.com/#narrow/stream/334454-rustlings)
+on the [Rust Project Zulip](https://rust-lang.zulipchat.com). Feel free to start a new thread there
+if you have ideas or suggestions!
+
## Contributors β¨
Thanks goes to the wonderful people listed in [AUTHORS.md](./AUTHORS.md) π
diff --git a/exercises/options/options1.rs b/exercises/options/options1.rs
index 99c95911..d1735c2f 100644
--- a/exercises/options/options1.rs
+++ b/exercises/options/options1.rs
@@ -19,6 +19,7 @@ mod tests {
#[test]
fn check_icecream() {
+ assert_eq!(maybe_icecream(9), Some(5));
assert_eq!(maybe_icecream(10), Some(5));
assert_eq!(maybe_icecream(23), Some(0));
assert_eq!(maybe_icecream(22), Some(0));
diff --git a/exercises/options/options2.rs b/exercises/options/options2.rs
index 75b66a37..b1120471 100644
--- a/exercises/options/options2.rs
+++ b/exercises/options/options2.rs
@@ -3,23 +3,34 @@
// I AM NOT DONE
-fn main() {
- let optional_word = Some(String::from("rustlings"));
- // TODO: Make this an if let statement whose value is "Some" type
- word = optional_word {
- println!("The word is: {}", word);
- } else {
- println!("The optional word doesn't contain anything");
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn simple_option() {
+ let target = "rustlings";
+ let optional_target = Some(target);
+
+ // TODO: Make this an if let statement whose value is "Some" type
+ word = optional_target {
+ assert_eq!(word, target);
+ }
}
- let mut optional_integers_vec: Vec> = Vec::new();
- for x in 1..10 {
- optional_integers_vec.push(Some(x));
- }
+ #[test]
+ fn layered_option() {
+ let mut range = 10;
+ let mut optional_integers: Vec > = Vec::new();
+ for i in 0..(range + 1) {
+ optional_integers.push(Some(i));
+ }
- // TODO: make this a while let statement - remember that vector.pop also adds another layer of Option
- // You can stack `Option`'s into while let and if let
- integer = optional_integers_vec.pop() {
- println!("current value: {}", integer);
+ // TODO: make this a while let statement - remember that vector.pop also adds another layer of Option
+ // You can stack `Option`'s into while let and if let
+ integer = optional_integers.pop() {
+ assert_eq!(integer, range);
+ range -= 1;
+ }
}
}
diff --git a/exercises/quiz1.rs b/exercises/quiz1.rs
index 8d05b110..d1e76e59 100644
--- a/exercises/quiz1.rs
+++ b/exercises/quiz1.rs
@@ -5,7 +5,7 @@
// - If
// Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy
-// more than 40 at once, each apple only costs 1! Write a function that calculates
+// 40 or more at once, each apple only costs 1! Write a function that calculates
// the price of an order of apples given the quantity bought. No hints this time!
// I AM NOT DONE
diff --git a/exercises/standard_library_types/cow1.rs b/exercises/standard_library_types/cow1.rs
new file mode 100644
index 00000000..5fba2519
--- /dev/null
+++ b/exercises/standard_library_types/cow1.rs
@@ -0,0 +1,48 @@
+// cow1.rs
+
+// This exercise explores the Cow, or Clone-On-Write type.
+// Cow is a clone-on-write smart pointer.
+// It can enclose and provide immutable access to borrowed data, and clone the data lazily when mutation or ownership is required.
+// The type is designed to work with general borrowed data via the Borrow trait.
+
+// I AM NOT DONE
+
+use std::borrow::Cow;
+
+fn abs_all<'a, 'b>(input: &'a mut Cow<'b, [i32]>) -> &'a mut Cow<'b, [i32]> {
+ for i in 0..input.len() {
+ let v = input[i];
+ if v < 0 {
+ // Clones into a vector if not already owned.
+ input.to_mut()[i] = -v;
+ }
+ }
+ input
+}
+
+fn main() {
+ // No clone occurs because `input` doesn't need to be mutated.
+ let slice = [0, 1, 2];
+ let mut input = Cow::from(&slice[..]);
+ match abs_all(&mut input) {
+ Cow::Borrowed(_) => println!("I borrowed the slice!"),
+ _ => panic!("expected borrowed value"),
+ }
+
+ // Clone occurs because `input` needs to be mutated.
+ let slice = [-1, 0, 1];
+ let mut input = Cow::from(&slice[..]);
+ match abs_all(&mut input) {
+ Cow::Owned(_) => println!("I modified the slice and now own it!"),
+ _ => panic!("expected owned value"),
+ }
+
+ // No clone occurs because `input` is already owned.
+ let slice = vec![-1, 0, 1];
+ let mut input = Cow::from(slice);
+ match abs_all(&mut input) {
+ // TODO
+ Cow::Borrowed(_) => println!("I own this slice!"),
+ _ => panic!("expected borrowed value"),
+ }
+}
diff --git a/exercises/standard_library_types/rc1.rs b/exercises/standard_library_types/rc1.rs
new file mode 100644
index 00000000..9b907fde
--- /dev/null
+++ b/exercises/standard_library_types/rc1.rs
@@ -0,0 +1,98 @@
+// rc1.rs
+// In this exercise, we want to express the concept of multiple owners via the Rc type.
+// This is a model of our solar system - there is a Sun type and multiple Planets.
+// The Planets take ownership of the sun, indicating that they revolve around the sun.
+
+// Make this code compile by using the proper Rc primitives to express that the sun has multiple owners.
+
+// I AM NOT DONE
+use std::rc::Rc;
+
+#[derive(Debug)]
+struct Sun {}
+
+#[derive(Debug)]
+enum Planet {
+ Mercury(Rc),
+ Venus(Rc),
+ Earth(Rc),
+ Mars(Rc),
+ Jupiter(Rc),
+ Saturn(Rc),
+ Uranus(Rc),
+ Neptune(Rc),
+}
+
+impl Planet {
+ fn details(&self) {
+ println!("Hi from {:?}!", self)
+ }
+}
+
+fn main() {
+ let sun = Rc::new(Sun {});
+ println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
+
+ let mercury = Planet::Mercury(Rc::clone(&sun));
+ println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
+ mercury.details();
+
+ let venus = Planet::Venus(Rc::clone(&sun));
+ println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
+ venus.details();
+
+ let earth = Planet::Earth(Rc::clone(&sun));
+ println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
+ earth.details();
+
+ let mars = Planet::Mars(Rc::clone(&sun));
+ println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
+ mars.details();
+
+ let jupiter = Planet::Jupiter(Rc::clone(&sun));
+ println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
+ jupiter.details();
+
+ // TODO
+ let saturn = Planet::Saturn(Rc::new(Sun {}));
+ println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
+ saturn.details();
+
+ // TODO
+ let uranus = Planet::Uranus(Rc::new(Sun {}));
+ println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
+ uranus.details();
+
+ // TODO
+ let neptune = Planet::Neptune(Rc::new(Sun {}));
+ println!("reference count = {}", Rc::strong_count(&sun)); // 9 references
+ neptune.details();
+
+ assert_eq!(Rc::strong_count(&sun), 9);
+
+ drop(neptune);
+ println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
+
+ drop(uranus);
+ println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
+
+ drop(saturn);
+ println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
+
+ drop(jupiter);
+ println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
+
+ drop(mars);
+ println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
+
+ // TODO
+ println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
+
+ // TODO
+ println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
+
+ // TODO
+ println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
+
+ assert_eq!(Rc::strong_count(&sun), 1);
+}
diff --git a/info.toml b/info.toml
index dc1485d7..060643d7 100644
--- a/info.toml
+++ b/info.toml
@@ -545,7 +545,7 @@ is the easiest, but how do you do it safely so that it doesn't panic in your fac
[[exercises]]
name = "options2"
path = "exercises/options/options2.rs"
-mode = "compile"
+mode = "test"
hint = """
check out:
https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html
@@ -932,6 +932,31 @@ is too much of a struggle, consider reading through all of Chapter 16 in the boo
https://doc.rust-lang.org/stable/book/ch16-00-concurrency.html
"""
+[[exercises]]
+name = "rc1"
+path = "exercises/standard_library_types/rc1.rs"
+mode = "compile"
+hint = """
+This is a straightforward exercise to use the Rc type. Each Planet has
+ownership of the Sun, and uses Rc::clone() to increment the reference count of the Sun.
+After using drop() to move the Planets out of scope individually, the reference count goes down.
+In the end the sun only has one reference again, to itself. See more at:
+https://doc.rust-lang.org/book/ch15-04-rc.html
+
+* Unforunately Pluto is no longer considered a planet :(
+"""
+
+[[exercises]]
+name = "cow1"
+path = "exercises/standard_library_types/cow1.rs"
+mode = "compile"
+hint = """
+Since the vector is already owned, the `Cow` type doesn't need to clone it.
+
+Checkout https://doc.rust-lang.org/std/borrow/enum.Cow.html for documentation
+on the `Cow` type.
+"""
+
# THREADS
[[exercises]]
@@ -987,7 +1012,7 @@ hint = """
An alternate way to handle concurrency between threads is to use
a mpsc (multiple producer, single consumer) channel to communicate.
With both a sending end and a receiving end, it's possible to
-send values in one thread and receieve them in another.
+send values in one thread and receive them in another.
Multiple producers are possible by using clone() to create a duplicate
of the original sending end.
See https://doc.rust-lang.org/book/ch16-02-message-passing.html for more info.
diff --git a/src/main.rs b/src/main.rs
index 0ddb7331..8eebc086 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,6 @@
use crate::exercise::{Exercise, ExerciseList};
use crate::project::RustAnalyzerProject;
-use crate::run::run;
+use crate::run::{reset, run};
use crate::verify::verify;
use argh::FromArgs;
use console::Emoji;
@@ -26,7 +26,7 @@ mod run;
mod verify;
// In sync with crate version
-const VERSION: &str = "5.0.0";
+const VERSION: &str = "5.2.0";
#[derive(FromArgs, PartialEq, Debug)]
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
@@ -47,6 +47,7 @@ enum Subcommands {
Verify(VerifyArgs),
Watch(WatchArgs),
Run(RunArgs),
+ Reset(ResetArgs),
Hint(HintArgs),
List(ListArgs),
Lsp(LspArgs),
@@ -71,6 +72,15 @@ struct RunArgs {
name: String,
}
+#[derive(FromArgs, PartialEq, Debug)]
+#[argh(subcommand, name = "reset")]
+/// Resets a single exercise using "git stash -- "
+struct ResetArgs {
+ #[argh(positional)]
+ /// the name of the exercise
+ name: String,
+}
+
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "hint")]
/// Returns a hint for the given exercise
@@ -85,7 +95,6 @@ struct HintArgs {
/// Enable rust-analyzer for exercises
struct LspArgs {}
-
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "list")]
/// Lists the exercises available in Rustlings
@@ -164,7 +173,9 @@ fn main() {
"Pending"
};
let solve_cond = {
- (e.looks_done() && subargs.solved) || (!e.looks_done() && subargs.unsolved) || (!subargs.solved && !subargs.unsolved)
+ (e.looks_done() && subargs.solved)
+ || (!e.looks_done() && subargs.unsolved)
+ || (!subargs.solved && !subargs.unsolved)
};
if solve_cond && (filter_cond || subargs.filter.is_none()) {
let line = if subargs.paths {
@@ -205,6 +216,12 @@ fn main() {
run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1));
}
+ Subcommands::Reset(subargs) => {
+ let exercise = find_exercise(&subargs.name, &exercises);
+
+ reset(exercise).unwrap_or_else(|_| std::process::exit(1));
+ }
+
Subcommands::Hint(subargs) => {
let exercise = find_exercise(&subargs.name, &exercises);
@@ -212,7 +229,8 @@ fn main() {
}
Subcommands::Verify(_subargs) => {
- verify(&exercises, (0, exercises.len()), verbose).unwrap_or_else(|_| std::process::exit(1));
+ verify(&exercises, (0, exercises.len()), verbose)
+ .unwrap_or_else(|_| std::process::exit(1));
}
Subcommands::Lsp(_subargs) => {
@@ -236,12 +254,18 @@ fn main() {
Subcommands::Watch(_subargs) => match watch(&exercises, verbose) {
Err(e) => {
- println!("Error: Could not watch your progress. Error message was {:?}.", 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!(
+ "{emoji} All exercises completed! {emoji}",
+ emoji = Emoji("π", "β
")
+ );
println!("\n{}\n", FENISH_LINE);
}
Ok(WatchStatus::Unfinished) => {
@@ -252,8 +276,10 @@ fn main() {
}
}
-
-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 {
@@ -290,16 +316,22 @@ fn spawn_watch_shell(failed_exercise_hint: &Arc>>, should_q
fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
if name.eq("next") {
- exercises.iter().find(|e| !e.looks_done()).unwrap_or_else(|| {
- println!("π Congratulations! You have done all the exercises!");
- println!("π There are no more exercises to do next!");
- std::process::exit(1)
- })
+ exercises
+ .iter()
+ .find(|e| !e.looks_done())
+ .unwrap_or_else(|| {
+ println!("π Congratulations! You have done all the exercises!");
+ println!("π There are no more exercises to do next!");
+ std::process::exit(1)
+ })
} else {
- exercises.iter().find(|e| e.name == name).unwrap_or_else(|| {
- println!("No exercise found for '{}'!", name);
- std::process::exit(1)
- })
+ exercises
+ .iter()
+ .find(|e| e.name == name)
+ .unwrap_or_else(|| {
+ println!("No exercise found for '{}'!", name);
+ std::process::exit(1)
+ })
}
}
@@ -337,8 +369,13 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result {
let filepath = b.as_path().canonicalize().unwrap();
let pending_exercises = exercises
.iter()
- .find(|e| filepath.ends_with(&e.path)).into_iter()
- .chain(exercises.iter().filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)));
+ .find(|e| filepath.ends_with(&e.path))
+ .into_iter()
+ .chain(
+ exercises
+ .iter()
+ .filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)),
+ );
let num_done = exercises.iter().filter(|e| e.looks_done()).count();
clear_screen();
match verify(pending_exercises, (num_done, exercises.len()), verbose) {
diff --git a/src/run.rs b/src/run.rs
index eb558850..826f00a6 100644
--- a/src/run.rs
+++ b/src/run.rs
@@ -1,3 +1,5 @@
+use std::process::Command;
+
use crate::exercise::{Exercise, Mode};
use crate::verify::test;
use indicatif::ProgressBar;
@@ -15,6 +17,19 @@ pub fn run(exercise: &Exercise, verbose: bool) -> Result<(), ()> {
Ok(())
}
+// Resets the exercise by stashing the changes.
+pub fn reset(exercise: &Exercise) -> Result<(), ()> {
+ let command = Command::new("git")
+ .args(["stash", "--"])
+ .arg(&exercise.path)
+ .spawn();
+
+ match command {
+ Ok(_) => Ok(()),
+ Err(_) => Err(()),
+ }
+}
+
// Invoke the rust compiler on the path of the given exercise
// and run the ensuing binary.
// This is strictly for non-test binaries, so output is displayed
diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs
index 0be191f0..1a729232 100644
--- a/tests/integration_tests.rs
+++ b/tests/integration_tests.rs
@@ -110,6 +110,27 @@ fn run_single_test_no_exercise() {
.code(1);
}
+#[test]
+fn reset_single_exercise() {
+ Command::cargo_bin("rustlings")
+ .unwrap()
+ .args(&["reset", "intro1"])
+ .assert()
+ .code(0);
+}
+
+#[test]
+fn reset_no_exercise() {
+ Command::cargo_bin("rustlings")
+ .unwrap()
+ .arg("reset")
+ .assert()
+ .code(1)
+ .stderr(predicates::str::contains(
+ "positional arguments not provided",
+ ));
+}
+
#[test]
fn get_hint_for_single_test() {
Command::cargo_bin("rustlings")
@@ -126,7 +147,7 @@ fn all_exercises_require_confirmation() {
for exercise in glob("exercises/**/*.rs").unwrap() {
let path = exercise.unwrap();
if path.file_name().unwrap() == "mod.rs" {
- continue
+ continue;
}
let source = {
let mut file = File::open(&path).unwrap();