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) = match cursor.literal() { Some(literal) => literal, None => return Err(Error::new(cursor.span(), "Failed to get literal")), }; let span = lit.span(); let text = match span.source_text() { Some(text) => text, None => { let start = span.start(); let end = span.end(); return Err(Error::new( span, format!( "Failed to get sourcetext for {}:{}-{}:{}", start.line, start.column, end.line, end.column, ), )); } }; Ok((text, 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) } } fn get_stream(dir: &str, data: Result) -> TokenStream { match data { Ok(id) => { let path = format!("../../../{}/{}/{}.txt", dir, id.year, id.day); quote! { static DATA: &str = include_str!(#path); } } Err(_)=> { quote! { static DATA: &str = ""; } } }.into() } /// includes Data from Advent of code /// ```ignore (cannot-doctest-external-file-dependency) /// include_data!(2015 01) /// /// fn main() { /// print!("{DATA}"); /// } /// ``` /// The Equivalent is /// ```ignore (cannot-doctest-external-file-dependency) /// static DATA: &str = include_str!("../../../data/2015/01.txt"); /// ``` #[proc_macro] pub fn include_data(data: TokenStream) -> TokenStream { get_stream("data", parse::(data)) } #[proc_macro] pub fn include_example(data: TokenStream)->TokenStream { get_stream("examples", parse::(data)) }