diff options
Diffstat (limited to 'src/transform.rs')
-rw-r--r-- | src/transform.rs | 98 |
1 files changed, 59 insertions, 39 deletions
diff --git a/src/transform.rs b/src/transform.rs index 60ac6e8..05866b6 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -23,26 +23,32 @@ pub struct TypeConverter<'a> { pub enum TransformError { AssocTypeWithoutDestType, UnsupportedType, + ExpectedAtLeastNTypes(usize), + AssocTypeAfterFirstNTypes(usize, Ident), } impl TypeConverter<'_> { - /// Returns true for types that take one generic type parameter T - /// and implement IntoIterator<Item=T> and FromIterator<T> - fn known_as_collection_with_one_type(&self, ident: &Ident) -> bool { + /// A return type of Some(1) means that the type implements + /// IntoIterator<Item=T1> and FromIterator<T1> + /// with T1 being its first generic type parameter. + /// + /// A return type of Some(2) means that the type implements + /// IntoIterator<Item=(T1, T2)> and FromIterator<(T1, T2)> + /// with T1 and T2 being its first two generic type parameters. + /// + /// ... etc. A return type of None means the type isn't recognized. + #[rustfmt::skip] + fn get_collection_type_count(&self, ident: &Ident) -> Option<usize> { // when adding a type here don't forget to document it in the README - ident == "Vec" - || ident == "VecDeque" - || ident == "LinkedList" - || ident == "HashSet" - || ident == "BinaryHeap" - || ident == "BTreeSet" - } - - /// Returns true for types that take two generic type parameter K and V - /// and implement IntoIterator<Item=(K, V)> and FromIterator<(K, V)> - fn known_as_collection_with_two_types(&self, ident: &Ident) -> bool { - // when adding a type here don't forget to document it in the README - ident == "HashMap" || ident == "BTreeMap" + if ident == "Vec" { return Some(1); } + if ident == "VecDeque" { return Some(1); } + if ident == "LinkedList" { return Some(1); } + if ident == "HashSet" { return Some(1); } + if ident == "BinaryHeap" { return Some(1); } + if ident == "BTreeSet" { return Some(1); } + if ident == "HashMap" { return Some(2); } + if ident == "BTreeMap" { return Some(2); } + None } pub fn convert_type(&self, type_: &mut Type) -> Result<TypeTransform, (Span, TransformError)> { @@ -113,36 +119,50 @@ impl TypeConverter<'_> { if let PathArguments::AngleBracketed(args) = &mut last_seg.arguments { let mut args: Vec<_> = type_arguments_mut(&mut args.args).collect(); - if args.len() == 1 { - if iter_type(args[0]).any(match_assoc_type) { - if (last_seg.ident == "Option" && path_len == 1) - || last_seg.ident == "Result" - { - return Ok(TypeTransform::Map(self.convert_type(args[0])?.into())); - } else if self.known_as_collection_with_one_type(&last_seg.ident) - && path_len == 1 - { - return Ok(TypeTransform::IntoIterMapCollect(vec![ - self.convert_type(args[0])? - ])); + if path_len == 1 { + if let Some(type_count) = self.get_collection_type_count(&last_seg.ident) { + if args.len() < type_count { + return Err(( + last_seg.span(), + TransformError::ExpectedAtLeastNTypes(type_count), + )); + } + for i in type_count..args.len() { + if iter_type(args[i]).any(match_assoc_type) { + return Err(( + args[i].span(), + TransformError::AssocTypeAfterFirstNTypes( + type_count, + last_seg.ident.clone(), + ), + )); + } + } + let mut transforms = Vec::new(); + for arg in args { + transforms.push(self.convert_type(arg)?); } + return Ok(TypeTransform::IntoIterMapCollect(transforms)); + } + } + + if args.len() == 1 { + if iter_type(args[0]).any(match_assoc_type) + && ((last_seg.ident == "Option" && path_len == 1) + || last_seg.ident == "Result") + { + return Ok(TypeTransform::Map(self.convert_type(args[0])?.into())); } } else if args.len() == 2 && path_len == 1 && (iter_type(args[0]).any(match_assoc_type) || iter_type(args[1]).any(match_assoc_type)) + && last_seg.ident == "Result" { - if last_seg.ident == "Result" { - return Ok(TypeTransform::Result( - self.convert_type(args[0])?.into(), - self.convert_type(args[1])?.into(), - )); - } else if self.known_as_collection_with_two_types(&last_seg.ident) { - return Ok(TypeTransform::IntoIterMapCollect(vec![ - self.convert_type(args[0])?, - self.convert_type(args[1])?, - ])); - } + return Ok(TypeTransform::Result( + self.convert_type(args[0])?.into(), + self.convert_type(args[1])?.into(), + )); } } } |