typst/macros/src/capable.rs
2022-12-15 23:11:20 +01:00

49 lines
1.4 KiB
Rust

use syn::parse::Parser;
use syn::punctuated::Punctuated;
use syn::Token;
use super::*;
/// 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
}
}
})
}