This commit is contained in:
nora 2024-12-30 21:09:55 +01:00
parent eb8f0855bf
commit 3fb4bf282b
4 changed files with 189 additions and 98 deletions

View file

@ -2,13 +2,46 @@ mod cmd;
mod ext;
mod hash;
use std::fmt::Display;
use std::{borrow::Cow, fmt::Debug};
pub use self::cmd::main;
pub use self::ext::*;
pub use self::hash::*;
pub type Solution = fn(&str) -> u64;
#[derive(PartialEq, Eq)]
pub enum Answer {
U64(u64),
String(String),
}
impl Debug for Answer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::U64(arg0) => Debug::fmt(arg0, f),
Self::String(arg0) => Debug::fmt(arg0, f),
}
}
}
impl Display for Answer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::U64(arg0) => Display::fmt(arg0, f),
Self::String(arg0) => Display::fmt(arg0, f),
}
}
}
impl From<u64> for Answer {
fn from(value: u64) -> Self {
Answer::U64(value)
}
}
impl From<String> for Answer {
fn from(value: String) -> Self {
Answer::String(value)
}
}
pub type Solution = fn(&str) -> Answer;
pub trait Day {
fn part1() -> Variants;
@ -46,12 +79,13 @@ impl Variant {
}
}
pub fn test_part1<D: Day>(inputs: &[(&str, &str, u64)]) {
#[track_caller]
pub fn test_part1<D: Day>(inputs: &[(&str, &str, Answer)]) {
for variant in D::part1().variants {
for input in inputs {
let (path, input, expected) = *input;
let (path, input, expected) = input;
let actual = (variant.f)(input);
if actual != expected {
if actual != *expected {
panic!(
"failed: {}: {}: {} != {}",
path, variant.name, actual, expected
@ -61,12 +95,13 @@ pub fn test_part1<D: Day>(inputs: &[(&str, &str, u64)]) {
}
}
pub fn test_part2<D: Day>(inputs: &[(&str, &str, u64)]) {
#[track_caller]
pub fn test_part2<D: Day>(inputs: &[(&str, &str, Answer)]) {
for variant in D::part2().variants {
for input in inputs {
let (path, input, expected) = *input;
let (path, input, expected) = input;
let actual = (variant.f)(input);
if actual != expected {
if actual != *expected {
panic!(
"failed: {}: {}: {} != {}",
path, variant.name, actual, expected
@ -120,7 +155,10 @@ macro_rules! construct_variants {
( $day:ty; $( ($name:ident, $func:expr, [ $($_:tt)* ]) ),*) => {
$crate::Variants {
variants: vec![$(
$crate::Variant::new(stringify!($name), std::hint::black_box($func))
$crate::Variant::new(stringify!($name), |input| {
let answer = $func(input);
$crate::Answer::from(answer)
})
),*]
}
};
@ -173,41 +211,32 @@ macro_rules! _define_benchmarks {
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _test_name_to_file {
(small) => {
"../input_small.txt"
};
(default) => {
"../input.txt"
};
($path:expr) => {
$path
};
}
#[macro_export]
macro_rules! tests {
(
$day_small:ident $day:ident;
part1 {
small => $p1small:expr;
default => $p1default:expr;
}
part2 {
small => $p2small:expr;
default => $p2default:expr;
}
) => {
$crate::tests! {
$day_small $day;
part1 {
"../input_small.txt" => $p1small;
"../input.txt" => $p1default;
}
part2 {
"../input_small.txt" => $p2small;
"../input.txt" => $p2default;
}
}
};
(
$day_small:ident $day:ident;
part1 {
$(
$file1:literal => $p1:expr;
$file1:tt => $p1:expr;
)*
}
part2 {
$(
$file2:literal => $p2:expr;
$file2:tt => $p2:expr;
)*
}
) => {
@ -217,7 +246,7 @@ macro_rules! tests {
fn part1() {
helper::test_part1::<super::$day>(&[
$(
($file1, include_str!($file1), $p1),
($crate::_test_name_to_file!($file1), include_str!($crate::_test_name_to_file!($file1)), $crate::Answer::from($p1)),
)*
]);
}
@ -226,7 +255,7 @@ macro_rules! tests {
fn part2() {
helper::test_part2::<super::$day>(&[
$(
($file2, include_str!($file2), $p2),
($crate::_test_name_to_file!($file2), include_str!($crate::_test_name_to_file!($file2)), $crate::Answer::from($p2)),
)*
]);
}