1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
mod headeritem;
mod item;
mod snippet;

use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;

/// Generate C header content from the included docstring.
///
/// This macro operates much like `#[ffizz_header::item]`, but can be applied when there is no Rust
/// item to document.  The `#[ffizz(name="..")]` attribute must always be supplied, and order is
/// usually supplied as well.
///
/// # Example
///
/// ```text
/// # ignored because ffizz_header isn't available in doctests
/// ffizz_header::snippet! {
///     #[ffizz(name="invariants", order=10)]
///     /// LIBRARY INVARIANTS
///     ///
///     /// This library maintains the following invariants:
///     ///  * what goes up, must come down
/// }
/// ```
///
/// produces
///
/// ```text
/// // LIBRARY INVARIANTS
/// //
/// // This library maintains the following invariants:
/// //  * what goes up, must come down
/// ```
#[proc_macro]
pub fn snippet(item: TokenStream) -> TokenStream {
    let snip = syn::parse_macro_input!(item as snippet::Snippet);
    let mut tokens = TokenStream2::new();
    snip.to_tokens(&mut tokens);
    tokens.into()
}

/// Generate C header content from the docstring on this item.
///
/// # Docstring Parsing
///
/// The generated C header content contains C-style comments with the content of the Rust
/// docstring.
///
/// Any blocks delimited by triple-backticks with the `c` type will be included in the header as C
/// code.  This should give the C declaration for the Rust item.
///
/// # Ordering
///
/// The header file is generated by concatenating the content supplied by this macro any by
/// `ffizz_header::snippet!`.  Each piece of content has "order" and "name" properties, and these
/// are used to sort the content in the header file.  The name must also be unique within the
/// resulting library.  The "order" property defaults to `100` and "name" defaults to the name of
/// the Rust item.  Both can be overridden with a `ffizz` attribute:
///
/// ```text
/// #[ffizz(name="FOO_free")]
/// #[ffizz(order=200)]
/// #[ffizz(name="FOO_free", order=200)]
/// ```
///
/// # Example
///
/// ```text
/// #[ffizz_header::item]
/// /// Free a foo_t.  The given foo_t must not be used after this
/// /// call.
/// ///
/// /// ```c
/// /// void foo_free(*foo_t);
/// /// ```
/// pub unsafe extern "C" fn foo_free(*mut foo_t) { .. }
/// ```
///
/// produces
///
/// ```text
/// // Free a foo_t.  The given foo_t must not be used after this
/// // call.
/// void foo_free(*foo_t);
/// ```
#[proc_macro_attribute]
pub fn item(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let docitem = syn::parse_macro_input!(item as item::DocItem);
    let mut tokens = TokenStream2::new();
    docitem.to_tokens(&mut tokens);
    tokens.into()
}