summaryrefslogtreecommitdiff
path: root/macros/src/syn_ext.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2023-03-18 17:14:42 +0100
committerHampusM <hampus@hampusmat.com>2023-03-18 17:15:30 +0100
commitc48271aef7e6b0819c497f302127c161845a83d7 (patch)
treea18d7b5fc8e017b4b7e0917a55534b28a01fe57d /macros/src/syn_ext.rs
parent2ca8017deebe7bfe5aac368aead777a2c4910ca2 (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.rs372
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,
+ }
+ }
+}