//! Types for working with generics use std::iter::Iterator; use std::slice::Iter; use crate::{FromGenericParam, FromGenerics, FromTypeParam, Result}; /// Extension trait for `GenericParam` to support getting values by variant. /// /// # Usage /// `darling::ast::Generics` needs a way to test its params array in order to iterate over type params. /// Rather than require callers to use `darling::ast::GenericParam` in all cases, this trait makes that /// polymorphic. pub trait GenericParamExt { /// The type this GenericParam uses to represent type params and their bounds type TypeParam; type LifetimeParam; type ConstParam; /// If this GenericParam is a type param, get the underlying value. fn as_type_param(&self) -> Option<&Self::TypeParam> { None } /// If this GenericParam is a lifetime, get the underlying value. fn as_lifetime_param(&self) -> Option<&Self::LifetimeParam> { None } /// If this GenericParam is a const param, get the underlying value. fn as_const_param(&self) -> Option<&Self::ConstParam> { None } } impl GenericParamExt for syn::GenericParam { type TypeParam = syn::TypeParam; type LifetimeParam = syn::LifetimeParam; type ConstParam = syn::ConstParam; fn as_type_param(&self) -> Option<&Self::TypeParam> { if let syn::GenericParam::Type(ref val) = *self { Some(val) } else { None } } fn as_lifetime_param(&self) -> Option<&Self::LifetimeParam> { if let syn::GenericParam::Lifetime(ref val) = *self { Some(val) } else { None } } fn as_const_param(&self) -> Option<&Self::ConstParam> { if let syn::GenericParam::Const(ref val) = *self { Some(val) } else { None } } } impl GenericParamExt for syn::TypeParam { type TypeParam = syn::TypeParam; type LifetimeParam = (); type ConstParam = (); fn as_type_param(&self) -> Option<&Self::TypeParam> { Some(self) } } /// A mirror of `syn::GenericParam` which is generic over all its contents. #[derive(Debug, Clone, PartialEq, Eq)] pub enum GenericParam { Type(T), Lifetime(L), Const(C), } impl FromTypeParam for GenericParam { fn from_type_param(type_param: &syn::TypeParam) -> Result { Ok(GenericParam::Type(FromTypeParam::from_type_param( type_param, )?)) } } impl FromGenericParam for GenericParam { fn from_generic_param(param: &syn::GenericParam) -> Result { Ok(match *param { syn::GenericParam::Type(ref ty) => { GenericParam::Type(FromTypeParam::from_type_param(ty)?) } syn::GenericParam::Lifetime(ref val) => GenericParam::Lifetime(val.clone()), syn::GenericParam::Const(ref val) => GenericParam::Const(val.clone()), }) } } impl GenericParamExt for GenericParam { type TypeParam = T; type LifetimeParam = L; type ConstParam = C; fn as_type_param(&self) -> Option<&T> { if let GenericParam::Type(ref val) = *self { Some(val) } else { None } } fn as_lifetime_param(&self) -> Option<&L> { if let GenericParam::Lifetime(ref val) = *self { Some(val) } else { None } } fn as_const_param(&self) -> Option<&C> { if let GenericParam::Const(ref val) = *self { Some(val) } else { None } } } /// A mirror of the `syn::Generics` type which can contain arbitrary representations /// of params and where clauses. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Generics { pub params: Vec

, pub where_clause: Option, } impl Generics { pub fn type_params(&self) -> TypeParams<'_, P> { TypeParams(self.params.iter()) } } impl FromGenerics for Generics

{ fn from_generics(generics: &syn::Generics) -> Result { Ok(Generics { params: generics .params .iter() .map(FromGenericParam::from_generic_param) .collect::>>()?, where_clause: generics.where_clause.clone(), }) } } pub struct TypeParams<'a, P: 'a>(Iter<'a, P>); impl<'a, P: GenericParamExt> Iterator for TypeParams<'a, P> { type Item = &'a

::TypeParam; fn next(&mut self) -> Option { let next = self.0.next(); match next { None => None, Some(v) => match v.as_type_param() { Some(val) => Some(val), None => self.next(), }, } } } #[cfg(test)] mod tests { use syn::parse_quote; use super::{GenericParam, Generics}; use crate::FromGenerics; #[test] fn generics() { let g: syn::Generics = parse_quote!(); let deified: Generics> = FromGenerics::from_generics(&g).unwrap(); assert!(deified.params.len() == 1); assert!(deified.where_clause.is_none()); } }