diff options
author | Martin Fischer <martin@push-f.com> | 2021-11-22 06:36:37 +0100 |
---|---|---|
committer | Martin Fischer <martin@push-f.com> | 2021-11-22 07:45:30 +0100 |
commit | bacdafb4883d8f8ea06e498285c78f82de9a391b (patch) | |
tree | 30f3f795e2b8c4895cea7e708ca4a1fe46eedd0c | |
parent | a973a628ec051ab9483fde7d694bb261bb793178 (diff) |
support Vec, VecDeque & LinkedList collections
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | src/lib.rs | 6 | ||||
-rw-r--r-- | src/parse_trait_sig.rs | 1 | ||||
-rw-r--r-- | src/transform.rs | 21 | ||||
-rw-r--r-- | tests/tests.rs | 15 |
5 files changed, 43 insertions, 1 deletions
@@ -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 @@ -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; |