added a new macro include_aoc!
this is to replace the include_data! and include_example macros. It features partitioned inputs and unified interface
Dieser Commit ist enthalten in:
Ursprung
727285020b
Commit
313c6f4e3b
1 geänderte Dateien mit 100 neuen und 2 gelöschten Zeilen
|
@ -1,8 +1,8 @@
|
|||
use std::fs;
|
||||
use std::fs::{self, read_to_string};
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{parse, Result};
|
||||
use syn::{parse, LitBool, Result};
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
spanned::Spanned,
|
||||
|
@ -152,3 +152,101 @@ pub fn include_example(data: TokenStream) -> TokenStream {
|
|||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct NewIncludeData {
|
||||
var: String,
|
||||
year: String,
|
||||
day: String,
|
||||
example: bool,
|
||||
parts: usize,
|
||||
}
|
||||
|
||||
impl Parse for NewIncludeData {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let mut v = Self::default();
|
||||
v.var = if input.peek(Ident) && !input.peek(LitInt) {
|
||||
get_text(input.parse::<Ident>().unwrap())?
|
||||
} else {
|
||||
VAR_NAME.to_string()
|
||||
};
|
||||
v.year = get_text(input.parse::<LitInt>()?)?;
|
||||
v.day = get_text(input.parse::<Lit>()?)?;
|
||||
if input.peek(LitBool) {
|
||||
v.example = input.parse::<LitBool>()?.value;
|
||||
}
|
||||
if input.peek(LitInt) {
|
||||
v.parts = input.parse::<LitInt>()?.base10_parse()?;
|
||||
}
|
||||
if v.parts == 0 {
|
||||
v.parts = 1;
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
fn fallback(input: NewIncludeData, message: String) -> TokenStream {
|
||||
if input.parts != 1 {
|
||||
let postfixes = (1..=input.parts).map(|i| format_ident!("{}_{}", input.var, i));
|
||||
quote! {
|
||||
#(
|
||||
///
|
||||
const #postfixes: &str = "";
|
||||
)*
|
||||
}
|
||||
.into()
|
||||
} else {
|
||||
let name = format_ident!("{}", input.var);
|
||||
quote! {
|
||||
/// #name
|
||||
const #name: &str = "";
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Macro to include data and examples.
|
||||
/// The First Argument(Optional) is the name/prefix for the constant,
|
||||
/// The Second is the Year
|
||||
/// The Third is the day/filename without the .txt at the end
|
||||
/// the fourth is if its an example or not
|
||||
/// and the last is the amount of parts in the file, if it is greater than 1 the first argument is treated as an Prefix.
|
||||
#[proc_macro]
|
||||
pub fn include_aoc(data: TokenStream) -> TokenStream {
|
||||
let input = match parse::<NewIncludeData>(data) {
|
||||
Ok(data) => data,
|
||||
Err(error) => return error.into_compile_error().into(),
|
||||
};
|
||||
let mut content = Default::default();
|
||||
if !input.example {
|
||||
let path = format!("{}/{}/{}.txt", DATA_DIR, input.year, input.day);
|
||||
match fs::exists(path.clone()) {
|
||||
Ok(true) => content = read_to_string(path).unwrap(),
|
||||
Ok(false) => {},
|
||||
Err(error) => return fallback(input, format!("Failed to read file: {}", error)),
|
||||
};
|
||||
}
|
||||
if content.is_empty() {
|
||||
let path = format!("{}/{}/{}.txt", EXAMPLE_DIR, input.year, input.day);
|
||||
content = match fs::exists(path.clone()) {
|
||||
Ok(true) => read_to_string(path).unwrap(),
|
||||
Ok(false) => Default::default(),
|
||||
Err(error) => return fallback(input, format!("Failed to read file: {}", error)),
|
||||
};
|
||||
}
|
||||
if input.parts != 1 {
|
||||
let parts = content.splitn(input.parts, "\n\n");
|
||||
let suffix = (1..=input.parts).map(|i| format_ident!("{}_{}", input.var, i));
|
||||
quote! {
|
||||
#(
|
||||
const #suffix: &str = #parts;
|
||||
)*
|
||||
}
|
||||
} else {
|
||||
let name = format_ident!("{}", input.var);
|
||||
quote! {
|
||||
const #name: &str = #content;
|
||||
}
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
|
Laden …
Tabelle hinzufügen
In neuem Issue referenzieren