aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Fischer <martin@push-f.com>2021-11-21 09:37:32 +0100
committerMartin Fischer <martin@push-f.com>2021-11-21 09:39:40 +0100
commit57641e00d6ed1fd7689c3079abb10f67d5387143 (patch)
treeadb48bb70be52bc6035d93826f7725dd64054b49
parent34dc166a9bc003bad36c28aeb29b625195d20a74 (diff)
support -> &mut dyn Iterator<Item = Self::A>
-rw-r--r--src/lib.rs4
-rw-r--r--src/parse_trait_sig.rs1
-rw-r--r--src/syn_utils.rs2
-rw-r--r--src/transform.rs46
-rw-r--r--tests/tests.rs14
5 files changed, 63 insertions, 4 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 439288e..c0286f8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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
diff --git a/tests/tests.rs b/tests/tests.rs
index 3139185..8bbb5b3 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -203,3 +203,17 @@ fn test3<T: TypeWithSuper>(some: T) {
let dyn_trait: &dyn DynTypeWithSuper = &some;
println!("{}", dyn_trait);
}
+
+#[dynamize::dynamize]
+trait ReturnIter {
+ type A: std::error::Error;
+
+ fn foobar(&mut self, text: &str) -> &mut dyn Iterator<Item = Self::A>;
+}
+
+#[dynamize::dynamize]
+trait FunIter {
+ type A: std::error::Error;
+
+ fn foobar<F: Fn(&mut dyn Iterator<Item = Self::A>)>(&mut self, f: F);
+}