diff --git a/exercises/24_async/async1.rs b/exercises/24_async/async1.rs index aa61ea70..4549759e 100644 --- a/exercises/24_async/async1.rs +++ b/exercises/24_async/async1.rs @@ -6,18 +6,14 @@ // Let's simulate this using asynchronous programming. Each person is // represented as an asynchronous task, which can be executed concurrently. -const SCORES_CLASS_A: &str = "exercises/24_async/scores_class_a.txt"; -const SCORES_CLASS_B: &str = "exercises/24_async/scores_class_b.txt"; -const SCORES_CLASS_C: &str = "exercises/24_async/scores_class_c.txt"; - // Async tasks need to be executed by a "runtime", which is not provided by // Rust's standard library. Here, we use the mainstream runtime `tokio`. // The macro `tokio::main` wraps the entire main function in a runtime. #[tokio::main] async fn main() { - let mean_score_a = tokio::spawn(calculate_mean_score(SCORES_CLASS_A)); - let mean_score_b = tokio::spawn(calculate_mean_score(SCORES_CLASS_B)); - let mean_score_c = tokio::spawn(calculate_mean_score(SCORES_CLASS_C)); + let mean_score_a = tokio::spawn(calculate_mean_score("scores_class_a.txt")); + let mean_score_b = tokio::spawn(calculate_mean_score("scores_class_b.txt")); + let mean_score_c = tokio::spawn(calculate_mean_score("scores_class_c.txt")); // TODO: Await the spawned tasks to check their results. assert_eq!(mean_score_a, 84); // alice diff --git a/solutions/24_async/async1.rs b/solutions/24_async/async1.rs index 97121c77..45f0ab8e 100644 --- a/solutions/24_async/async1.rs +++ b/solutions/24_async/async1.rs @@ -6,18 +6,14 @@ // Let's simulate this using asynchronous programming. Each person is // represented as an asynchronous task, which can be executed concurrently. -const SCORES_CLASS_A: &str = "exercises/24_async/scores_class_a.txt"; -const SCORES_CLASS_B: &str = "exercises/24_async/scores_class_b.txt"; -const SCORES_CLASS_C: &str = "exercises/24_async/scores_class_c.txt"; - // Async tasks need to be executed by a "runtime", which is not provided by // Rust's standard library. Here, we use the mainstream runtime `tokio`. // The macro `tokio::main` wraps the entire main function in a runtime. #[tokio::main] async fn main() { - let mean_score_a = tokio::spawn(calculate_mean_score(SCORES_CLASS_A)); - let mean_score_b = tokio::spawn(calculate_mean_score(SCORES_CLASS_B)); - let mean_score_c = tokio::spawn(calculate_mean_score(SCORES_CLASS_C)); + let mean_score_a = tokio::spawn(calculate_mean_score("scores_class_a.txt")); + let mean_score_b = tokio::spawn(calculate_mean_score("scores_class_b.txt")); + let mean_score_c = tokio::spawn(calculate_mean_score("scores_class_c.txt")); assert_eq!(mean_score_a.await.unwrap(), 84); // alice assert_eq!(mean_score_b.await.unwrap(), 89); // bob diff --git a/src/cmd.rs b/src/cmd.rs index 094db5a0..0717ee0b 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -13,7 +13,12 @@ const TIMEOUT_SECS: u64 = 30; /// Run a command with a description for a possible error and append the merged stdout and stderr. /// The boolean in the returned `Result` is true if the command's exit status is success. -fn run_cmd(mut cmd: Command, description: &str, output: Option<&mut Vec>) -> Result { +fn run_cmd( + mut cmd: Command, + description: &str, + cwd: Option<&str>, + output: Option<&mut Vec>, +) -> Result { let spawn = |mut cmd: Command| { // The closure drops `cmd` which prevents a pipe deadlock. cmd.stdin(Stdio::null()) @@ -25,6 +30,9 @@ fn run_cmd(mut cmd: Command, description: &str, output: Option<&mut Vec>) -> .wait_timeout(Duration::from_secs(TIMEOUT_SECS)) .with_context(|| format!("Failed to wait on `{description}` to exit")) }; + if let Some(cwd) = cwd { + cmd.current_dir(cwd); + } let mut handle = if let Some(output) = output { let (mut reader, writer) = @@ -133,7 +141,12 @@ impl CmdRunner { } /// The boolean in the returned `Result` is true if the command's exit status is success. - pub fn run_debug_bin(&self, bin_name: &str, output: Option<&mut Vec>) -> Result { + pub fn run_debug_bin( + &self, + bin_name: &str, + cwd: &str, + output: Option<&mut Vec>, + ) -> Result { // 7 = "/debug/".len() let mut bin_path = PathBuf::with_capacity(self.target_dir.as_os_str().len() + 7 + bin_name.len()); @@ -141,7 +154,7 @@ impl CmdRunner { bin_path.push("debug"); bin_path.push(bin_name); - run_cmd(Command::new(&bin_path), bin_name, output) + run_cmd(Command::new(&bin_path), bin_name, Some(cwd), output) } } @@ -161,7 +174,7 @@ impl CargoSubcommand<'_> { /// The boolean in the returned `Result` is true if the command's exit status is success. pub fn run(self, description: &str) -> Result { - run_cmd(self.cmd, description, self.output) + run_cmd(self.cmd, description, None, self.output) } } @@ -179,7 +192,7 @@ mod tests { cmd.arg("Hello"); let mut output = Vec::with_capacity(8); - run_cmd(cmd, "echo …", Some(&mut output)).unwrap(); + run_cmd(cmd, "echo …", None, Some(&mut output)).unwrap(); assert_eq!(output, b"Hello\n\n"); } diff --git a/src/exercise.rs b/src/exercise.rs index 7732e1a2..e31b3174 100644 --- a/src/exercise.rs +++ b/src/exercise.rs @@ -36,6 +36,7 @@ pub fn solution_link_line( // Compilation must be done before calling this method. fn run_bin( bin_name: &str, + cwd: &str, mut output: Option<&mut Vec>, cmd_runner: &CmdRunner, ) -> Result { @@ -46,7 +47,7 @@ fn run_bin( output.push(b'\n'); } - let success = cmd_runner.run_debug_bin(bin_name, output.as_deref_mut())?; + let success = cmd_runner.run_debug_bin(bin_name, cwd, output.as_deref_mut())?; if let Some(output) = output && !success @@ -123,6 +124,14 @@ pub trait RunnableExercise { output.clear(); } + let cwd_buf; + let cwd = if let Some(dir) = self.dir() { + cwd_buf = format!("exercises/{dir}"); + cwd_buf.as_str() + } else { + "exercises" + }; + if self.test() { let output_is_some = output.is_some(); let mut test_cmd = cmd_runner.cargo("test", bin_name, output.as_deref_mut()); @@ -131,7 +140,7 @@ pub trait RunnableExercise { } let test_success = test_cmd.run("cargo test …")?; if !test_success { - run_bin(bin_name, output, cmd_runner)?; + run_bin(bin_name, cwd, output, cmd_runner)?; return Ok(false); } @@ -151,7 +160,7 @@ pub trait RunnableExercise { } let clippy_success = clippy_cmd.run("cargo clippy …")?; - let run_success = run_bin(bin_name, output, cmd_runner)?; + let run_success = run_bin(bin_name, cwd, output, cmd_runner)?; Ok(clippy_success && run_success) }