miniextendr_macros/miniextendr_impl_trait/
defaults.rs1use std::collections::HashMap;
4
5use syn::visit_mut::VisitMut;
6
7pub(super) fn inherited_methods(
10 implementation: &syn::ItemImpl,
11 declaration: &[syn::TraitItemFn],
12 generics: &syn::Generics,
13 trait_path: &syn::Path,
14) -> syn::Result<Vec<syn::ImplItemFn>> {
15 let missing: Vec<_> = declaration
16 .iter()
17 .filter(|method| {
18 method.default.is_some()
19 && !implementation.items.iter().any(|item| {
20 #[allow(non_exhaustive_omitted_patterns)] match item {
syn::ImplItem::Fn(own) if own.sig.ident == method.sig.ident => true,
_ => false,
}matches!(item, syn::ImplItem::Fn(own) if own.sig.ident == method.sig.ident)
21 })
22 })
23 .collect();
24 if missing.is_empty() {
25 return Ok(Vec::new());
26 }
27
28 let mut arguments = Substitution::new(generics, trait_path)?;
29 arguments.self_type = Some((*implementation.self_ty).clone());
30 arguments.trait_path = Some(trait_path.clone());
31 missing
32 .into_iter()
33 .map(|method| {
34 let mut sig = method.sig.clone();
35 arguments.visit_signature_mut(&mut sig);
36 let attrs = &method.attrs;
37 syn::parse2({
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut attrs, i) = attrs.quote_into_iter();
let has_iter = has_iter | i;
<_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let attrs =
match attrs.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&attrs, &mut _s);
}
}
::quote::ToTokens::to_tokens(&sig, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
::quote::__private::TokenStream::new());
_s
}quote::quote! { #(#attrs)* #sig {} })
38 })
39 .collect()
40}
41
42#[derive(#[automatically_derived]
impl ::core::default::Default for Substitution {
#[inline]
fn default() -> Self {
Substitution {
types: ::core::default::Default::default(),
consts: ::core::default::Default::default(),
lifetimes: ::core::default::Default::default(),
self_type: ::core::default::Default::default(),
trait_path: ::core::default::Default::default(),
}
}
}Default)]
43struct Substitution {
44 types: HashMap<syn::Ident, syn::Type>,
45 consts: HashMap<syn::Ident, syn::Expr>,
46 lifetimes: HashMap<syn::Lifetime, syn::Lifetime>,
47 self_type: Option<syn::Type>,
48 trait_path: Option<syn::Path>,
49}
50
51impl Substitution {
52 fn new(generics: &syn::Generics, trait_path: &syn::Path) -> syn::Result<Self> {
53 let supplied: Vec<_> = match &trait_path.segments.last().unwrap().arguments {
54 syn::PathArguments::AngleBracketed(args) => args.args.iter().collect(),
55 _ => Vec::new(),
56 };
57 let mut supplied = supplied.into_iter().peekable();
58 let mut result = Self::default();
59 for param in &generics.params {
60 match param {
61 syn::GenericParam::Type(param) => {
62 let ty = match supplied.next() {
63 Some(syn::GenericArgument::Type(ty)) => ty.clone(),
64 None if param.default.is_some() => {
65 let mut ty = param.default.clone().unwrap();
66 result.visit_type_mut(&mut ty);
69 ty
70 }
71 _ => {
72 return Err(syn::Error::new_spanned(
73 trait_path,
74 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected a concrete argument for trait type parameter `{0}`",
param.ident))
})format!(
75 "expected a concrete argument for trait type parameter `{}`",
76 param.ident,
77 ),
78 ));
79 }
80 };
81 result.types.insert(param.ident.clone(), ty);
82 }
83 syn::GenericParam::Const(param) => {
84 let value = match supplied.next() {
85 Some(syn::GenericArgument::Const(value)) => value.clone(),
86 Some(syn::GenericArgument::Type(ty)) => syn::parse2({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&ty, &mut _s);
_s
}quote::quote!(#ty))?,
89 None if param.default.is_some() => {
90 let mut value = param.default.clone().unwrap();
91 result.visit_expr_mut(&mut value);
92 value
93 }
94 _ => {
95 return Err(syn::Error::new_spanned(
96 trait_path,
97 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected a concrete argument for trait const parameter `{0}`",
param.ident))
})format!(
98 "expected a concrete argument for trait const parameter `{}`",
99 param.ident,
100 ),
101 ));
102 }
103 };
104 result.consts.insert(param.ident.clone(), value);
105 }
106 syn::GenericParam::Lifetime(param) => {
107 let lifetime = match supplied.peek() {
108 Some(syn::GenericArgument::Lifetime(_)) => {
109 let Some(syn::GenericArgument::Lifetime(value)) = supplied.next()
110 else {
111 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
112 };
113 value.clone()
114 }
115 _ => ::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lifetime(&mut _s, "\'_");
_s
})syn::parse_quote!('_),
116 };
117 result.lifetimes.insert(param.lifetime.clone(), lifetime);
118 }
119 }
120 }
121 Ok(result)
122 }
123}
124
125impl VisitMut for Substitution {
126 fn visit_type_mut(&mut self, ty: &mut syn::Type) {
127 if let syn::Type::Path(path) = ty
128 && path.qself.is_none()
129 && path.path.segments.len() > 1
130 && path.path.segments[0].ident == "Self"
131 && self.self_type.is_some()
132 && self.trait_path.is_some()
133 {
134 let mut associated = path.path.clone();
135 associated.segments = associated.segments.into_iter().skip(1).collect();
136 self.visit_path_mut(&mut associated);
137 let concrete = self.self_type.as_ref().unwrap();
138 let trait_path = self.trait_path.as_ref().unwrap();
139 *ty = ::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&concrete, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::ToTokens::to_tokens(&trait_path, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&associated, &mut _s);
_s
})syn::parse_quote!(<#concrete as #trait_path>::#associated);
140 return;
141 }
142 if let syn::Type::Path(path) = ty
143 && path.qself.is_none()
144 && let Some(name) = path.path.get_ident()
145 && let Some(concrete) = self.types.get(name)
146 {
147 *ty = concrete.clone();
148 return;
149 }
150 syn::visit_mut::visit_type_mut(self, ty);
151 }
152
153 fn visit_expr_mut(&mut self, expr: &mut syn::Expr) {
154 if let syn::Expr::Path(path) = expr
155 && path.qself.is_none()
156 && let Some(name) = path.path.get_ident()
157 && let Some(value) = self.consts.get(name)
158 {
159 *expr = value.clone();
160 return;
161 }
162 syn::visit_mut::visit_expr_mut(self, expr);
163 }
164
165 fn visit_generic_argument_mut(&mut self, arg: &mut syn::GenericArgument) {
166 if let syn::GenericArgument::Type(syn::Type::Path(path)) = arg
169 && let Some(name) = path.path.get_ident()
170 && let Some(value) = self.consts.get(name)
171 {
172 *arg = ::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&value, &mut _s);
_s
});
_s
})syn::parse_quote!({ #value });
173 return;
174 }
175 syn::visit_mut::visit_generic_argument_mut(self, arg);
176 }
177
178 fn visit_lifetime_mut(&mut self, lifetime: &mut syn::Lifetime) {
179 if let Some(concrete) = self.lifetimes.get(lifetime) {
180 *lifetime = concrete.clone();
181 }
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use quote::quote;
189
190 #[test]
191 fn nested_types_consts_lifetimes_and_parameter_defaults() {
192 let generics = syn::parse_quote!(<'a, T, const N: usize, U = Vec<T>>);
193 let path = syn::parse_quote!(Example<'static, i32, 3>);
194 let mut sub = Substitution::new(&generics, &path).unwrap();
195 let mut ty: syn::Type = syn::parse_quote!((&'a [T; N], U, SizedBuffer<N>));
196 sub.visit_type_mut(&mut ty);
197 assert_eq!(
198 quote!(#ty).to_string(),
199 quote!((&'static [i32; 3], Vec<i32>, SizedBuffer<{ 3 }>)).to_string()
200 );
201 }
202
203 #[test]
204 fn caller_types_are_not_reinterpreted_as_declaration_parameters() {
205 let generics = syn::parse_quote!(<T, U>);
206 let path = syn::parse_quote!(Example<i32, T>);
207 let mut sub = Substitution::new(&generics, &path).unwrap();
208 let mut ty: syn::Type = syn::parse_quote!((T, U));
209 sub.visit_type_mut(&mut ty);
210 assert_eq!(quote!(#ty).to_string(), quote!((i32, T)).to_string());
211 }
212
213 #[test]
214 fn only_omitted_defaults_get_synthetic_signatures() {
215 let implementation = syn::parse_quote!(impl Example<i32> for Host {
216 fn own(&self) -> i32 { 9 }
217 });
218 let declaration = vec![
219 syn::parse_quote!(
220 fn own(&self) -> T {}
221 ),
222 syn::parse_quote!(
223 fn required(&self) -> T;
224 ),
225 syn::parse_quote!(
226 #[miniextendr(r_name = "values")]
227 fn inherited(&self, x: Vec<T>) -> T {}
228 ),
229 ];
230 let methods = inherited_methods(
231 &implementation,
232 &declaration,
233 &syn::parse_quote!(<T>),
234 &syn::parse_quote!(Example<i32>),
235 )
236 .unwrap();
237 assert_eq!(methods.len(), 1);
238 let method = &methods[0];
239 assert_eq!(
240 quote!(#method).to_string(),
241 quote!(
242 #[miniextendr(r_name = "values")]
243 fn inherited(&self, x: Vec<i32>) -> i32 {}
244 )
245 .to_string()
246 );
247 }
248}