impl_tools_lib/
split_impl.rs1use crate::utils::{self, PathAsStr, copy_non_doc_attrs};
9use proc_macro_error3::emit_error;
10use proc_macro2::TokenStream;
11use quote::quote;
12use syn::{Generics, ImplItem, ItemTrait, Token, TraitItem, Type, parse_quote};
13
14pub struct SplitImpl {
16 for_: Token![for],
17 generics: Generics,
18 target: Box<Type>,
19}
20
21mod parsing {
22 use super::*;
23 use syn::parse::{Parse, ParseStream, Result};
24
25 impl Parse for SplitImpl {
26 fn parse(input: ParseStream) -> Result<Self> {
27 let for_ = input.parse::<Token![for]>()?;
28 let mut generics = if input.peek(Token![<]) {
29 input.parse()?
30 } else {
31 Generics::default()
32 };
33 let target = input.parse()?;
34 if input.peek(Token![where]) {
35 generics.where_clause = Some(input.parse()?);
36 }
37
38 Ok(SplitImpl {
39 for_,
40 generics,
41 target,
42 })
43 }
44 }
45}
46
47impl SplitImpl {
48 pub fn process(self, mut trait_: ItemTrait) -> TokenStream {
50 let mut attrs = Vec::with_capacity(trait_.attrs.len());
51 for attr in &trait_.attrs {
52 if utils::propegate_attr_to_impl(attr) {
53 attrs.push(attr.clone());
54 }
55 }
56
57 let mut items = Vec::with_capacity(trait_.items.len());
58 for item in trait_.items.iter_mut() {
59 match item {
60 TraitItem::Const(item) => {
61 let Some((eq_token, expr)) = item.default.take() else {
62 emit_error!(item, "definition not found");
63 continue;
64 };
65
66 items.push(ImplItem::Const(syn::ImplItemConst {
67 attrs: copy_non_doc_attrs(&item.attrs),
68 vis: syn::Visibility::Inherited,
69 defaultness: None,
70 const_token: item.const_token,
71 ident: item.ident.clone(),
72 generics: item.generics.clone(),
73 colon_token: item.colon_token,
74 ty: item.ty.clone(),
75 eq_token,
76 expr,
77 semi_token: item.semi_token,
78 }));
79 }
80 TraitItem::Fn(item) => {
81 let Some(block) = item.default.take() else {
82 emit_error!(item, "definition not found");
83 continue;
84 };
85
86 items.push(ImplItem::Fn(syn::ImplItemFn {
87 attrs: copy_non_doc_attrs(&item.attrs),
88 vis: syn::Visibility::Inherited,
89 defaultness: None,
90 sig: item.sig.clone(),
91 block,
92 }));
93
94 item.attrs.retain(|attr| attr.path_as_string() != "inline");
95 }
96 TraitItem::Type(item) => {
97 let Some((eq_token, ty)) = item.default.take() else {
98 emit_error!(item, "definition not found");
99 continue;
100 };
101
102 items.push(ImplItem::Type(syn::ImplItemType {
103 attrs: copy_non_doc_attrs(&item.attrs),
104 vis: syn::Visibility::Inherited,
105 defaultness: None,
106 type_token: item.type_token,
107 ident: item.ident.clone(),
108 generics: item.generics.clone(),
109 eq_token,
110 ty,
111 semi_token: item.semi_token,
112 }));
113 }
114 other => emit_error!(other, "unsupported trait item"),
115 }
116 }
117
118 let mut generics = self.generics;
119 utils::extend_generics(&mut generics, &trait_.generics);
120
121 let ident = &trait_.ident;
122 let (_, ty_generics, _) = trait_.generics.split_for_impl();
123 let path = parse_quote! { #ident #ty_generics };
124
125 let impl_ = syn::ItemImpl {
126 attrs,
127 defaultness: None,
128 unsafety: None,
129 impl_token: Default::default(),
130 generics,
131 trait_: Some((None, path, self.for_)),
132 self_ty: self.target,
133 brace_token: Default::default(),
134 items,
135 };
136
137 quote! { #trait_ #impl_ }
138 }
139}