use proc_macro::TokenStream; use quote::quote; use syn::{ buffer::Cursor, parse::{Parse, ParseStream, StepCursor}, Error, }; use syn::{parse, LitInt, Result}; struct IncludeData { year: String, day: String, } fn get_string<'a, 'b>(cursor: StepCursor<'a, 'b>) -> Result<(String, Cursor<'a>)> { let (lit, c) = cursor.literal().unwrap(); Ok((lit.span().source_text().unwrap(), c)) } impl Parse for IncludeData { fn parse(input: ParseStream) -> Result { let mut data = IncludeData { year: "".into(), day: "".into(), }; let mut look = input.lookahead1(); if !look.peek(LitInt) { let s = input.span(); return Err(Error::new(s, format!("{} is not an valid Year", s.source_text().unwrap()))); } data.year = input.step(get_string).expect("Wanted an string"); look = input.lookahead1(); if !look.peek(LitInt) { let s = input.span(); return Err(Error::new(s, format!("{} is not an valid Day", s.source_text().unwrap()))); } data.day = input.step(get_string).expect("Wanted an string"); Ok(data) } } /// includes Data from Advent of code /// ```ignore (cannot-doctest-external-file-dependency) /// include_data!(2015 01) /// /// fn main() { /// print!("{DATA}"); /// } /// ``` #[proc_macro] pub fn include_data(data: TokenStream)->TokenStream { let gen = match parse::(data) { Ok(data) => { let path = format!("../../../data/{}/{}.txt", data.year, data.day); quote! { static DATA: &str = include_str!(#path); } }, Err(_) => { quote! { static DATA: &str = ""; } }, }; gen.into() }