Skip to content

Commit

Permalink
Sync to template at 72e1283
Browse files Browse the repository at this point in the history
  • Loading branch information
fspoettel authored and kcaffrey committed Dec 6, 2023
1 parent 8752b60 commit 000475e
Show file tree
Hide file tree
Showing 16 changed files with 78 additions and 64 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "advent_of_code"
version = "0.9.3"
version = "0.9.4"
authors = ["Felix Spöttel <1682504+fspoettel@users.noreply.github.com>"]
edition = "2021"
default-run = "advent_of_code"
Expand Down
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,17 @@ cargo scaffold <day>

Individual solutions live in the `./src/bin/` directory as separate binaries. _Inputs_ and _examples_ live in the the `./data` directory.

Every [solution](https://github.com/fspoettel/advent-of-code-rust/blob/main/src/template/commands/scaffold.rs#L9-L35) has _tests_ referencing its _example_ file in `./data/examples`. Use these tests to develop and debug your solutions against the example input.
Every [solution](https://github.com/fspoettel/advent-of-code-rust/blob/main/src/template.txt) has _tests_ referencing its _example_ file in `./data/examples`. Use these tests to develop and debug your solutions against the example input. In VS Code, `rust-analyzer` will display buttons for running / debugging these unit tests above the unit test blocks.

> [!TIP]
> If a day has different example inputs for both parts, you can use the `read_file_part()` helper in your tests instead of `read_file()`. For example, if this applies to day 1, you can create a second example file `01-2.txt` and invoke the helper like `let result = part_two(&advent_of_code::template::read_file_part("examples", DAY, 2));` to read it in `test_part_two`.
> [!TIP]
> when editing a solution, `rust-analyzer` will display buttons for running / debugging unit tests above the unit test blocks.
### Download input & description for a day

> [!IMPORTANT]
> This command requires [installing the aoc-cli crate](#configure-aoc-cli-integration).
> This requires [installing the aoc-cli crate](#configure-aoc-cli-integration).
You can automatically download puzzle inputs and description by either appending the `--download` flag to `scaffold` (e.g. `cargo scaffold 4 --download`) or with the separate `download` command:

```sh
# example: `cargo download 1`
Expand Down Expand Up @@ -121,7 +120,7 @@ For example, running a benchmarked, optimized execution of day 1 would look like
#### Submitting solutions

> [!IMPORTANT]
> This command requires [installing the aoc-cli crate](#configure-aoc-cli-integration).
> This requires [installing the aoc-cli crate](#configure-aoc-cli-integration).
In order to submit part of a solution for checking, append the `--submit <part>` option to the `solve` command.

Expand All @@ -145,7 +144,7 @@ This runs all solutions sequentially and prints output to the command-line. Same

#### Update readme benchmarks

The template can output a table with solution times to your readme. In order to generate a benchmarking table, run `cargo all --release --time`. If everything goes well, the command will output "_Successfully updated README with benchmarks._" after the execution finishes and the readme will be updated.
The template can output a table with solution times to your readme. In order to generate a benchmarking table, run `cargo time`. If everything goes well, the command will output "_Successfully updated README with benchmarks._" after the execution finishes and the readme will be updated.

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.

Expand Down
3 changes: 0 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
mod day;
pub mod template;

pub use day::*;
12 changes: 9 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ use advent_of_code::template::commands::{all, download, read, scaffold, solve};
use args::{parse, AppArguments};

mod args {
use advent_of_code::template::Day;
use std::process;

use advent_of_code::Day;

pub enum AppArguments {
Download {
day: Day,
Expand All @@ -15,6 +14,7 @@ mod args {
},
Scaffold {
day: Day,
download: bool,
},
Solve {
day: Day,
Expand Down Expand Up @@ -44,6 +44,7 @@ mod args {
},
Some("scaffold") => AppArguments::Scaffold {
day: args.free_from_str()?,
download: args.contains("--download"),
},
Some("solve") => AppArguments::Solve {
day: args.free_from_str()?,
Expand Down Expand Up @@ -80,7 +81,12 @@ fn main() {
AppArguments::All { release, time } => all::handle(release, time),
AppArguments::Download { day } => download::handle(day),
AppArguments::Read { day } => read::handle(day),
AppArguments::Scaffold { day } => scaffold::handle(day),
AppArguments::Scaffold { day, download } => {
scaffold::handle(day);
if download {
download::handle(day);
}
}
AppArguments::Solve {
day,
release,
Expand Down
26 changes: 26 additions & 0 deletions src/template.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
advent_of_code::solution!(%DAY_NUMBER%);

pub fn part_one(input: &str) -> Option<u32> {
None
}

pub fn part_two(input: &str) -> Option<u32> {
None
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_part_one() {
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, None);
}

#[test]
fn test_part_two() {
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, None);
}
}
2 changes: 1 addition & 1 deletion src/template/aoc_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{
process::{Command, Output, Stdio},
};

use crate::Day;
use crate::template::Day;

#[derive(Debug)]
pub enum AocCommandError {
Expand Down
6 changes: 3 additions & 3 deletions src/template/commands/all.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::io;

use crate::template::{
all_days,
readme_benchmarks::{self, Timings},
ANSI_BOLD, ANSI_ITALIC, ANSI_RESET,
Day, ANSI_BOLD, ANSI_ITALIC, ANSI_RESET,
};
use crate::{all_days, Day};

pub fn handle(is_release: bool, is_timed: bool) {
let mut timings: Vec<Timings> = vec![];
Expand Down Expand Up @@ -65,7 +65,7 @@ pub fn get_path_for_bin(day: Day) -> String {
/// This module encapsulates interaction with these binaries, both invoking them as well as parsing the timing output.
mod child_commands {
use super::{get_path_for_bin, Error};
use crate::Day;
use crate::template::Day;
use std::{
io::{BufRead, BufReader},
path::Path,
Expand Down
3 changes: 1 addition & 2 deletions src/template/commands/download.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::template::aoc_cli;
use crate::Day;
use crate::template::{aoc_cli, Day};
use std::process;

pub fn handle(day: Day) {
Expand Down
3 changes: 1 addition & 2 deletions src/template/commands/read.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::process;

use crate::template::aoc_cli;
use crate::Day;
use crate::template::{aoc_cli, Day};

pub fn handle(day: Day) {
if aoc_cli::check().is_err() {
Expand Down
33 changes: 4 additions & 29 deletions src/template/commands/scaffold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,10 @@ use std::{
process,
};

use crate::Day;
use crate::template::Day;

const MODULE_TEMPLATE: &str = r#"advent_of_code::solution!(DAY_NUMBER);
pub fn part_one(input: &str) -> Option<u32> {
None
}
pub fn part_two(input: &str) -> Option<u32> {
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, None);
}
#[test]
fn test_part_two() {
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, None);
}
}
"#;
const MODULE_TEMPLATE: &str =
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/template.txt"));

fn safe_create_file(path: &str) -> Result<File, std::io::Error> {
OpenOptions::new().write(true).create_new(true).open(path)
Expand All @@ -57,7 +32,7 @@ pub fn handle(day: Day) {

match file.write_all(
MODULE_TEMPLATE
.replace("DAY_NUMBER", &day.into_inner().to_string())
.replace("%DAY_NUMBER%", &day.into_inner().to_string())
.as_bytes(),
) {
Ok(()) => {
Expand Down
2 changes: 1 addition & 1 deletion src/template/commands/solve.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::process::{Command, Stdio};

use crate::Day;
use crate::template::Day;

pub fn handle(day: Day, release: bool, time: bool, submit_part: Option<u8>) {
let mut cmd_args = vec!["run".to_string(), "--bin".to_string(), day.to_string()];
Expand Down
2 changes: 1 addition & 1 deletion src/day.rs → src/template/day.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ macro_rules! day {
"`, expecting a value between 1 and 25"
),
);
$crate::Day::__new_unchecked($day)
$crate::template::Day::__new_unchecked($day)
}};
}

