1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use syn::{Lifetime, Token, Type};

use super::Pat;

ast_enum_of_structs! {
    /// An argument in a function signature: the `n: usize` in `fn f(n: usize)`.
    ///
    /// # Syntax tree enum
    ///
    /// This type is a [syntax tree enum].
    ///
    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
    pub enum FnArg {
        /// Self captured by reference in a function signature: `&self` or `&mut
        /// self`.
        pub SelfRef(ArgSelfRef {
            pub and_token: Token![&],
            pub lifetime: Option<Lifetime>,
            pub mutability: Option<Token![mut]>,
            pub self_token: Token![self],
        }),

        /// Self captured by value in a function signature: `self` or `mut
        /// self`.
        pub SelfValue(ArgSelf {
            pub mutability: Option<Token![mut]>,
            pub self_token: Token![self],
        }),

        /// An explicitly typed pattern captured by a function signature.
        pub Captured(ArgCaptured {
            pub pat: Pat,
            pub colon_token: Token![:],
            pub ty: Type,
        }),

        /// A pattern whose type is inferred captured by a function signature.
        pub Inferred(Pat),
        /// A type not bound to any pattern in a function signature.
        pub Ignored(Type),
    }
}

mod parsing {
    use syn::{
        parse::{Parse, ParseStream, Result},
        Token, Type,
    };

    use super::{ArgCaptured, ArgSelf, ArgSelfRef, FnArg};

    impl Parse for FnArg {
        fn parse(input: ParseStream<'_>) -> Result<Self> {
            if input.peek(Token![&]) {
                let ahead = input.fork();
                if ahead.call(arg_self_ref).is_ok() && !ahead.peek(Token![:]) {
                    return input.call(arg_self_ref).map(FnArg::SelfRef);
                }
            }

            if input.peek(Token![mut]) || input.peek(Token![self]) {
                let ahead = input.fork();
                if ahead.call(arg_self).is_ok() && !ahead.peek(Token![:]) {
                    return input.call(arg_self).map(FnArg::SelfValue);
                }
            }

            let ahead = input.fork();
            let err = match ahead.call(arg_captured) {
                Ok(_) => return input.call(arg_captured).map(FnArg::Captured),
                Err(err) => err,
            };

            let ahead = input.fork();
            if ahead.parse::<Type>().is_ok() {
                return input.parse().map(FnArg::Ignored);
            }

            Err(err)
        }
    }

    fn arg_self_ref(input: ParseStream<'_>) -> Result<ArgSelfRef> {
        Ok(ArgSelfRef {
            and_token: input.parse()?,
            lifetime: input.parse()?,
            mutability: input.parse()?,
            self_token: input.parse()?,
        })
    }

    fn arg_self(input: ParseStream<'_>) -> Result<ArgSelf> {
        Ok(ArgSelf {
            mutability: input.parse()?,
            self_token: input.parse()?,
        })
    }

    fn arg_captured(input: ParseStream<'_>) -> Result<ArgCaptured> {
        Ok(ArgCaptured {
            pat: input.parse()?,
            colon_token: input.parse()?,
            ty: input.parse()?,
        })
    }
}

mod printing {
    use proc_macro2::TokenStream;
    use quote::ToTokens;

    use super::{ArgCaptured, ArgSelf, ArgSelfRef};

    impl ToTokens for ArgSelfRef {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.and_token.to_tokens(tokens);
            self.lifetime.to_tokens(tokens);
            self.mutability.to_tokens(tokens);
            self.self_token.to_tokens(tokens);
        }
    }

    impl ToTokens for ArgSelf {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.mutability.to_tokens(tokens);
            self.self_token.to_tokens(tokens);
        }
    }

    impl ToTokens for ArgCaptured {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.pat.to_tokens(tokens);
            self.colon_token.to_tokens(tokens);
            self.ty.to_tokens(tokens);
        }
    }
}