use syn::{punctuated::Punctuated, Ident, PathArguments, ReturnType, Token, Type, TypePath};
pub fn switch_to_inner(
fn_output: &ReturnType,
parsed_args: &Punctuated<Ident, Token![,]>,
struct_name: &Ident, ) -> ReturnType {
let generic_idents: Vec<syn::GenericArgument> = parsed_args
.iter()
.map(|i| {
syn::GenericArgument::Type(Type::Path(TypePath {
qself: None,
path: i.clone().into(),
}))
})
.collect();
let original_return_type = match &fn_output {
ReturnType::Type(_, ty) => &**ty,
_ => panic!("Expected a return type."),
};
let mut modified_return_type = original_return_type.clone();
recursively_modify_return_type(&mut modified_return_type, generic_idents, struct_name);
ReturnType::Type(Default::default(), Box::new(modified_return_type))
}
fn recursively_modify_return_type(
ty: &mut Type,
generic_idents: Vec<syn::GenericArgument>,
struct_name: &Ident, ) {
match ty {
Type::Path(type_path) => {
let last_segment = type_path.path.segments.last_mut().unwrap();
if last_segment.ident == *struct_name {
modify_type_path(type_path, generic_idents);
} else {
if let PathArguments::AngleBracketed(arguments) = &mut last_segment.arguments {
for arg in &mut arguments.args {
if let syn::GenericArgument::Type(inner_type) = arg {
recursively_modify_return_type(
inner_type,
generic_idents.clone(),
struct_name,
);
}
}
}
}
}
_ => panic!("Expected a path type."),
}
}
fn modify_type_path(type_path: &mut TypePath, generic_idents: Vec<syn::GenericArgument>) {
let last_segment = type_path.path.segments.last_mut().unwrap();
match &mut last_segment.arguments {
PathArguments::AngleBracketed(arguments) => {
arguments.args.extend(generic_idents);
}
PathArguments::None => {
last_segment.arguments =
PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
args: generic_idents.into_iter().collect(),
colon2_token: None,
lt_token: Default::default(),
gt_token: Default::default(),
});
}
_ => panic!("Unsupported path arguments in return type."),
}
}