checked_rs_macro_impl/params/
number_arg_range.rs

1use 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![..](Span::call_site())),
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![..=](Span::call_site())),
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}