use crate::VerbatimUntil;
#[cfg(test)]
use proc_macro2::TokenStream;
use unsynn::*;
unsynn! {
#[derive(Clone)]
pub struct AngleTokenTree(
#[allow(clippy::type_complexity)] pub Either<Cons<Lt, Vec<Cons<Except<Gt>, AngleTokenTree>>, Gt>, TokenTree>,
);
pub struct TypeParam {
pub name: Ident,
pub bounds: Option<Cons<Colon, VerbatimUntil<Either<Comma,Gt>>>>,
}
pub struct GenericParams {
pub _lt: Lt,
pub params: CommaDelimitedVec<TypeParam>,
pub _gt: Gt,
}
}
#[cfg(test)]
pub fn parse_generics_for_test(input: TokenStream) -> Option<GenericParams> {
let mut it = input.to_token_iter();
it.parse::<GenericParams>().ok()
}
#[cfg(test)]
mod tests {
use super::*;
use quote::quote;
#[test]
fn test_no_generics() {
let input = quote! { fn_name() };
let generics = parse_generics_for_test(input);
assert!(generics.is_none());
}
#[test]
fn test_simple_generics() {
let input = quote! { <T> };
let generics = parse_generics_for_test(input).expect("should parse");
assert_eq!(generics.params.len(), 1);
assert_eq!(generics.params[0].value.name.to_string(), "T");
assert!(generics.params[0].value.bounds.is_none());
}
#[test]
fn test_multiple_generics() {
let input = quote! { <T, U, V> };
let generics = parse_generics_for_test(input).expect("should parse");
assert_eq!(generics.params.len(), 3);
assert_eq!(generics.params[0].value.name.to_string(), "T");
assert_eq!(generics.params[1].value.name.to_string(), "U");
assert_eq!(generics.params[2].value.name.to_string(), "V");
}
#[test]
fn test_generics_with_bounds() {
let input = quote! { <T: Clone, U: Send> };
let generics = parse_generics_for_test(input).expect("should parse");
assert_eq!(generics.params.len(), 2);
assert_eq!(generics.params[0].value.name.to_string(), "T");
assert!(generics.params[0].value.bounds.is_some());
assert_eq!(generics.params[1].value.name.to_string(), "U");
assert!(generics.params[1].value.bounds.is_some());
}
#[test]
fn test_complex_generics() {
let input = quote! { <T: Add<Output = T>, U: Iterator<Item = String>> };
let generics = parse_generics_for_test(input).expect("should parse");
assert_eq!(generics.params.len(), 2);
assert_eq!(generics.params[0].value.name.to_string(), "T");
assert_eq!(generics.params[1].value.name.to_string(), "U");
assert!(generics.params[0].value.bounds.is_some());
assert!(generics.params[1].value.bounds.is_some());
}
#[test]
fn test_empty_generics() {
let input = quote! { <> };
let generics = parse_generics_for_test(input).expect("should parse");
assert_eq!(generics.params.len(), 0);
}
}