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