aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Fischer <martin@push-f.com>2021-11-22 06:36:37 +0100
committerMartin Fischer <martin@push-f.com>2021-11-22 07:45:30 +0100
commitbacdafb4883d8f8ea06e498285c78f82de9a391b (patch)
tree30f3f795e2b8c4895cea7e708ca4a1fe46eedd0c
parenta973a628ec051ab9483fde7d694bb261bb793178 (diff)
support Vec, VecDeque & LinkedList collections
-rw-r--r--README.md1
-rw-r--r--src/lib.rs6
-rw-r--r--src/parse_trait_sig.rs1
-rw-r--r--src/transform.rs21
-rw-r--r--tests/tests.rs15
5 files changed, 43 insertions, 1 deletions
diff --git a/README.md b/README.md
index 6b4d4e1..cf5d0c1 100644
--- a/README.md
+++ b/README.md
@@ -90,6 +90,7 @@ Dynamize also understands if you wrap associated types in the following types:
* `Option<_>`
* `Result<_, _>`
* `some::module::Result<_>` (type alias with fixed error type)
+* `Vec<_>`, `VecDeque<_>`,`LinkedList<_>`
* `&mut dyn Iterator<Item = _>`
Note that since these are resolved recursively you can actually nest these
diff --git a/src/lib.rs b/src/lib.rs
index 1f75023..6a1708f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -409,7 +409,11 @@ impl TypeTransform {
quote! {#arg.map_err(|x| #err_inner)}
}
}
- _other => arg,
+ TypeTransform::Collection(inner) => {
+ let inner = inner.convert(quote!(x));
+ quote! {#arg.into_iter().map(|x| #inner).collect()}
+ }
+ TypeTransform::NoOp => arg,
}
}
}
diff --git a/src/parse_trait_sig.rs b/src/parse_trait_sig.rs
index ab2c437..c924a71 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>),
+ Collection(Box<TypeTransform>),
Iterator(BoxType, Box<TypeTransform>),
Result(Box<TypeTransform>, Box<TypeTransform>),
}
diff --git a/src/transform.rs b/src/transform.rs
index e8481bb..3f1c313 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -22,6 +22,12 @@ pub enum TransformError {
AssocTypeInUnsupportedType(Span),
}
+fn is_supported_collection(ident: &Ident) -> bool {
+ // collections added here must implement IntoIterator & FromIterator
+ // FromIterator must not require bounds like Eq or Ord since these are Self-referential
+ ident == "Vec" || ident == "VecDeque" || ident == "LinkedList"
+}
+
impl AssocTypeConversions<'_> {
pub fn parse_type_path(&self, type_: &mut Type) -> Result<TypeTransform, TransformError> {
if !iter_type(type_).any(match_assoc_type) {
@@ -120,6 +126,21 @@ impl AssocTypeConversions<'_> {
}
}
}
+ } else if is_supported_collection(ident) && path.segments.len() == 1 {
+ let first_seg = path.segments.first_mut().unwrap();
+
+ if let PathArguments::AngleBracketed(args) = &mut first_seg.arguments {
+ if args.args.len() == 1 {
+ if let GenericArgument::Type(generic_type) = args.args.first_mut().unwrap()
+ {
+ if iter_type(generic_type).any(match_assoc_type) {
+ return Ok(TypeTransform::Collection(
+ self.parse_type_path(generic_type)?.into(),
+ ));
+ }
+ }
+ }
+ }
} else {
let last_seg = &path.segments.last().unwrap();
if last_seg.ident == "Result" {
diff --git a/tests/tests.rs b/tests/tests.rs
index bae52bd..7801cfc 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -204,6 +204,21 @@ fn test3<T: TypeWithSuper>(some: T) {
println!("{}", dyn_trait);
}
+use std::collections::{LinkedList, VecDeque};
+
+#[dynamize::dynamize]
+trait Collections {
+ type A: std::error::Error;
+
+ fn vec(&self) -> Vec<Self::A>;
+
+ fn vec_deque(&self) -> VecDeque<Self::A>;
+
+ fn linked_list(&self) -> LinkedList<Self::A>;
+
+ fn vec_opt(&self) -> Vec<Option<Self::A>>;
+}
+
#[dynamize::dynamize]
trait ReturnIter {
type A: std::error::Error;