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}