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