use proc_macro2::{Ident, Span, TokenStream}; use quote::format_ident; use syn::token::{Bracket, Paren}; use syn::{ AngleBracketedGenericArguments, AttrStyle, Attribute, BareFnArg, FnArg, GenericArgument, GenericParam, Generics, Lifetime, Path, PathArguments, PathSegment, ReturnType, Signature, Token, Type, TypeBareFn, TypePath, TypeReference, VisRestricted, Visibility, }; pub trait GenericsExt: Sized { fn without_where_clause(self) -> Self; } impl GenericsExt for Generics { fn without_where_clause(mut self) -> Self { self.where_clause = None; self } } pub trait AttributeExt: Sized { fn new(style: AttributeStyle, path: Path, token_stream: TokenStream) -> Self; } impl AttributeExt for Attribute { fn new(style: AttributeStyle, path: Path, token_stream: TokenStream) -> Self { Self { pound_token: ::default(), style: style.into(), bracket_token: Bracket::default(), path, tokens: token_stream, } } } pub enum AttributeStyle { /// A outer attribute. For example like `#[repr(C)]`. Outer, /// A inner attribute. For example like `#![deny(clippy::all)]`. Inner, } impl From for AttrStyle { fn from(style: AttributeStyle) -> Self { match style { AttributeStyle::Outer => Self::Outer, AttributeStyle::Inner => Self::Inner(::default()), } } } pub trait VisibilityExt: Sized { /// Returns a new `pub(crate)` visibility. fn new_pub_crate() -> Self; } impl VisibilityExt for Visibility { fn new_pub_crate() -> Self { Self::Restricted(VisRestricted { pub_token: ::default(), paren_token: Paren::default(), in_token: None, path: Box::new(Path::new( WithLeadingColons::No, [PathSegment::new(format_ident!("crate"), None)], )), }) } } pub trait PathExt: Sized { fn new( with_leading_colons: WithLeadingColons, segments: impl IntoIterator, ) -> Self; } impl PathExt for Path { fn new( with_leading_colons: WithLeadingColons, segments: impl IntoIterator, ) -> Self { Self { leading_colon: match with_leading_colons { WithLeadingColons::Yes => Some(::default()), WithLeadingColons::No => None, }, segments: segments.into_iter().collect(), } } } pub enum WithLeadingColons { Yes, No, } pub trait PathSegmentExt: Sized { fn new(ident: Ident, args: Option) -> Self; } impl PathSegmentExt for PathSegment { fn new(ident: Ident, args: Option) -> Self { Self { ident, arguments: args .map_or_else(|| PathArguments::None, PathArguments::AngleBracketed), } } } pub trait AngleBracketedGenericArgumentsExt: Sized { fn new( with_colons: WithColons, generic_args: impl IntoIterator, ) -> Self; } impl AngleBracketedGenericArgumentsExt for AngleBracketedGenericArguments { fn new( with_colons: WithColons, generic_args: impl IntoIterator, ) -> Self { Self { colon2_token: match with_colons { WithColons::Yes => Some(::default()), WithColons::No => None, }, lt_token: ::default(), args: generic_args.into_iter().collect(), gt_token: <::syn::Token![>]>::default(), } } } pub enum WithColons { Yes, No, } pub trait TypeReferenceExt: Sized { fn new(lifetime: Option, is_mut: IsMut, inner_type: Type) -> Self; } impl TypeReferenceExt for TypeReference { fn new(lifetime: Option, is_mut: IsMut, inner_type: Type) -> Self { Self { and_token: ::default(), lifetime, mutability: is_mut.into(), elem: Box::new(inner_type), } } } pub enum IsMut { Yes, No, } impl From> for IsMut { fn from(opt_mut: Option) -> Self { match opt_mut { Some(_) => Self::Yes, None => Self::No, } } } impl From for Option { fn from(is_mut: IsMut) -> Self { match is_mut { IsMut::Yes => Some(Self::None.unwrap_or_default()), IsMut::No => None, } } } pub trait SignatureExt: Sized { fn new( ident: Ident, generics: Generics, inputs: impl IntoIterator, output: ReturnType, ) -> Self; } impl SignatureExt for Signature { fn new( ident: Ident, generics: Generics, inputs: impl IntoIterator, output: ReturnType, ) -> Self { Self { constness: None, asyncness: None, unsafety: None, abi: None, fn_token: ::default(), ident, generics, paren_token: Paren::default(), inputs: inputs.into_iter().collect(), variadic: None, output, } } } pub trait ReturnTypeExt: Sized { /// Returns a new `ReturnType::Type`. fn new(ty: Type) -> Self; } impl ReturnTypeExt for ReturnType { fn new(ty: Type) -> Self { Self::Type(]>::default(), Box::new(ty)) } } pub trait GenericArgumentExt: Sized { fn from_generic_param(generic_param: GenericParam) -> Self; } impl GenericArgumentExt for GenericArgument { fn from_generic_param(generic_param: GenericParam) -> Self { match generic_param { GenericParam::Type(type_param) => { GenericArgument::Type(Type::Path(TypePath::new(Path::new( WithLeadingColons::No, [PathSegment::new(type_param.ident, None)], )))) } GenericParam::Lifetime(lifetime_param) => { GenericArgument::Lifetime(lifetime_param.lifetime) } GenericParam::Const(_) => { todo!(); } } } } pub trait TypePathExt: Sized { fn new(path: Path) -> Self; } impl TypePathExt for TypePath { fn new(path: Path) -> Self { Self { qself: None, path } } } pub trait TypeBareFnExt: Sized { fn new(inputs: impl IntoIterator, output: ReturnType) -> Self; } impl TypeBareFnExt for TypeBareFn { fn new(inputs: impl IntoIterator, output: ReturnType) -> Self { Self { lifetimes: None, unsafety: None, abi: None, fn_token: ::default(), paren_token: Paren::default(), inputs: inputs.into_iter().collect(), variadic: None, output, } } } pub trait LifetimeExt: Sized { fn create(ident: Ident) -> Self; } impl LifetimeExt for Lifetime { fn create(ident: Ident) -> Self { Self { apostrophe: Span::call_site(), ident, } } } pub trait BareFnArgExt: Sized { fn new(ty: Type) -> Self; } impl BareFnArgExt for BareFnArg { fn new(ty: Type) -> Self { Self { attrs: vec![], name: None, ty, } } }