pub(crate) fn extract_signature_params(sig: &syn::Signature) -> Vec<(String, &syn::Type)> {
sig.inputs
.iter()
.filter_map(|arg| match arg {
syn::FnArg::Typed(pt) => {
param_name_from_pat(pt.pat.as_ref()).map(|n| (n, pt.ty.as_ref()))
}
_ => None,
})
.collect()
}
pub(crate) fn extract_method_generic_params(
sig: &syn::Signature,
outer_names: &[&str],
) -> Vec<(String, Vec<Vec<String>>)> {
let mut bounds_by_name = collect_inline_bounds(&sig.generics);
if let Some(where_clause) = sig.generics.where_clause.as_ref() {
merge_where_bounds_extending(&mut bounds_by_name, where_clause, outer_names);
}
bounds_by_name
}
pub(crate) fn extract_generics(generics: &syn::Generics) -> Vec<(String, Vec<Vec<String>>)> {
let mut bounds_by_name = collect_inline_bounds(generics);
if let Some(where_clause) = generics.where_clause.as_ref() {
merge_where_bounds(&mut bounds_by_name, where_clause);
}
bounds_by_name
}
fn collect_inline_bounds(generics: &syn::Generics) -> Vec<(String, Vec<Vec<String>>)> {
generics
.params
.iter()
.filter_map(|p| match p {
syn::GenericParam::Type(tp) => {
Some((tp.ident.to_string(), trait_bound_paths(&tp.bounds)))
}
_ => None,
})
.collect()
}
pub(crate) fn merge_generic_params(
outer: Vec<(String, Vec<Vec<String>>)>,
inner: Vec<(String, Vec<Vec<String>>)>,
) -> Vec<(String, Vec<Vec<String>>)> {
let mut out = outer;
for (name, bounds) in inner {
match out.iter_mut().find(|(n, _)| n == &name) {
Some(entry) => entry.1.extend(bounds),
None => out.push((name, bounds)),
}
}
out
}
fn merge_where_bounds(
bounds_by_name: &mut [(String, Vec<Vec<String>>)],
where_clause: &syn::WhereClause,
) {
for_each_simple_predicate(where_clause, |name, bounds| {
if let Some(entry) = bounds_by_name.iter_mut().find(|(n, _)| n == &name) {
entry.1.extend(bounds);
}
});
}
fn merge_where_bounds_extending(
bounds_by_name: &mut Vec<(String, Vec<Vec<String>>)>,
where_clause: &syn::WhereClause,
extending_names: &[&str],
) {
for_each_simple_predicate(where_clause, |name, bounds| {
if let Some(entry) = bounds_by_name.iter_mut().find(|(n, _)| n == &name) {
entry.1.extend(bounds);
} else if extending_names.iter().any(|n| *n == name) {
bounds_by_name.push((name, bounds));
}
});
}
fn for_each_simple_predicate<F: FnMut(String, Vec<Vec<String>>)>(
where_clause: &syn::WhereClause,
mut sink: F,
) {
for predicate in &where_clause.predicates {
let syn::WherePredicate::Type(pt) = predicate else {
continue;
};
let Some(name) = single_ident_type(&pt.bounded_ty) else {
continue;
};
sink(name, trait_bound_paths(&pt.bounds));
}
}
fn single_ident_type(ty: &syn::Type) -> Option<String> {
let syn::Type::Path(p) = ty else {
return None;
};
super::type_infer::single_ident_of(p)
}
fn trait_bound_paths(
bounds: &syn::punctuated::Punctuated<syn::TypeParamBound, syn::Token![+]>,
) -> Vec<Vec<String>> {
bounds
.iter()
.filter_map(|b| match b {
syn::TypeParamBound::Trait(tb) => Some(
tb.path
.segments
.iter()
.map(|s| s.ident.to_string())
.collect(),
),
_ => None,
})
.collect()
}
fn param_name_from_pat(pat: &syn::Pat) -> Option<String> {
match pat {
syn::Pat::Ident(pi) => Some(pi.ident.to_string()),
syn::Pat::TupleStruct(ts) if ts.elems.len() == 1 => {
if let syn::Pat::Ident(pi) = &ts.elems[0] {
return Some(pi.ident.to_string());
}
None
}
_ => None,
}
}