1use syn::{token::Comma, RangeLimits};
2
3use crate::*;
4
5#[derive(Debug, Clone)]
6pub struct ClosedRangeList {
7 pub list: Vec<Range<i32>>,
8}
9
10impl Parse for ClosedRangeList {
11 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
12 let mut ranges: Vec<Range<i32>> = Vec::new();
13
14 while !input.is_empty() {
15 let item: Expr = input.parse()?;
16
17 if let Expr::Range(range_expr) = &item {
18 let start = if let Some(start_expr) = &range_expr.start {
19 start_expr.as_int::<i32>()?
20 } else {
21 return Err(input.error("Expected a defined start for this range"));
22 };
23
24 if let Some(end_expr) = &range_expr.end {
25 let mut end = end_expr.as_int::<i32>()?;
26
27 if let RangeLimits::Closed(_) = &range_expr.limits {
28 end += 1;
29 }
30
31 ranges.push(start..end)
32 } else {
33 return Err(input.error("Expected a closed range"));
34 }
35 } else if let Expr::Lit(lit) = &item && let Lit::Int(lit_int) = &lit.lit {
36 let num = lit_int.base10_parse::<i32>()?;
37
38 ranges.push(num..num + 1);
39 } else {
40 return Err(error!(
41 item,
42 "Expected a range (e.g. `1..5`, `10..=15`) or a single number"
43 ));
44 }
45
46 if input.is_empty() {
47 break;
48 }
49
50 let _comma: Comma = input.parse()?;
51 }
52
53 ranges.sort_by_key(|range| range.start);
54
55 Ok(Self { list: ranges })
56 }
57}
58
59#[derive(Debug, Clone)]
60pub enum GenericRange {
61 Open(RangeFrom<i32>),
62 Closed(Range<i32>),
63}
64
65#[derive(Debug, Clone)]
66pub struct GenericRangeList {
67 pub list: Vec<GenericRange>,
68}
69
70impl Parse for GenericRangeList {
71 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
72 let mut ranges: Vec<GenericRange> = Vec::new();
73
74 while !input.is_empty() {
75 let item: Expr = input.parse()?;
76
77 if let Expr::Range(range_expr) = &item {
78 let start = if let Some(start_expr) = &range_expr.start {
79 start_expr.as_int::<i32>()?
80 } else {
81 return Err(input.error("Expected a defined start for this range"));
82 };
83
84 if let Some(end_expr) = &range_expr.end {
85 let mut end = end_expr.as_int::<i32>()?;
86
87 if let RangeLimits::Closed(_) = &range_expr.limits {
88 end += 1;
89 }
90 ranges.push(GenericRange::Closed(start..end))
91 } else {
92 ranges.push(GenericRange::Open(start..))
93 }
94 } else if let Expr::Lit(lit) = &item && let Lit::Int(lit_int) = &lit.lit {
95 let num = lit_int.base10_parse::<i32>()?;
96
97 ranges.push(GenericRange::Closed(num..num + 1));
98 } else {
99 return Err(error!(
100 item,
101 "Expected a range (e.g. `1..5`, `10..=15`) or a single number"
102 ));
103 }
104
105 if input.is_empty() {
106 break;
107 }
108
109 let _comma: Comma = input.parse()?;
110 }
111
112 Ok(Self { list: ranges })
113 }
114}
115
116#[derive(Debug, Clone)]
117pub enum PathOrClosure {
118 Path(TokenStream2),
119 Closure(TokenStream2),
120}
121
122impl ToTokens for PathOrClosure {
123 fn to_tokens(&self, tokens: &mut TokenStream2) {
124 match self {
125 PathOrClosure::Path(path) => path.to_tokens(tokens),
126 PathOrClosure::Closure(expr_closure) => expr_closure.to_tokens(tokens),
127 }
128 }
129}
130
131#[derive(Debug, Clone)]
132pub enum CallOrClosure {
133 Call(TokenStream2),
134 Closure(TokenStream2),
135}
136
137impl ToTokens for CallOrClosure {
138 fn to_tokens(&self, tokens: &mut TokenStream2) {
139 match self {
140 CallOrClosure::Call(call) => call.to_tokens(tokens),
141 CallOrClosure::Closure(expr_closure) => expr_closure.to_tokens(tokens),
142 }
143 }
144}
145
146pub struct PunctuatedItems<T: Parse + ToTokens> {
147 pub list: Vec<T>,
148}
149
150pub type PathList = PunctuatedItems<Path>;
151pub type IdentList = PunctuatedItems<Ident>;
152
153impl<T: Parse + ToTokens> Parse for PunctuatedItems<T> {
154 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
155 let mut inner = Vec::new();
156
157 while !input.is_empty() {
158 inner.push(input.parse()?);
159
160 if input.is_empty() {
161 break;
162 }
163 let _comma: Comma = input.parse()?;
164 }
165
166 Ok(Self { list: inner })
167 }
168}
169
170impl<T: Parse + ToTokens> ToTokens for PunctuatedItems<T> {
171 fn to_tokens(&self, tokens: &mut TokenStream2) {
172 let list = &self.list;
173
174 let output = quote! { #(#list),* };
175
176 tokens.extend(output)
177 }
178}
179
180pub struct StringList {
181 pub list: Vec<String>,
182}
183
184impl ToTokens for StringList {
185 fn to_tokens(&self, tokens: &mut TokenStream2) {
186 let list = &self.list;
187
188 let output = quote! { #(#list),* };
189
190 tokens.extend(output)
191 }
192}
193
194impl Parse for StringList {
195 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
196 let mut list: Vec<String> = Vec::new();
197
198 while !input.is_empty() {
199 list.push(input.parse::<LitStr>()?.value());
200
201 if input.is_empty() {
202 break;
203 }
204 let _comma: Comma = input.parse()?;
205 }
206
207 Ok(Self { list })
208 }
209}
210
211pub struct NumList {
212 pub list: Vec<i32>,
213}
214
215impl ToTokens for NumList {
216 fn to_tokens(&self, tokens: &mut TokenStream2) {
217 let list = self
218 .list
219 .iter()
220 .map(|n| proc_macro2::Literal::i32_unsuffixed(*n));
221
222 let output = quote! { #(#list),* };
223
224 tokens.extend(output)
225 }
226}
227
228impl Parse for NumList {
229 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
230 let mut list: Vec<i32> = Vec::new();
231
232 while !input.is_empty() {
233 list.push(input.parse::<LitInt>()?.base10_parse()?);
234
235 if input.is_empty() {
236 break;
237 }
238 let _comma: Comma = input.parse()?;
239 }
240
241 Ok(Self { list })
242 }
243}