xref: /DragonOS/kernel/crates/intertrait/macros/src/item_impl.rs (revision bd70d2d1f490aabd570a5301b858bd5eb04149fa)
1*bd70d2d1SLoGin use hashbrown::HashSet;
2*bd70d2d1SLoGin use proc_macro2::TokenStream;
3*bd70d2d1SLoGin use quote::{quote, quote_spanned, ToTokens};
4*bd70d2d1SLoGin use syn::punctuated::Punctuated;
5*bd70d2d1SLoGin use syn::spanned::Spanned;
6*bd70d2d1SLoGin use syn::Token;
7*bd70d2d1SLoGin use syn::{
8*bd70d2d1SLoGin     AngleBracketedGenericArguments, Binding, GenericArgument, ImplItem, ItemImpl, Path,
9*bd70d2d1SLoGin     PathArguments,
10*bd70d2d1SLoGin };
11*bd70d2d1SLoGin use PathArguments::AngleBracketed;
12*bd70d2d1SLoGin 
13*bd70d2d1SLoGin use crate::args::Flag;
14*bd70d2d1SLoGin use crate::gen_caster::generate_caster;
15*bd70d2d1SLoGin 
process(flags: &HashSet<Flag>, input: ItemImpl) -> TokenStream16*bd70d2d1SLoGin pub fn process(flags: &HashSet<Flag>, input: ItemImpl) -> TokenStream {
17*bd70d2d1SLoGin     let ItemImpl {
18*bd70d2d1SLoGin         ref self_ty,
19*bd70d2d1SLoGin         ref trait_,
20*bd70d2d1SLoGin         ref items,
21*bd70d2d1SLoGin         ..
22*bd70d2d1SLoGin     } = input;
23*bd70d2d1SLoGin 
24*bd70d2d1SLoGin     let generated = match trait_ {
25*bd70d2d1SLoGin         None => quote_spanned! {
26*bd70d2d1SLoGin             self_ty.span() => compile_error!("#[cast_to] should only be on an impl of a trait");
27*bd70d2d1SLoGin         },
28*bd70d2d1SLoGin         Some(trait_) => match trait_ {
29*bd70d2d1SLoGin             (Some(bang), _, _) => quote_spanned! {
30*bd70d2d1SLoGin                 bang.span() => compile_error!("#[cast_to] is not for !Trait impl");
31*bd70d2d1SLoGin             },
32*bd70d2d1SLoGin             (None, path, _) => {
33*bd70d2d1SLoGin                 let path = fully_bound_trait(path, items);
34*bd70d2d1SLoGin                 generate_caster(self_ty, &path, flags.contains(&Flag::Sync))
35*bd70d2d1SLoGin             }
36*bd70d2d1SLoGin         },
37*bd70d2d1SLoGin     };
38*bd70d2d1SLoGin 
39*bd70d2d1SLoGin     quote! {
40*bd70d2d1SLoGin         #input
41*bd70d2d1SLoGin         #generated
42*bd70d2d1SLoGin     }
43*bd70d2d1SLoGin }
44*bd70d2d1SLoGin 
fully_bound_trait(path: &Path, items: &[ImplItem]) -> impl ToTokens45*bd70d2d1SLoGin fn fully_bound_trait(path: &Path, items: &[ImplItem]) -> impl ToTokens {
46*bd70d2d1SLoGin     let bindings = items
47*bd70d2d1SLoGin         .iter()
48*bd70d2d1SLoGin         .filter_map(|item| {
49*bd70d2d1SLoGin             if let ImplItem::Type(assoc_ty) = item {
50*bd70d2d1SLoGin                 Some(GenericArgument::Binding(Binding {
51*bd70d2d1SLoGin                     ident: assoc_ty.ident.to_owned(),
52*bd70d2d1SLoGin                     eq_token: Default::default(),
53*bd70d2d1SLoGin                     ty: assoc_ty.ty.to_owned(),
54*bd70d2d1SLoGin                 }))
55*bd70d2d1SLoGin             } else {
56*bd70d2d1SLoGin                 None
57*bd70d2d1SLoGin             }
58*bd70d2d1SLoGin         })
59*bd70d2d1SLoGin         .collect::<Punctuated<_, Token![,]>>();
60*bd70d2d1SLoGin 
61*bd70d2d1SLoGin     let mut path = path.clone();
62*bd70d2d1SLoGin 
63*bd70d2d1SLoGin     if bindings.is_empty() {
64*bd70d2d1SLoGin         return path;
65*bd70d2d1SLoGin     }
66*bd70d2d1SLoGin 
67*bd70d2d1SLoGin     if let Some(last) = path.segments.last_mut() {
68*bd70d2d1SLoGin         match &mut last.arguments {
69*bd70d2d1SLoGin             PathArguments::None => {
70*bd70d2d1SLoGin                 last.arguments = AngleBracketed(AngleBracketedGenericArguments {
71*bd70d2d1SLoGin                     colon2_token: None,
72*bd70d2d1SLoGin                     lt_token: Default::default(),
73*bd70d2d1SLoGin                     args: bindings,
74*bd70d2d1SLoGin                     gt_token: Default::default(),
75*bd70d2d1SLoGin                 })
76*bd70d2d1SLoGin             }
77*bd70d2d1SLoGin             AngleBracketed(args) => args.args.extend(bindings),
78*bd70d2d1SLoGin             _ => {}
79*bd70d2d1SLoGin         }
80*bd70d2d1SLoGin     }
81*bd70d2d1SLoGin     path
82*bd70d2d1SLoGin }
83