diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 4 | ||||
-rw-r--r-- | src/parse_trait_sig.rs | 1 | ||||
-rw-r--r-- | src/syn_utils.rs | 2 | ||||
-rw-r--r-- | src/transform.rs | 46 |
4 files changed, 49 insertions, 4 deletions
@@ -390,6 +390,10 @@ impl TypeTransform { let inner = opt.convert(quote!(x)); quote! {#arg.map(|x| #inner)} } + TypeTransform::Iterator(inner) => { + let inner = inner.convert(quote!(x)); + quote! {Box::new(#arg.map(|x| #inner))} + } TypeTransform::Result(ok, err) => { let map_ok = !matches!(ok.as_ref(), TypeTransform::NoOp); let map_err = !matches!(err.as_ref(), TypeTransform::NoOp); diff --git a/src/parse_trait_sig.rs b/src/parse_trait_sig.rs index 82b8ee9..cf2d7da 100644 --- a/src/parse_trait_sig.rs +++ b/src/parse_trait_sig.rs @@ -17,6 +17,7 @@ pub enum TypeTransform { Into, Box(BoxType), Map(Box<TypeTransform>), + Iterator(Box<TypeTransform>), Result(Box<TypeTransform>, Box<TypeTransform>), } diff --git a/src/syn_utils.rs b/src/syn_utils.rs index 43c4d94..ea4b5ea 100644 --- a/src/syn_utils.rs +++ b/src/syn_utils.rs @@ -128,6 +128,8 @@ fn types_in_path(p: &Path) -> impl Iterator<Item = &Type> { PathArguments::AngleBracketed(ang) => { IterEnum::Left(ang.args.iter().flat_map(|a| match a { GenericArgument::Type(t) => Some(t), + GenericArgument::Binding(b) => Some(&b.ty), + // TODO: handle GenericArgument::Constraint _other => None, })) } diff --git a/src/transform.rs b/src/transform.rs index b13b7cf..fff9c6c 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -1,9 +1,10 @@ use std::collections::HashMap; use proc_macro2::Span; +use quote::quote; use syn::{ spanned::Spanned, GenericArgument, Generics, Ident, PathArguments, TraitBound, Type, - TypeParamBound, TypePath, WherePredicate, + TypeParamBound, TypePath, TypeReference, TypeTraitObject, WherePredicate, }; use crate::{ @@ -28,12 +29,49 @@ impl AssocTypeConversions<'_> { None => return Ok(TypeTransform::NoOp), }; + if let Type::Reference(TypeReference { + lifetime: None, + mutability: Some(_), + elem, + .. + }) = type_ + { + if let Type::TraitObject(TypeTraitObject { + dyn_token: Some(_), + bounds, + }) = elem.as_mut() + { + if bounds.len() == 1 { + if let TypeParamBound::Trait(bound) = bounds.first_mut().unwrap() { + if bound.path.segments.len() == 1 { + let first = bound.path.segments.first_mut().unwrap(); + if first.ident == "Iterator" { + if let PathArguments::AngleBracketed(args) = &mut first.arguments { + if args.args.len() == 1 { + if let GenericArgument::Binding(binding) = + args.args.first_mut().unwrap() + { + if binding.ident == "Item" + && iter_type(&binding.ty).any(match_assoc_type) + { + let inner = + self.parse_type_path(&mut binding.ty)?; + *type_ = Type::Verbatim(quote! {Box<#elem + '_>}); + return Ok(TypeTransform::Iterator(inner.into())); + } + } + } + } + } + } + } + } + } + } + if let Type::Path(TypePath { path, qself: None }) = type_ { let ident = &path.segments.first().unwrap().ident; - // TODO: support &mut dyn Iterator<Item = Self::A> - // conversion to Box<dyn Iterator<Item = Whatever>> via .map(Into::into) - if ident == "Self" && path.segments.len() == 2 { let ident = &path.segments.last().unwrap().ident; let dest_type = self |