init
This commit is contained in:
commit
5b84356e5e
6 changed files with 192 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
target/
|
||||||
|
Cargo.lock
|
5
Cargo.toml
Normal file
5
Cargo.toml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"libaoc",
|
||||||
|
"libaoc-macros",
|
||||||
|
]
|
14
libaoc-macros/Cargo.toml
Normal file
14
libaoc-macros/Cargo.toml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[package]
|
||||||
|
name = "libaoc-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
quote = "1.0"
|
||||||
|
syn = { version = "1.0", features = ["full"] }
|
||||||
|
|
||||||
|
[features]
|
108
libaoc-macros/src/lib.rs
Normal file
108
libaoc-macros/src/lib.rs
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
#![feature(proc_macro_diagnostic)]
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{
|
||||||
|
parse::{Parse, ParseStream},
|
||||||
|
parse_macro_input, parse_quote,
|
||||||
|
punctuated::Punctuated,
|
||||||
|
spanned::Spanned,
|
||||||
|
token::Comma,
|
||||||
|
Expr, Item, ItemMod,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn day(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
|
let mut input = parse_macro_input!(input as ItemMod);
|
||||||
|
let args = parse_macro_input!(args as Args);
|
||||||
|
|
||||||
|
let content = if let Some(c) = &mut input.content {
|
||||||
|
&mut c.1
|
||||||
|
} else {
|
||||||
|
input.span().unwrap().error("Module must have body!").emit();
|
||||||
|
return quote!(#input).into();
|
||||||
|
};
|
||||||
|
|
||||||
|
let fns = content
|
||||||
|
.iter()
|
||||||
|
.filter_map(|i| match i {
|
||||||
|
Item::Fn(fun) => Some(fun),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let part1 = fns
|
||||||
|
.iter()
|
||||||
|
.find(|i| &i.sig.ident.to_string() == "part1")
|
||||||
|
.copied();
|
||||||
|
let part2 = fns
|
||||||
|
.iter()
|
||||||
|
.find(|i| &i.sig.ident.to_string() == "part2")
|
||||||
|
.copied();
|
||||||
|
|
||||||
|
if part1.is_none() {
|
||||||
|
input
|
||||||
|
.span()
|
||||||
|
.unwrap()
|
||||||
|
.error("Need part1 function, which is not found within module.")
|
||||||
|
.emit();
|
||||||
|
return quote!(#input).into();
|
||||||
|
}
|
||||||
|
|
||||||
|
let part2 = if part2.is_some() {
|
||||||
|
quote!(Some(self::part2))
|
||||||
|
} else {
|
||||||
|
quote!(None)
|
||||||
|
};
|
||||||
|
|
||||||
|
let name = args.name;
|
||||||
|
content.push(parse_quote! {
|
||||||
|
pub fn aoc_day() -> libaoc::Day {
|
||||||
|
libaoc::Day {
|
||||||
|
name: format!("{}", #name),
|
||||||
|
part1: self::part1,
|
||||||
|
part2: #part2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(infile) = args.input {
|
||||||
|
content.push(parse_quote!{
|
||||||
|
const INPUT: &str = include_str!(#infile);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
quote!(#input).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Args {
|
||||||
|
name: Expr,
|
||||||
|
input: Option<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Args {
|
||||||
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
|
let mut puncted = Punctuated::<Expr, Comma>::parse_separated_nonempty(input)?.into_iter();
|
||||||
|
let name = puncted.next();
|
||||||
|
if name.is_none() {
|
||||||
|
return Err(syn::Error::new(
|
||||||
|
input.span(),
|
||||||
|
"Must provide at least one argument for the day name!",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = puncted.next();
|
||||||
|
|
||||||
|
if let Some(excess) = puncted.next() {
|
||||||
|
return Err(syn::Error::new(
|
||||||
|
excess.span(),
|
||||||
|
"No more than 2 arguments allowed!",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
name: name.unwrap(),
|
||||||
|
input,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
11
libaoc/Cargo.toml
Normal file
11
libaoc/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "libaoc"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libaoc-macros = { path = "../libaoc-macros" }
|
||||||
|
miette = { version = "3.2", features = ["fancy"] }
|
||||||
|
owo-colors = "2.1"
|
52
libaoc/src/lib.rs
Normal file
52
libaoc/src/lib.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
pub use libaoc_macros::*;
|
||||||
|
pub use miette;
|
||||||
|
use miette::Context;
|
||||||
|
use owo_colors::OwoColorize;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! run_days {
|
||||||
|
($($day:ident),+) => {
|
||||||
|
libaoc::AocRunner::new()
|
||||||
|
$(.day($day::aoc_day()))*
|
||||||
|
.run()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Day {
|
||||||
|
pub name: String,
|
||||||
|
pub part1: fn() -> miette::Result<()>,
|
||||||
|
pub part2: Option<fn() -> miette::Result<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AocRunner {
|
||||||
|
days: Vec<Day>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AocRunner {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { days: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn day(&mut self, day: Day) -> &mut Self {
|
||||||
|
self.days.push(day);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&self) -> miette::Result<()> {
|
||||||
|
for day in &self.days {
|
||||||
|
println!("Running day {}...", day.name.blue());
|
||||||
|
|
||||||
|
println!("{}", "--- Part 1 ---".red());
|
||||||
|
(day.part1)().wrap_err_with(|| format!("Running part 1 of day {}", &day.name))?;
|
||||||
|
println!();
|
||||||
|
|
||||||
|
if let Some(p2) = day.part2 {
|
||||||
|
println!("{}", "--- Part 2 ---".red());
|
||||||
|
p2().wrap_err_with(|| format!("Running part 2 of day {}", &day.name))?;
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue