aboutsummaryrefslogtreecommitdiff
path: root/syn-mid/src/arg.rs
diff options
context:
space:
mode:
Diffstat (limited to 'syn-mid/src/arg.rs')
-rw-r--r--syn-mid/src/arg.rs99
1 files changed, 99 insertions, 0 deletions
diff --git a/syn-mid/src/arg.rs b/syn-mid/src/arg.rs
new file mode 100644
index 0000000..593a1ac
--- /dev/null
+++ b/syn-mid/src/arg.rs
@@ -0,0 +1,99 @@
+use syn::{Attribute, Lifetime, Token};
+
+use super::PatType;
+
+ast_enum_of_structs! {
+ /// An argument in a function signature: the `n: usize` in `fn f(n: usize)`.
+ pub enum FnArg {
+ /// The `self` argument of an associated method, whether taken by value
+ /// or by reference.
+ Receiver(Receiver),
+
+ /// A function argument accepted by pattern and type.
+ Typed(PatType),
+ }
+}
+
+ast_struct! {
+ /// The `self` argument of an associated method, whether taken by value
+ /// or by reference.
+ pub struct Receiver {
+ pub attrs: Vec<Attribute>,
+ pub reference: Option<(Token![&], Option<Lifetime>)>,
+ pub mutability: Option<Token![mut]>,
+ pub self_token: Token![self],
+ }
+}
+
+mod parsing {
+ use syn::{
+ parse::{discouraged::Speculative, Parse, ParseStream, Result},
+ Attribute, Token,
+ };
+
+ use super::{FnArg, PatType, Receiver};
+
+ impl Parse for FnArg {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+
+ let ahead = input.fork();
+ if let Ok(mut receiver) = ahead.parse::<Receiver>() {
+ if !ahead.peek(Token![:]) {
+ input.advance_to(&ahead);
+ receiver.attrs = attrs;
+ return Ok(FnArg::Receiver(receiver));
+ }
+ }
+
+ let mut typed = input.call(fn_arg_typed)?;
+ typed.attrs = attrs;
+ Ok(FnArg::Typed(typed))
+ }
+ }
+
+ impl Parse for Receiver {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ Ok(Self {
+ attrs: Vec::new(),
+ reference: {
+ if input.peek(Token![&]) {
+ Some((input.parse()?, input.parse()?))
+ } else {
+ None
+ }
+ },
+ mutability: input.parse()?,
+ self_token: input.parse()?,
+ })
+ }
+ }
+
+ fn fn_arg_typed(input: ParseStream<'_>) -> Result<PatType> {
+ Ok(PatType {
+ attrs: Vec::new(),
+ pat: input.parse()?,
+ colon_token: input.parse()?,
+ ty: Box::new(input.parse()?),
+ })
+ }
+}
+
+mod printing {
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ use super::Receiver;
+
+ impl ToTokens for Receiver {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ if let Some((ampersand, lifetime)) = &self.reference {
+ ampersand.to_tokens(tokens);
+ lifetime.to_tokens(tokens);
+ }
+ self.mutability.to_tokens(tokens);
+ self.self_token.to_tokens(tokens);
+ }
+ }
+}