diff options
author | HampusM <hampus@hampusmat.com> | 2023-03-18 17:14:42 +0100 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2023-03-18 17:15:30 +0100 |
commit | c48271aef7e6b0819c497f302127c161845a83d7 (patch) | |
tree | a18d7b5fc8e017b4b7e0917a55534b28a01fe57d /macros/src/syn_ext.rs | |
parent | 2ca8017deebe7bfe5aac368aead777a2c4910ca2 (diff) |
refactor: rewrite the mock macro as a procedural macro
Diffstat (limited to 'macros/src/syn_ext.rs')
-rw-r--r-- | macros/src/syn_ext.rs | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/macros/src/syn_ext.rs b/macros/src/syn_ext.rs new file mode 100644 index 0000000..7a3e9ae --- /dev/null +++ b/macros/src/syn_ext.rs @@ -0,0 +1,372 @@ +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: <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<AttributeStyle> for AttrStyle +{ + fn from(style: AttributeStyle) -> Self + { + match style { + AttributeStyle::Outer => Self::Outer, + AttributeStyle::Inner => Self::Inner(<Token![!]>::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: <Token![pub]>::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<Item = PathSegment>, + ) -> Self; +} + +impl PathExt for Path +{ + fn new( + with_leading_colons: WithLeadingColons, + segments: impl IntoIterator<Item = PathSegment>, + ) -> Self + { + Self { + leading_colon: match with_leading_colons { + WithLeadingColons::Yes => Some(<Token![::]>::default()), + WithLeadingColons::No => None, + }, + segments: segments.into_iter().collect(), + } + } +} + +pub enum WithLeadingColons +{ + Yes, + No, +} + +pub trait PathSegmentExt: Sized +{ + fn new(ident: Ident, args: Option<AngleBracketedGenericArguments>) -> Self; +} + +impl PathSegmentExt for PathSegment +{ + fn new(ident: Ident, args: Option<AngleBracketedGenericArguments>) -> 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<Item = GenericArgument>, + ) -> Self; +} + +impl AngleBracketedGenericArgumentsExt for AngleBracketedGenericArguments +{ + fn new( + with_colons: WithColons, + generic_args: impl IntoIterator<Item = GenericArgument>, + ) -> Self + { + Self { + colon2_token: match with_colons { + WithColons::Yes => Some(<Token![::]>::default()), + WithColons::No => None, + }, + lt_token: <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<Lifetime>, is_mut: IsMut, inner_type: Type) -> Self; +} + +impl TypeReferenceExt for TypeReference +{ + fn new(lifetime: Option<Lifetime>, is_mut: IsMut, inner_type: Type) -> Self + { + Self { + and_token: <Token![&]>::default(), + lifetime, + mutability: is_mut.into(), + elem: Box::new(inner_type), + } + } +} + +pub enum IsMut +{ + Yes, + No, +} + +impl From<Option<Token![mut]>> for IsMut +{ + fn from(opt_mut: Option<Token![mut]>) -> Self + { + match opt_mut { + Some(_) => Self::Yes, + None => Self::No, + } + } +} + +impl From<IsMut> for Option<Token![mut]> +{ + 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<Item = FnArg>, + output: ReturnType, + ) -> Self; +} + +impl SignatureExt for Signature +{ + fn new( + ident: Ident, + generics: Generics, + inputs: impl IntoIterator<Item = FnArg>, + output: ReturnType, + ) -> Self + { + Self { + constness: None, + asyncness: None, + unsafety: None, + abi: None, + fn_token: <Token![fn]>::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(<Token![->]>::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<Item = BareFnArg>, output: ReturnType) -> Self; +} + +impl TypeBareFnExt for TypeBareFn +{ + fn new(inputs: impl IntoIterator<Item = BareFnArg>, output: ReturnType) -> Self + { + Self { + lifetimes: None, + unsafety: None, + abi: None, + fn_token: <Token![fn]>::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, + } + } +} |