benvolio/
lib.rs

1#[proc_macro]
2pub fn doctest_glob(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
3    let path = if let Some(directory_tt) = input.into_iter().next() {
4        match directory_tt {
5            proc_macro::TokenTree::Literal(lit) => format!(
6                "{}/{}",
7                std::env::var("CARGO_MANIFEST_DIR").unwrap(),
8                lit.to_string()
9            ),
10            _ => {
11                return syn::Error::new(
12                    proc_macro::Span::call_site().into(),
13                    "Expected a string literal here.",
14                )
15                .to_compile_error()
16                .into()
17            }
18        }
19    } else {
20        return syn::Error::new(
21            proc_macro::Span::call_site().into(),
22            "Expected a string literal here.",
23        )
24        .to_compile_error()
25        .into();
26    };
27    let path = path.replace("\"", "");
28    let mut output = quote::quote! {
29        macro_rules! doc_comment {
30            ($x:expr) => {
31                #[doc = $x]
32                extern {}
33            };
34            ($x:expr, $($tt:tt)*) => {
35                #[doc = $x]
36                $($tt)*
37            };
38        }
39        macro_rules! doctest {
40            ($x:expr) => {
41                doc_comment!(include_str!($x));
42            };
43            ($x:expr, $y:ident) => {
44                doc_comment!(include_str!($x), mod $y {});
45            };
46        }
47    };
48    for file in glob::glob(&path).expect("invalid file pattern") {
49        let file = file.expect("error – invalid glob pattern");
50        let str = file.as_os_str().to_str().unwrap();
51        output = quote::quote! {
52            #output
53
54            doctest!(#str);
55        };
56    }
57    output.into()
58}