aboutsummaryrefslogtreecommitdiff
path: root/src/transform.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/transform.rs')
-rw-r--r--src/transform.rs98
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(),
+ ));
}
}
}