1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use proc_macro::{Group, Ident, TokenStream, TokenTree};
15 
16 // default is all false
17 #[derive(Default)]
18 struct Flags {
19     flag_with: bool,
20     flag_except: bool,
21     flag_at: bool,
22 }
23 
24 #[derive(Default)]
25 struct ParserBuilder {
26     len: usize,
27     default: TokenStream,
28     except: TokenStream,
29     except_index: usize,
30 }
31 
32 impl ParserBuilder {
build(self) -> TupleParser33     fn build(self) -> TupleParser {
34         TupleParser {
35             len: self.len,
36             default: self.default,
37             except: self.except,
38             except_index: self.except_index,
39         }
40     }
41 }
42 
43 // returns true if needs to handle default or except
parse_ident(ident: &Ident, idx: &mut usize, flags: &mut Flags) -> bool44 fn parse_ident(ident: &Ident, idx: &mut usize, flags: &mut Flags) -> bool {
45     // Get Separator "with/except/at"
46     match ident.to_string().as_str() {
47         "with" => {
48             flags.flag_with = true;
49             *idx += 1;
50             false
51         }
52         "except" => {
53             flags.flag_except = true;
54             *idx += 1;
55             false
56         }
57         "at" => {
58             flags.flag_at = true;
59             *idx += 1;
60             false
61         }
62         _ => true,
63     }
64 }
65 
66 // returns true if needs to handle default or except
parse_group( group: &Group, idx: &mut usize, flags: &mut Flags, builder: &mut ParserBuilder, ) -> bool67 fn parse_group(
68     group: &Group,
69     idx: &mut usize,
70     flags: &mut Flags,
71     builder: &mut ParserBuilder,
72 ) -> bool {
73     if !flags.flag_with && !flags.flag_except && !flags.flag_at {
74         // The tuple length is obtained by calculating the number of parenthesis layers
75         // of ((0 + 1) + 1). Actually the '0' also has a parenthesis wrapped around it,
76         // So here have to -1.
77         builder.len = group_num(group.stream()) - 1;
78         *idx += 1;
79         return false;
80     }
81     if flags.flag_with && flags.flag_except && flags.flag_at {
82         // Get the except_index.
83         builder.except_index = group.stream().into_iter().count();
84         *idx += 1;
85         return false;
86     }
87     true
88 }
89 
parse_token(buf: &[TokenTree], idx: &mut usize, flags: &mut Flags, builder: &mut ParserBuilder)90 fn parse_token(buf: &[TokenTree], idx: &mut usize, flags: &mut Flags, builder: &mut ParserBuilder) {
91     match &buf[*idx] {
92         TokenTree::Ident(ident) => {
93             if !parse_ident(ident, idx, flags) {
94                 return;
95             }
96         }
97         TokenTree::Group(group) => {
98             if !parse_group(group, idx, flags, builder) {
99                 return;
100             }
101         }
102         _ => {}
103     }
104     // Get TupleParser's 'default' or 'except'
105     if flags.flag_with && !flags.flag_at {
106         let default_or_except = TokenStream::from((buf[*idx]).to_owned());
107         if flags.flag_except {
108             builder.except.extend(default_or_except);
109         } else {
110             builder.default.extend(default_or_except);
111         }
112     }
113 
114     *idx += 1;
115 }
116 
117 /// Convert [`TokenStream`] to [`TupleParser`]
tuple_parser(input: TokenStream) -> TupleParser118 pub(crate) fn tuple_parser(input: TokenStream) -> TupleParser {
119     let buf = input.into_iter().collect::<Vec<_>>();
120     let mut flags = Flags::default();
121     let mut builder = ParserBuilder::default();
122     let mut idx = 0;
123 
124     while idx < buf.len() {
125         parse_token(&buf, &mut idx, &mut flags, &mut builder);
126     }
127     builder.build()
128 }
129 
130 /// Recursively queried how many layers of [`TokenTree::Group`]
group_num(inner: TokenStream) -> usize131 fn group_num(inner: TokenStream) -> usize {
132     match inner.into_iter().next() {
133         Some(TokenTree::Group(group)) => group_num(group.stream()) + 1,
134         _ => 0,
135     }
136 }
137 
138 /// Necessary data for building tuples
139 pub(crate) struct TupleParser {
140     /// Length of Tuple
141     pub(crate) len: usize,
142     /// Default value of Tuple
143     pub(crate) default: TokenStream,
144     /// Except value of Tuple
145     pub(crate) except: TokenStream,
146     /// Index of the default value in the tuple
147     pub(crate) except_index: usize,
148 }
149