1use std::{collections::HashMap, mem};
2
3use darling::{export::NestedMeta, util::PathList, FromMeta, ToTokens};
4use proc_macro2::Ident;
5use replace_types::{ReplaceTypes, VisitMut};
6use syn::{parse_macro_input, Attribute, ItemImpl, Path, TypePath};
7
8fn parse_substitutions(
9 nested: impl AsRef<[NestedMeta]>,
10) -> darling::Result<HashMap<TypePath, TypePath>> {
11 let substitutions = HashMap::<Ident, TypePath>::from_list(nested.as_ref())?;
12
13 let substitutions: HashMap<TypePath, TypePath> = substitutions
14 .into_iter()
15 .map(|(ident, type_path)| {
16 (
17 TypePath {
18 qself: None,
19 path: Path::from(ident),
20 },
21 type_path,
22 )
23 })
24 .collect();
25
26 Ok(substitutions)
27}
28
29#[proc_macro_attribute]
59pub fn impl_for(
60 args: proc_macro::TokenStream,
61 input: proc_macro::TokenStream,
62) -> proc_macro::TokenStream {
63 let mut input = parse_macro_input!(input as ItemImpl);
64
65 let mut errors: Vec<darling::Error> = Vec::new();
66 let mut substitutions_list: Vec<HashMap<TypePath, TypePath>> = Vec::new();
67
68 match NestedMeta::parse_meta_list(args.into())
69 .map_err(darling::Error::from)
70 .and_then(parse_substitutions)
71 {
72 Ok(substitutions) => {
73 substitutions_list.push(substitutions);
74 }
75 Err(err) => {
76 errors.push(err);
77 }
78 }
79
80 let mut attrs: Vec<Attribute> = Vec::new();
81
82 let input_attrs = mem::take(&mut input.attrs);
83
84 for attr in input_attrs.into_iter() {
85 if attr.path().is_ident("impl_for") {
86 match attr.meta.require_list() {
87 Ok(list) => {
88 match NestedMeta::parse_meta_list(list.tokens.to_owned())
89 .map_err(darling::Error::from)
90 .and_then(parse_substitutions)
91 {
92 Ok(substitutions) => {
93 substitutions_list.push(substitutions);
94 }
95 Err(err) => {
96 errors.push(err);
97 }
98 }
99 }
100 Err(err) => {
101 errors.push(err.into());
102 }
103 }
104 } else {
105 attrs.push(attr);
106 }
107 }
108
109 if !errors.is_empty() {
110 return darling::Error::multiple(errors).write_errors().into();
111 }
112
113 input.attrs = attrs;
114
115 substitutions_list
116 .into_iter()
117 .map(|substitutions| {
118 let mut item_impl = input.clone();
119 ReplaceTypes::new(substitutions).visit_item_impl_mut(&mut item_impl);
120 proc_macro::TokenStream::from(item_impl.into_token_stream())
121 })
122 .collect::<proc_macro::TokenStream>()
123}
124
125#[proc_macro_attribute]
146pub fn impl_for_each(
147 args: proc_macro::TokenStream,
148 input: proc_macro::TokenStream,
149) -> proc_macro::TokenStream {
150 let input = parse_macro_input!(input as ItemImpl);
151
152 let substitutions_list: Vec<HashMap<TypePath, TypePath>> =
153 match NestedMeta::parse_meta_list(args.into())
154 .map_err(darling::Error::from)
155 .and_then(|meta_list| PathList::from_list(meta_list.as_slice()))
156 {
157 Ok(substitutions) => {
158 let t_type = TypePath {
159 qself: None,
160 path: Path::from(Ident::from_string("T").unwrap()),
161 };
162
163 substitutions
164 .iter()
165 .map(|path| {
166 HashMap::<TypePath, TypePath>::from(
167 [(
168 t_type.clone(),
169 TypePath {
170 qself: None,
171 path: path.to_owned(),
172 },
173 ); 1],
174 )
175 })
176 .collect()
177 }
178 Err(err) => {
179 return err.write_errors().into();
180 }
181 };
182
183 substitutions_list
184 .into_iter()
185 .map(|substitutions| {
186 let mut item_impl = input.clone();
187 ReplaceTypes::new(substitutions).visit_item_impl_mut(&mut item_impl);
188 proc_macro::TokenStream::from(item_impl.into_token_stream())
189 })
190 .collect::<proc_macro::TokenStream>()
191}