mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
49 lines
1.4 KiB
Rust
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
|
|
}
|
|
}
|
|
})
|
|
}
|