diff --git a/README.md b/README.md index dd64433..472f8ba 100644 --- a/README.md +++ b/README.md @@ -116,15 +116,15 @@ cargo all # Total: 0.20ms ``` -This runs all solutions sequentially and prints output to the command-line. Same as for the `solve` command, the `--release` flag runs an optimized build. +This runs all solutions sequentially and prints output to the command-line. Same as for the `solve` command, the `--release` flag runs an optimized build and the `--time` flag outputs benchmarks. -#### Update readme benchmarks +### ➡️ Update readme benchmarks -The template can output a table with solution times to your readme. +The template can write benchmark times to the README via the `cargo time` command. -In order to generate the benchmarking table, run `cargo time`. By default, this command checks for missing benchmarks, runs those solutions, and then updates the table. If you want to (re-)time all solutions, run `cargo time --force` flag. If you want to (re-)time a specific solution, run `cargo time `. +By default, this command checks for missing benchmarks, runs those solutions, and then updates the table. If you want to (re-)time all solutions, run `cargo time --all`. If you want to (re-)time one specific solution, run `cargo time `. -Please note that these are not "scientific" benchmarks, understand them as a fun approximation. 😉 Timings, especially in the microseconds range, might change a bit between invocations. +Please note that these are not _scientific_ benchmarks, understand them as a fun approximation. 😉 Timings, especially in the microseconds range, might change a bit between invocations. ### ➡️ Run all tests diff --git a/src/main.rs b/src/main.rs index e14ab43..57d4fe3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,8 +33,8 @@ mod args { time: bool, }, Time { + all: bool, day: Option, - force: bool, }, #[cfg(feature = "today")] Today, @@ -49,10 +49,10 @@ mod args { time: args.contains("--time"), }, Some("time") => { - let force = args.contains("--force"); + let all = args.contains("--all"); AppArguments::Time { - force, + all, day: args.opt_free_from_str()?, } } @@ -102,7 +102,7 @@ fn main() { } Ok(args) => match args { AppArguments::All { release, time } => all::handle(release, time), - AppArguments::Time { day, force } => time::handle(day, force), + AppArguments::Time { day, all } => time::handle(day, all), AppArguments::Download { day } => download::handle(day), AppArguments::Read { day } => read::handle(day), AppArguments::Scaffold { day, download } => { diff --git a/src/template/commands/time.rs b/src/template/commands/time.rs index 9c08412..fc6e42f 100644 --- a/src/template/commands/time.rs +++ b/src/template/commands/time.rs @@ -4,7 +4,7 @@ use crate::template::run_multi::run_multi; use crate::template::timings::Timings; use crate::template::{all_days, readme_benchmarks, Day}; -pub fn handle(day: Option, force: bool) { +pub fn handle(day: Option, recreate_all: bool) { let stored_timings = Timings::read_from_file(); let mut days_to_run = HashSet::new(); @@ -15,13 +15,8 @@ pub fn handle(day: Option, force: bool) { } None => { all_days().for_each(|day| { - // when the force flag is not set, filter out days that are fully benched. - if force - || !stored_timings - .data - .iter() - .any(|t| t.day == day && t.part_1.is_some() && t.part_2.is_some()) - { + // when the `--all` flag is not set, filter out days that are fully benched. + if recreate_all || !stored_timings.is_day_complete(&day) { days_to_run.insert(day); } }); diff --git a/src/template/run_multi.rs b/src/template/run_multi.rs index f11fe71..0fdf2d5 100644 --- a/src/template/run_multi.rs +++ b/src/template/run_multi.rs @@ -8,7 +8,7 @@ use super::{ }; pub fn run_multi(days_to_run: HashSet, is_release: bool, is_timed: bool) -> Option { - let mut timings: Vec = vec![]; + let mut timings: Vec = Vec::with_capacity(days_to_run.len()); all_days().for_each(|day| { if day > 1 { diff --git a/src/template/timings.rs b/src/template/timings.rs index 9cd14ae..f7dc091 100644 --- a/src/template/timings.rs +++ b/src/template/timings.rs @@ -25,9 +25,8 @@ impl Timings { /// Dehydrate timings to a JSON file. pub fn store_file(&self) -> Result<(), Error> { let json = JsonValue::from(self.clone()); - let mut bytes = vec![]; - json.format_to(&mut bytes)?; - fs::write(TIMINGS_FILE_PATH, bytes) + let mut file = fs::File::create(TIMINGS_FILE_PATH)?; + json.format_to(&mut file) } /// Rehydrate timings from a JSON file. If not present, returns empty timings. @@ -67,6 +66,12 @@ impl Timings { pub fn total_millis(&self) -> f64 { self.data.iter().map(|x| x.total_nanos).sum::() / 1_000_000_f64 } + + pub fn is_day_complete(&self, day: &Day) -> bool { + self.data + .iter() + .any(|t| &t.day == day && t.part_1.is_some() && t.part_2.is_some()) + } } /* -------------------------------------------------------------------------- */ @@ -101,8 +106,8 @@ impl TryFrom for Timings { Ok(Timings { data: json_data .iter() - .map(|value| Timing::try_from(value).unwrap()) - .collect(), + .map(Timing::try_from) + .collect::>()?, }) } } @@ -270,7 +275,56 @@ mod tests { } } - mod helpers { + mod is_day_complete { + use crate::{ + day, + template::timings::{Timing, Timings}, + }; + + #[test] + fn handles_completed_days() { + let timings = Timings { + data: vec![Timing { + day: day!(1), + part_1: Some("1ms".into()), + part_2: Some("2ms".into()), + total_nanos: 3_000_000_000_f64, + }], + }; + + assert_eq!(timings.is_day_complete(&day!(1)), true); + } + + #[test] + fn handles_partial_days() { + let timings = Timings { + data: vec![Timing { + day: day!(1), + part_1: Some("1ms".into()), + part_2: None, + total_nanos: 1_000_000_000_f64, + }], + }; + + assert_eq!(timings.is_day_complete(&day!(1)), false); + } + + #[test] + fn handles_uncompleted_days() { + let timings = Timings { + data: vec![Timing { + day: day!(1), + part_1: None, + part_2: None, + total_nanos: 0.0, + }], + }; + + assert_eq!(timings.is_day_complete(&day!(1)), false); + } + } + + mod merge { use crate::{ day, template::timings::{Timing, Timings},