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
|
use super::*;
/// Expand the `#[func]` macro.
pub fn func(item: syn::Item) -> Result<TokenStream> {
let doc = documentation(&item)?;
if let syn::Item::Fn(item) = &item {
let vis = &item.vis;
let ident = &item.sig.ident;
let s = ident.to_string();
let mut chars = s.trim_end_matches("_").chars();
let ty = quote::format_ident!(
"{}{}Func",
chars.next().unwrap().to_ascii_uppercase(),
chars.as_str()
);
let full = if item.sig.inputs.len() == 1 {
quote! { |_, args| #ident(args) }
} else {
quote! { #ident }
};
Ok(quote! {
#item
#[doc(hidden)]
#vis enum #ty {}
impl::typst::model::FuncType for #ty {
fn create_func(name: &'static str) -> ::typst::model::Func {
::typst::model::Func::from_fn(name, #full, #doc)
}
}
})
} else {
let (ident, generics) = match &item {
syn::Item::Struct(s) => (&s.ident, &s.generics),
syn::Item::Enum(s) => (&s.ident, &s.generics),
_ => bail!(item, "only structs, enums, and functions are supported"),
};
let (params, args, clause) = generics.split_for_impl();
Ok(quote! {
#item
impl #params ::typst::model::FuncType for #ident #args #clause {
fn create_func(name: &'static str) -> ::typst::model::Func {
::typst::model::Func::from_node::<Self>(name, #doc)
}
}
})
}
}
/// Extract the item's documentation.
fn documentation(item: &syn::Item) -> Result<String> {
let mut doc = String::new();
// Extract attributes.
let attrs = match item {
syn::Item::Struct(item) => &item.attrs,
syn::Item::Enum(item) => &item.attrs,
syn::Item::Fn(item) => &item.attrs,
_ => return Ok(doc),
};
// Parse doc comments.
for attr in attrs {
if let syn::Meta::NameValue(meta) = attr.parse_meta()? {
if meta.path.is_ident("doc") {
if let syn::Lit::Str(string) = &meta.lit {
doc.push_str(&string.value());
doc.push('\n');
}
}
}
}
Ok(doc.trim().into())
}
|