use syn::parse::Parser; use syn::punctuated::Punctuated; use syn::Token; use super::*; /// Expand the `#[capability]` macro. pub fn capability(item: syn::ItemTrait) -> Result { 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 { 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::::parse_terminated .parse2(attr)? .into_iter() .map(|capability| { quote! { if id == ::std::any::TypeId::of::() { 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 } } }) }