Expand Down
25 changes: 19 additions & 6 deletions src/template/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use crate::Day;
use std::{env, fs};

pub mod aoc_cli;
pub mod commands;
mod day;
pub mod readme_benchmarks;
pub mod runner;

pub use day::*;

pub const ANSI_ITALIC: &str = "\x1b[3m";
pub const ANSI_BOLD: &str = "\x1b[1m";
pub const ANSI_RESET: &str = "\x1b[0m";
Expand All @@ -32,17 +34,28 @@ pub fn read_file_part(folder: &str, day: Day, part: u8) -> String {
}

/// Creates the constant `DAY` and sets up the input and runner for each part.
///
/// The optional, second parameter (1 or 2) allows you to only run a single part of the solution.
#[macro_export]
macro_rules! solution {
($day:expr) => {
$crate::solution!(@impl $day, [part_one, 1] [part_two, 2]);
};
($day:expr, 1) => {
$crate::solution!(@impl $day, [part_one, 1]);
};
($day:expr, 2) => {
$crate::solution!(@impl $day, [part_two, 2]);
};

(@impl $day:expr, $( [$func:expr, $part:expr] )*) => {
/// The current day.
const DAY: advent_of_code::Day = advent_of_code::day!($day);
const DAY: $crate::template::Day = $crate::day!($day);

fn main() {
use advent_of_code::template::runner::*;
let input = advent_of_code::template::read_file("inputs", DAY);
run_part(part_one, &input, DAY, 1);
run_part(part_two, &input, DAY, 2);
use $crate::template::runner::*;
let input = $crate::template::read_file("inputs", DAY);
$( run_part($func, &input, DAY, $part); )*
}
};
}
2 changes: 1 addition & 1 deletion src/template/readme_benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/// The approach taken is similar to how `aoc-readme-stars` handles this.
use std::{fs, io};

use crate::Day;
use crate::template::Day;

static MARKER: &str = "<!--- benchmarking table --->";

Expand Down
6 changes: 3 additions & 3 deletions src/template/runner.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// Encapsulates code that interacts with solution functions.
use crate::template::{aoc_cli, ANSI_ITALIC, ANSI_RESET};
use crate::Day;
use crate::template::{aoc_cli, Day, ANSI_ITALIC, ANSI_RESET};
use std::fmt::Display;
use std::hint::black_box;
use std::io::{stdout, Write};
use std::process::Output;
use std::time::{Duration, Instant};
Expand Down Expand Up @@ -65,7 +65,7 @@ fn bench<I: Clone, T>(func: impl Fn(I) -> T, input: I, base_time: &Duration) ->
// need a clone here to make the borrow checker happy.
let cloned = input.clone();
let timer = Instant::now();
func(cloned);
black_box(func(black_box(cloned)));
timers.push(timer.elapsed());
}

Expand Down

0 comments on commit 000475e

Please sign in to comment.