1#![doc = include_str!("../README.md")]
2
3use proc_macro::*;
4use proc_macro::Spacing::*;
5use proc_macro::Delimiter::*;
6use proc_macro::TokenTree as T;
7
8
9#[doc = include_str!("../README.md")]
10#[proc_macro_attribute]
11pub fn docsrs_cfg(attr: TokenStream, item: TokenStream) -> TokenStream {
12 macro_impl("docsrs", attr, item)
13}
14
15#[proc_macro_attribute]
31pub fn doc_cfg(attr: TokenStream, item: TokenStream) -> TokenStream {
32 macro_impl("doc", attr, item)
33}
34
35fn macro_impl(kind: &str, attr: TokenStream, item: TokenStream) -> TokenStream {
36 let span = Span::call_site();
37 [
38 TokenStream::from(T::Punct(Punct::new('#', Joint))),
39 TokenStream::from(T::Group(Group::new(Bracket, [
40 T::Ident(Ident::new("cfg", span)),
41 T::Group(Group::new(Parenthesis, [
42 T::Ident(Ident::new("any", span)),
43 T::Group(Group::new(Parenthesis, [
44 T::Ident(Ident::new(kind, span)).into(),
45 T::Punct(Punct::new(',', Alone)).into(),
46 attr.clone(),
47 ].into_iter().collect())),
48 ].into_iter().collect())),
49 ].into_iter().collect()))),
50 TokenStream::from(T::Punct(Punct::new('#', Spacing::Joint))),
51 TokenStream::from(T::Group(Group::new(Bracket, [
52 T::Ident(Ident::new("cfg_attr", span)),
53 T::Group(Group::new(Parenthesis, [
54 T::Ident(Ident::new(kind, span)),
55 T::Punct(Punct::new(',', Alone)),
56 T::Ident(Ident::new("doc", span)),
57 T::Group(Group::new(Parenthesis, [
58 T::Ident(Ident::new("cfg", span)),
59 T::Group(Group::new(Parenthesis, attr)),
60 ].into_iter().collect())),
61 ].into_iter().collect())),
62 ].into_iter().collect()))),
63 item,
64 ].into_iter().collect()
65}
66
67#[doc(hidden)]
72#[proc_macro_attribute]
73pub fn __test_docsrs(attr: TokenStream, item: TokenStream) -> TokenStream {
74 let output = docsrs_cfg(attr, item.clone()).to_string()
75 .parse::<TokenStream>().unwrap().to_string();
76 let expect = r#"
77#[cfg(any(docsrs, any(feature = "std", feature = "alloc")))]
78#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
79fn foo() {}
80 "#.parse::<TokenStream>().unwrap().to_string();
81
82 if output.trim() == expect.trim() {
83 item
84 } else {
85 let span = Span::call_site();
86 [
87 T::Ident(Ident::new("compile_error", span)),
88 T::Punct(Punct::new('!', Joint)),
89 T::Group(Group::new(Brace, T::Literal(
90 Literal::string(&format!(
91 "assert failed, expected:\n{}\ncurrent:\n{}",
92 expect.trim(),
93 output.trim(),
94 ))
95 ).into())),
96 ].into_iter().collect()
97 }
98}
99
100#[doc(hidden)]
105#[proc_macro_attribute]
106pub fn __test_doc(attr: TokenStream, item: TokenStream) -> TokenStream {
107 let output = doc_cfg(attr, item.clone()).to_string()
108 .parse::<TokenStream>().unwrap().to_string();
109 let expect = r#"
110#[cfg(any(doc, any(feature = "std", feature = "alloc")))]
111#[cfg_attr(doc, doc(cfg(any(feature = "std", feature = "alloc"))))]
112fn foo() {}
113 "#.parse::<TokenStream>().unwrap().to_string();
114
115 if output.trim() == expect.trim() {
116 item
117 } else {
118 let span = Span::call_site();
119 [
120 T::Ident(Ident::new("compile_error", span)),
121 T::Punct(Punct::new('!', Joint)),
122 T::Group(Group::new(Brace, T::Literal(
123 Literal::string(&format!(
124 "assert failed, expected:\n{}\ncurrent:\n{}",
125 expect.trim(),
126 output.trim(),
127 ))
128 ).into())),
129 ].into_iter().collect()
130 }
131}