1use proc_macro2::TokenStream;
2use quote::{format_ident, quote, ToTokens};
3use syn::parse_quote;
4
5use crate::{
6 common_impl::{
7 define_guard, impl_binary_op, impl_conversions, impl_deref, impl_other_compare,
8 impl_other_eq, impl_self_cmp, impl_self_eq,
9 },
10 params::{NumberArg, NumberValueRange, Params},
11};
12
13pub fn define_mod(params: &Params, ranges: &Vec<NumberValueRange>) -> syn::Result<TokenStream> {
14 let integer = ¶ms.integer;
15
16 let vis = ¶ms.vis;
17 let ident = ¶ms.ident;
18 let mod_ident = params.mod_ident();
19
20 let implementations = TokenStream::from_iter(vec![
21 impl_deref(ident, params),
22 impl_conversions(ident, params),
23 impl_self_eq(ident),
24 impl_self_cmp(ident),
25 impl_other_eq(ident, params),
26 impl_other_compare(ident, params),
27 impl_binary_op(
28 ident,
29 params,
30 format_ident!("Add"),
31 format_ident!("add"),
32 ¶ms.behavior,
33 Some((
34 NumberArg::new_min_constant(*integer),
35 NumberArg::new_max_constant(*integer),
36 )),
37 ),
38 impl_binary_op(
39 ident,
40 params,
41 format_ident!("Sub"),
42 format_ident!("sub"),
43 ¶ms.behavior,
44 Some((
45 NumberArg::new_min_constant(*integer),
46 NumberArg::new_max_constant(*integer),
47 )),
48 ),
49 impl_binary_op(
50 ident,
51 params,
52 format_ident!("Mul"),
53 format_ident!("mul"),
54 ¶ms.behavior,
55 Some((
56 NumberArg::new_min_constant(*integer),
57 NumberArg::new_max_constant(*integer),
58 )),
59 ),
60 impl_binary_op(
61 ident,
62 params,
63 format_ident!("Div"),
64 format_ident!("div"),
65 ¶ms.behavior,
66 Some((
67 NumberArg::new_min_constant(*integer),
68 NumberArg::new_max_constant(*integer),
69 )),
70 ),
71 impl_binary_op(
72 ident,
73 params,
74 format_ident!("Rem"),
75 format_ident!("rem"),
76 ¶ms.behavior,
77 Some((
78 NumberArg::new_min_constant(*integer),
79 NumberArg::new_max_constant(*integer),
80 )),
81 ),
82 impl_binary_op(
83 ident,
84 params,
85 format_ident!("BitAnd"),
86 format_ident!("bitand"),
87 ¶ms.behavior,
88 Some((
89 NumberArg::new_min_constant(*integer),
90 NumberArg::new_max_constant(*integer),
91 )),
92 ),
93 impl_binary_op(
94 ident,
95 params,
96 format_ident!("BitOr"),
97 format_ident!("bitor"),
98 ¶ms.behavior,
99 Some((
100 NumberArg::new_min_constant(*integer),
101 NumberArg::new_max_constant(*integer),
102 )),
103 ),
104 impl_binary_op(
105 ident,
106 params,
107 format_ident!("BitXor"),
108 format_ident!("bitxor"),
109 ¶ms.behavior,
110 Some((
111 NumberArg::new_min_constant(*integer),
112 NumberArg::new_max_constant(*integer),
113 )),
114 ),
115 ]);
116
117 let behavior = ¶ms.behavior;
118 let lower_limit = params.lower_limit_token();
119 let upper_limit = params.upper_limit_token();
120 let default_val = params.default_val_token();
121
122 let guard_ident = params.guard_ident();
123 let def_guard = define_guard(ident, &guard_ident, params);
124
125 let mut traits = params
126 .derived_traits
127 .as_ref()
128 .map(|x| {
129 let mut traits = Vec::with_capacity(x.traits.len());
130
131 traits.extend(
132 x.traits
133 .iter()
134 .filter(|ty| {
135 let ty = ty
136 .path
137 .segments
138 .last()
139 .unwrap()
140 .to_token_stream()
141 .to_string();
142
143 match ty.as_str() {
144 "Clone" | "Copy" => false,
145 _ => true,
146 }
147 })
148 .cloned(),
149 );
150
151 traits
152 })
153 .unwrap_or(Vec::with_capacity(2));
154
155 traits.extend(vec![parse_quote!(Clone), parse_quote!(Copy)]);
156
157 let clamp_trait_impl = {
158 let mut valid_ranges = Vec::with_capacity(ranges.len());
159
160 for value_range in ranges {
161 let first_val = value_range.first_val();
162 let last_val = value_range.last_val();
163
164 valid_ranges.push(quote! {
165 ValueRangeInclusive(#first_val..=#last_val),
166 });
167 }
168
169 quote! {
170 unsafe impl RangeValues<#integer> for #ident {
171 const VALID_RANGES: &'static [ValueRangeInclusive<#integer>] = &[
172 #(#valid_ranges)*
173 ];
174 }
175
176 unsafe impl SoftClamp<#integer> for #ident {}
177 }
178 };
179
180 Ok(quote! {
181 #vis mod #mod_ident {
182 use super::*;
183
184 #[derive(#(#traits),*)]
185 pub struct #ident(#integer);
186
187 impl #ident {
188 #[inline(always)]
190 pub fn new(val: #integer) -> Option<Self> {
191 match #ident::validate(val) {
192 Ok(v) => Some(Self(v)),
193 Err(..) => None,
194 }
195 }
196
197 #[inline(always)]
198 pub const fn new_unchecked(val: #integer) -> Self {
199 Self(val)
200 }
201
202 pub(self) fn op_behavior_params(&self) -> OpBehaviorParams<#integer> {
203 let ranges = <#ident as RangeValues<#integer>>::VALID_RANGES;
204
205 if ranges.len() == 1 {
206 let range = &ranges[0];
207
208 OpBehaviorParams::Simple {
209 min: range.first_val(),
210 max: range.last_val(),
211 }
212 } else {
213 let min = ranges.first().unwrap().first_val();
214 let max = ranges.last().unwrap().last_val();
215
216 OpBehaviorParams::RangesOnly(ranges)
217 }
218 }
219
220 #[inline(always)]
221 pub fn rand() -> Self {
222 loop {
223 if let Ok(v) = Self::validate(rand::random::<#integer>()) {
224 return Self::from_primitive(v).unwrap();
225 }
226 }
227 }
228
229 #[inline(always)]
230 pub fn validate(val: #integer) -> ::anyhow::Result<#integer, ClampError<#integer>> {
231 let ranges = <#ident as RangeValues<#integer>>::VALID_RANGES;
232
233 if ranges.len() == 1 {
234 let range = &ranges[0];
235 let min = range.first_val();
236 let max = range.last_val();
237
238 if val < min {
239 Err(ClampError::TooSmall { val, min })
240 } else if val > max {
241 Err(ClampError::TooLarge { val, max })
242 } else {
243 Ok(val)
244 }
245 } else {
246 for (i, range) in ranges.iter().enumerate() {
247 if range.contains(val) {
248 return Ok(val);
249 }
250
251 let min = range.first_val();
252
253 if i == 0 && val < min {
254 return Err(ClampError::TooSmall { val, min });
255 }
256
257 if i == ranges.len() - 1 {
258 let max = range.last_val();
259 return Err(ClampError::TooLarge { val, max });
260 }
261
262 let left_range = range;
263 let right_range = &ranges[i + 1];
264
265 let left_max = left_range.last_val();
266 let right_min = right_range.first_val();
267
268 if val > left_max && val < right_min {
269 return Err(ClampError::OutOfBounds {
270 val,
271 left_min: left_range.first_val(),
272 left_max,
273 right_min,
274 right_max: right_range.last_val(),
275 });
276 }
277 }
278
279 unreachable!("all error cases should be covered by loop");
280 }
281 }
282
283 #[inline(always)]
284 pub fn is_valid(&self) -> bool {
285 Self::validate(self.0).is_ok()
286 }
287
288 #[inline(always)]
289 pub fn set(&mut self, value: #integer) -> ::anyhow::Result<(), ClampError<#integer>> {
290 self.0 = Self::validate(value)?;
291 Ok(())
292 }
293
294 #[inline(always)]
295 pub fn set_unchecked(&mut self, value: #integer) {
296 self.0 = value;
297 }
298
299 #[inline(always)]
300 pub fn get(&self) -> &#integer {
301 &self.0
302 }
303
304 #[inline(always)]
305 pub fn get_mut(&mut self) -> &mut #integer {
306 &mut self.0
307 }
308
309 #[inline(always)]
310 pub fn modify<'a>(&'a mut self) -> #guard_ident<'a> {
311 #guard_ident::new(self)
312 }
313 }
314
315
316 impl InherentLimits<#integer> for #ident {
317 const MIN_INT: #integer = #lower_limit;
318 const MAX_INT: #integer = #upper_limit;
319 const MIN: Self = Self(Self::MIN_INT);
320 const MAX: Self = Self(Self::MAX_INT);
321
322 #[inline(always)]
323 fn is_zero(&self) -> bool {
324 self.0 == 0
325 }
326
327 #[inline(always)]
328 fn is_negative(&self) -> bool {
329 self.0 < 0
330 }
331
332 #[inline(always)]
333 fn is_positive(&self) -> bool {
334 self.0 > 0
335 }
336 }
337
338 impl InherentBehavior for #ident {
339 type Behavior = #behavior;
340 }
341
342 unsafe impl ClampedInteger<#integer> for #ident {
343 #[inline(always)]
344 fn from_primitive(n: #integer) -> ::anyhow::Result<Self> {
345 Ok(Self(n))
346 }
347
348 #[inline(always)]
349 fn as_primitive(&self) -> &#integer {
350 &self.0
351 }
352 }
353
354 #clamp_trait_impl
355
356 impl Default for #ident {
357 #[inline(always)]
358 fn default() -> Self {
359 Self(#default_val)
360 }
361 }
362
363 impl std::ops::DerefMut for #ident {
364 #[inline(always)]
365 fn deref_mut(&mut self) -> &mut Self::Target {
366 &mut self.0
367 }
368 }
369
370
371 impl AsMut<#integer> for #ident {
372 #[inline(always)]
373 fn as_mut(&mut self) -> &mut #integer {
374 &mut self.0
375 }
376 }
377
378 #implementations
379
380 #def_guard
381 }
382
383 #vis use #mod_ident::#ident;
384 })
385}