checked_rs_macro_impl/params/
number_value_range.rs1use std::ops::{Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};
2
3use proc_macro2::{Span, TokenStream};
4use quote::{quote, ToTokens};
5
6use super::{NumberArg, NumberArgRange, NumberKind, NumberValue};
7
8#[derive(Debug, Clone)]
9pub enum NumberValueRange {
10 Full(NumberKind),
11 From(RangeFrom<NumberValue>),
12 ToExclusive(RangeTo<NumberValue>),
13 ToInclusive(RangeToInclusive<NumberValue>),
14 Exclusive(Range<NumberValue>),
15 Inclusive(RangeInclusive<NumberValue>),
16}
17
18impl From<NumberKind> for NumberValueRange {
19 fn from(kind: NumberKind) -> Self {
20 Self::Full(kind)
21 }
22}
23
24impl From<&NumberKind> for NumberValueRange {
25 fn from(kind: &NumberKind) -> Self {
26 Self::Full(*kind)
27 }
28}
29
30impl From<RangeFrom<NumberValue>> for NumberValueRange {
31 fn from(range: RangeFrom<NumberValue>) -> Self {
32 Self::From(range)
33 }
34}
35
36impl From<&RangeFrom<NumberValue>> for NumberValueRange {
37 fn from(range: &RangeFrom<NumberValue>) -> Self {
38 Self::From(range.clone())
39 }
40}
41
42impl From<RangeTo<NumberValue>> for NumberValueRange {
43 fn from(range: RangeTo<NumberValue>) -> Self {
44 Self::ToExclusive(range)
45 }
46}
47
48impl From<&RangeTo<NumberValue>> for NumberValueRange {
49 fn from(range: &RangeTo<NumberValue>) -> Self {
50 Self::ToExclusive(range.clone())
51 }
52}
53
54impl From<RangeToInclusive<NumberValue>> for NumberValueRange {
55 fn from(range: RangeToInclusive<NumberValue>) -> Self {
56 Self::ToInclusive(range)
57 }
58}
59
60impl From<&RangeToInclusive<NumberValue>> for NumberValueRange {
61 fn from(range: &RangeToInclusive<NumberValue>) -> Self {
62 Self::ToInclusive(range.clone())
63 }
64}
65
66impl From<Range<NumberValue>> for NumberValueRange {
67 fn from(range: Range<NumberValue>) -> Self {
68 Self::Exclusive(range)
69 }
70}
71
72impl From<&Range<NumberValue>> for NumberValueRange {
73 fn from(range: &Range<NumberValue>) -> Self {
74 Self::Exclusive(range.clone())
75 }
76}
77
78impl From<RangeInclusive<NumberValue>> for NumberValueRange {
79 fn from(range: RangeInclusive<NumberValue>) -> Self {
80 Self::Inclusive(range)
81 }
82}
83
84impl From<&RangeInclusive<NumberValue>> for NumberValueRange {
85 fn from(range: &RangeInclusive<NumberValue>) -> Self {
86 Self::Inclusive(range.clone())
87 }
88}
89
90impl ToTokens for NumberValueRange {
91 fn to_tokens(&self, tokens: &mut TokenStream) {
92 let min = self.first_val();
93 let max = self.last_val();
94
95 tokens.extend(quote! {
96 #min..=#max
97 });
98 }
99}
100
101impl NumberValueRange {
102 fn check_matching_kinds(
103 a: impl Into<NumberKind> + std::fmt::Debug + Clone,
104 b: impl Into<NumberKind> + std::fmt::Debug + Clone,
105 ) -> syn::Result<()> {
106 let a_kind: NumberKind = a.clone().into();
107 let b_kind: NumberKind = b.clone().into();
108
109 if a_kind != b_kind {
110 return Err(syn::Error::new(
111 Span::call_site(),
112 format!("Number kinds do not match: {:?} != {:?}", a, b),
113 ));
114 }
115
116 Ok(())
117 }
118
119 pub fn kind(&self) -> NumberKind {
120 match self {
121 Self::Full(kind) => *kind,
122 Self::From(range) => range.start.kind(),
123 Self::ToExclusive(range) => range.end.kind(),
124 Self::ToInclusive(range) => range.end.kind(),
125 Self::Exclusive(range) => range.start.kind(),
126 Self::Inclusive(range) => range.start().kind(),
127 }
128 }
129
130 pub fn first_val(&self) -> NumberValue {
131 match self {
132 Self::From(range) => range.start,
133 Self::Inclusive(range) => *range.start(),
134 Self::Exclusive(range) => range.start,
135 _ => {
136 let kind = self.kind();
137 NumberArg::new_min_constant(kind).into_value(kind)
138 }
139 }
140 }
141
142 pub fn last_val(&self) -> NumberValue {
143 match self {
144 Self::ToExclusive(range) => range.end.sub_usize(1),
145 Self::ToInclusive(range) => range.end,
146 Self::Exclusive(range) => range.end.sub_usize(1),
147 Self::Inclusive(range) => *range.end(),
148 _ => {
149 let kind = self.kind();
150 NumberArg::new_max_constant(kind).into_value(kind)
151 }
152 }
153 }
154
155 pub fn contains(&self, val: &NumberValue) -> bool {
156 if *val >= self.first_val() && *val <= self.first_val() {
157 true
158 } else {
159 false
160 }
161 }
162
163 #[must_use]
164 pub fn new_inclusive(
165 start: Option<NumberValue>,
166 end: Option<NumberValue>,
167 kind: NumberKind,
168 ) -> syn::Result<Self> {
169 Ok(match (start, end) {
170 (Some(start), Some(end)) => {
171 Self::check_matching_kinds(start, kind)?;
172 Self::check_matching_kinds(end, kind)?;
173 Self::Inclusive(start..=end)
174 }
175 (Some(start), None) => {
176 Self::check_matching_kinds(start, kind)?;
177 Self::From(start..)
178 }
179 (None, Some(end)) => {
180 Self::check_matching_kinds(end, kind)?;
181 Self::ToInclusive(..=end)
182 }
183 (None, None) => Self::Full(kind),
184 })
185 }
186
187 #[must_use]
188 pub fn new_exclusive(
189 start: Option<NumberValue>,
190 end: Option<NumberValue>,
191 kind: NumberKind,
192 ) -> syn::Result<Self> {
193 Ok(match (start, end) {
194 (Some(start), Some(end)) => {
195 Self::check_matching_kinds(start, kind)?;
196 Self::check_matching_kinds(end, kind)?;
197 Self::Exclusive(start..end)
198 }
199 (Some(start), None) => {
200 Self::check_matching_kinds(start, kind)?;
201 Self::From(start..)
202 }
203 (None, Some(end)) => {
204 Self::check_matching_kinds(end, kind)?;
205 Self::ToExclusive(..end)
206 }
207 (None, None) => Self::Full(kind),
208 })
209 }
210
211 #[must_use]
212 pub fn from_arg_range(arg_range: NumberArgRange, kind: NumberKind) -> syn::Result<Self> {
213 let NumberArgRange {
214 start,
215 end,
216 dot_dot_eq,
217 ..
218 } = arg_range;
219
220 let inclusive = dot_dot_eq.is_some();
221 let start = start.map(|arg| arg.into_value(kind));
222 let end = end.map(|arg| arg.into_value(kind));
223
224 Ok(match (start, end) {
225 (None, None) => Self::Full(kind),
226 (Some(start), None) => {
227 Self::check_matching_kinds(kind, &start)?;
228 Self::From(start..)
229 }
230 (Some(start), Some(end)) => {
231 Self::check_matching_kinds(kind, &start)?;
232 Self::check_matching_kinds(kind, &end)?;
233
234 if inclusive {
235 Self::Inclusive(start..=end)
236 } else {
237 Self::Exclusive(start..end)
238 }
239 }
240 (None, Some(end)) => {
241 Self::check_matching_kinds(kind, &end)?;
242
243 if inclusive {
244 Self::ToInclusive(..=end)
245 } else {
246 Self::ToExclusive(..end)
247 }
248 }
249 })
250 }
251}