checked_rs_macro_impl/params/
number_arg_range.rs1use proc_macro2::{Span, TokenStream};
2use quote::{quote, ToTokens};
3use syn::parse::Parse;
4
5use super::{NumberArg, NumberKind, NumberValue, NumberValueRange};
6
7#[derive(Clone)]
8pub struct NumberArgRange {
9 pub start: Option<NumberArg>,
10 pub dot_dot: Option<syn::Token![..]>,
11 pub dot_dot_eq: Option<syn::Token![..=]>,
12 pub end: Option<NumberArg>,
13}
14
15impl Parse for NumberArgRange {
16 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
17 let mut start = None;
18 let mut dot_dot = None;
19 let mut dot_dot_eq = None;
20 let mut end = None;
21
22 let lookahead = input.lookahead1();
23
24 if lookahead.peek(syn::Token![..=]) {
25 dot_dot_eq = Some(input.parse()?);
26
27 if !input.is_empty() {
28 end = Some(input.parse()?);
29 }
30 } else if lookahead.peek(syn::Token![..]) {
31 dot_dot = Some(input.parse()?);
32
33 if !input.is_empty() {
34 end = Some(input.parse()?);
35 }
36 } else if lookahead.peek(syn::LitInt) {
37 start = Some(input.parse()?);
38
39 if input.peek(syn::Token![..=]) {
40 dot_dot_eq = Some(input.parse()?);
41
42 if !input.is_empty() {
43 end = Some(input.parse()?);
44 }
45 } else if input.peek(syn::Token![..]) {
46 dot_dot = Some(input.parse()?);
47
48 if !input.is_empty() {
49 end = Some(input.parse()?);
50 }
51 } else {
52 return Err(lookahead.error());
53 }
54 } else {
55 return Err(lookahead.error());
56 }
57
58 Ok(Self {
59 start,
60 dot_dot,
61 dot_dot_eq,
62 end,
63 })
64 }
65}
66
67impl ToTokens for NumberArgRange {
68 fn to_tokens(&self, tokens: &mut TokenStream) {
69 let start = self.start.as_ref();
70 let dot_dot = self.dot_dot.as_ref();
71 let dot_dot_eq = self.dot_dot_eq.as_ref();
72 let end = self.end.as_ref();
73
74 tokens.extend(quote! {
75 #start #dot_dot #dot_dot_eq #end
76 });
77 }
78}
79
80impl std::fmt::Debug for NumberArgRange {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 let dot_dot = self.dot_dot.as_ref().map(|_| "..".to_string());
83 let dot_dot_eq = self.dot_dot_eq.as_ref().map(|_| "..=".to_string());
84
85 write!(
86 f,
87 "{}{}{}{}",
88 self.start
89 .as_ref()
90 .map(|arg| arg.to_string())
91 .unwrap_or_default(),
92 dot_dot.unwrap_or_default(),
93 dot_dot_eq.unwrap_or_default(),
94 self.end
95 .as_ref()
96 .map(|arg| arg.to_string())
97 .unwrap_or_default()
98 )
99 }
100}
101
102impl std::fmt::Display for NumberArgRange {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 std::fmt::Debug::fmt(self, f)
105 }
106}
107
108impl NumberArgRange {
109 pub fn new_exclusive(start: NumberArg, end: NumberArg) -> Self {
110 Self {
111 start: Some(start),
112 dot_dot_eq: None,
113 dot_dot: Some(syn::Token)),
114 end: Some(end),
115 }
116 }
117
118 pub fn new_inclusive(start: NumberArg, end: NumberArg) -> Self {
119 Self {
120 start: Some(start),
121 dot_dot_eq: Some(syn::Token)),
122 dot_dot: None,
123 end: Some(end),
124 }
125 }
126
127 pub fn start_arg(&self, kind: NumberKind) -> NumberArg {
128 self.start
129 .as_ref()
130 .cloned()
131 .unwrap_or_else(|| NumberArg::new_min_constant(kind))
132 }
133
134 pub fn first_val(&self, kind: NumberKind) -> NumberValue {
135 self.start_arg(kind).into_value(kind)
136 }
137
138 pub fn end_arg(&self, kind: NumberKind) -> NumberArg {
139 self.end
140 .as_ref()
141 .cloned()
142 .unwrap_or_else(|| NumberArg::new_max_constant(kind))
143 }
144
145 pub fn last_val(&self, kind: NumberKind) -> NumberValue {
146 if let Some(end_arg) = &self.end {
147 let val = end_arg.into_value(kind);
148
149 if self.dot_dot_eq.is_some() {
150 val
151 } else {
152 val.sub_usize(1)
153 }
154 } else {
155 NumberArg::new_max_constant(kind).into_value(kind)
156 }
157 }
158
159 pub fn is_full_range(&self) -> bool {
160 self.start.is_none() && self.end.is_none()
161 }
162
163 pub fn to_value_range(&self, kind: NumberKind) -> syn::Result<NumberValueRange> {
164 NumberValueRange::from_arg_range(self.clone(), kind)
165 }
166
167 pub fn iter(&self, kind: NumberKind) -> impl Iterator<Item = NumberArg> {
168 self.iter_values(kind).map(|val| val.into_number_arg())
169 }
170
171 pub fn iter_values(&self, kind: NumberKind) -> impl Iterator<Item = NumberValue> {
172 let first = self.first_val(kind);
173 let last = self.last_val(kind);
174
175 first.iter_to(last.add_usize(1))
176 }
177}
178
179#[derive(Clone)]
180pub struct StrictNumberArgRange(pub NumberArgRange);
181
182impl Parse for StrictNumberArgRange {
183 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
184 let range: NumberArgRange = input.parse()?;
185
186 if range.start.is_none() && range.end.is_none() {
187 Err(input.error("Should not be a full range"))
188 } else {
189 Ok(Self(range))
190 }
191 }
192}
193
194impl ToTokens for StrictNumberArgRange {
195 fn to_tokens(&self, tokens: &mut TokenStream) {
196 self.0.to_tokens(tokens);
197 }
198}
199
200impl std::fmt::Debug for StrictNumberArgRange {
201 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 std::fmt::Debug::fmt(&self.0, f)
203 }
204}
205
206impl std::fmt::Display for StrictNumberArgRange {
207 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208 std::fmt::Debug::fmt(self, f)
209 }
210}
211
212impl std::ops::Deref for StrictNumberArgRange {
213 type Target = NumberArgRange;
214
215 fn deref(&self) -> &Self::Target {
216 &self.0
217 }
218}