blob: aa98f5843221b73c4083bd5f7b2c64e65d924a03 (
plain) (
blame)
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
|
use super::*;
use syn::parse::Parser;
use syn::punctuated::Punctuated;
use syn::Token;
/// Expand the `#[capability]` macro.
pub fn capability(item: syn::ItemTrait) -> Result<TokenStream> {
let ident = &item.ident;
Ok(quote! {
#item
impl ::typst::model::Capability for dyn #ident {}
})
}
/// Expand the `#[capable(..)]` macro.
pub fn capable(attr: TokenStream, item: syn::Item) -> Result<TokenStream> {
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 and enums are supported"),
};
let (params, args, clause) = generics.split_for_impl();
let checks = Punctuated::<Ident, Token![,]>::parse_terminated
.parse2(attr)?
.into_iter()
.map(|capability| {
quote! {
if id == ::std::any::TypeId::of::<dyn #capability>() {
return Some(unsafe {
::typst::util::fat::vtable(self as &dyn #capability)
});
}
}
});
Ok(quote! {
#item
unsafe impl #params ::typst::model::Capable for #ident #args #clause {
fn vtable(&self, id: ::std::any::TypeId) -> ::std::option::Option<*const ()> {
#(#checks)*
None
}
}
})
}
|