• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use syn::{
16     parse::{Parse, ParseStream},
17     Expr, LitStr, Token,
18 };
19 
20 /// Custom keywords
21 pub mod kw {
22     syn::custom_keyword!(package);
23     syn::custom_keyword!(class);
24     syn::custom_keyword!(method_name);
25     syn::custom_keyword!(panic_returns);
26 }
27 
28 /// Arguments to the attribute
29 pub enum MetaArg {
30     Package {
31         package_token: kw::package,
32         _eq_token: Token![=],
33         value: LitStr,
34     },
35     Class {
36         class_token: kw::class,
37         _eq_token: Token![=],
38         value: LitStr,
39     },
40     MethodName {
41         method_name_token: kw::method_name,
42         _eq_token: Token![=],
43         value: LitStr,
44     },
45     PanicReturns {
46         panic_returns_token: kw::panic_returns,
47         _eq_token: Token![=],
48         value: Expr,
49     },
50 }
51 
52 impl Parse for MetaArg {
parse(stream: ParseStream<'_>) -> syn::Result<Self>53     fn parse(stream: ParseStream<'_>) -> syn::Result<Self> {
54         let lookahead = stream.lookahead1();
55         if lookahead.peek(kw::package) {
56             Ok(MetaArg::Package {
57                 package_token: stream.parse::<kw::package>()?,
58                 _eq_token: stream.parse()?,
59                 value: stream.parse()?,
60             })
61         } else if lookahead.peek(kw::class) {
62             Ok(MetaArg::Class {
63                 class_token: stream.parse::<kw::class>()?,
64                 _eq_token: stream.parse()?,
65                 value: stream.parse()?,
66             })
67         } else if lookahead.peek(kw::method_name) {
68             Ok(MetaArg::MethodName {
69                 method_name_token: stream.parse::<kw::method_name>()?,
70                 _eq_token: stream.parse()?,
71                 value: stream.parse()?,
72             })
73         } else if lookahead.peek(kw::panic_returns) {
74             Ok(MetaArg::PanicReturns {
75                 panic_returns_token: stream.parse::<kw::panic_returns>()?,
76                 _eq_token: stream.parse()?,
77                 value: stream.parse()?,
78             })
79         } else {
80             Err(lookahead.error())
81         }
82     }
83 }
84 
85 #[cfg(test)]
86 #[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
87 mod tests {
88     use super::*;
89     use syn::parse_quote;
90 
91     #[test]
parse_meta_arg_package()92     fn parse_meta_arg_package() {
93         let MetaArg::Package { value, .. } = parse_quote!(package = "com.example") else {
94             panic!("failed to parse")
95         };
96 
97         assert_eq!("com.example", value.value());
98     }
99 
100     #[test]
parse_meta_arg_class()101     fn parse_meta_arg_class() {
102         let MetaArg::Class { value, .. } = parse_quote!(class = "Foo") else {
103             panic!("failed to parse")
104         };
105 
106         assert_eq!("Foo", value.value());
107     }
108 
109     #[test]
parse_meta_arg_panic_returns()110     fn parse_meta_arg_panic_returns() {
111         let MetaArg::PanicReturns { value, .. } = parse_quote!(panic_returns = { foo() }) else {
112             panic!("failed to parse")
113         };
114 
115         let syn::Expr::Block(_) = value else {
116             panic!("not a block expression")
117         };
118     }
119 }
120