light_ranged_integers/
ranged.rs

1/*
2Copyright © 2024 - Massimo Gismondi
3
4This file is part of light-ranged-integers.
5
6light-ranged-integers is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11light-ranged-integers is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with light-ranged-integers.  If not, see <http://www.gnu.org/licenses/>.
18*/
19
20use crate::op_mode;
21use std::marker::PhantomData;
22
23macro_rules! gen_ranged_structs {
24    ($i:ty, $typename:ident, $const_typename:ident) => {
25        #[derive(Debug, Clone, Copy)]
26        #[doc = concat!("A ranged integer between MIN and MAX, encapsulating [", stringify!($i), "] type.\n\n")]
27        ///
28        /// The library offers Range types, declared in this form
29        /// ```rust,ignore
30        #[doc= concat!(stringify!($typename), "<MIN, MAX, OpMode>")]
31        /// ```
32        /// where:
33        /// - `MIN` is a lower limit of the interval
34        /// - `MAX` is the upper limit of the interval
35        /// - `OpMode` selects how to behave when a number goes out of range. Have a
36        ///    look at [op_mode] for all available modes.
37        /// ```rust
38        /// use light_ranged_integers::{RangedU16, op_mode::Panic};
39        ///
40        /// // Creating a Ranged value of 3, in the interval from 1 to 6.
41        /// let n1 = RangedU16::<1,6, Panic>::new(3);
42        ///
43        /// ```
44        /// The interval must be valid, as the MIN limit must be smaller than MAX.
45        /// This is checked at compile time.
46        /// ```rust,compile_fail
47        /// # use light_ranged_integers::RangedU8;
48        /// RangedU8::<2,1>::new(2);
49        /// ```
50        ///
51        /// It will fail to compile even if the limits are the same
52        /// ```rust,compile_fail
53        /// # use light_ranged_integers::RangedU8;
54        /// RangedU8::<2,2>::new(2);
55        /// ```
56        ///
57        /// Pay attention that the code at compile time will check only the validity
58        /// of the interval, but the check of the provided value fitting the interval is done at runtime.
59        /// If you desire to move that check at compile time too, have a look at [Self::new_const()](Self::new_const()) constructor.
60        pub struct $typename<const MIN: $i = {<$i>::MIN}, const MAX:$i = {<$i>::MAX}, OpMode=op_mode::Panic>($i, PhantomData<OpMode>) where OpMode: op_mode::OpModeExt;
61
62
63
64        // Implement methods common for all modes
65        impl<OpMode, const MIN: $i, const MAX:$i> $typename<MIN, MAX, OpMode> where OpMode: op_mode::OpModeExt
66        {
67            const COMPTIME_RANGE_CHECK: () = assert!(MIN < MAX, "INVALID RANGE. MIN must be smaller than MAX");
68
69            #[doc=concat!("Builds a new [",stringify!($typename),"] checking the limits at runtime")]
70            ///
71            /// The number MUST be inside the interval.
72            /// Will panic if the number is outside the interval.
73            ///
74            /// It will always panic **INDEPENDENTLY** of OpMode
75            pub const fn new(v: $i) -> Self
76            {
77                let _ = Self::COMPTIME_RANGE_CHECK;
78                Self::check_in_range(v);
79                Self(v, PhantomData)
80            }
81
82            /// Applies the OpMode to try to bring the
83            /// provided value into its intended range
84            pub fn new_adjust(v:$i) -> Self
85            {
86                let _ = Self::COMPTIME_RANGE_CHECK;
87                let v = OpMode::bring_in_range(v, MIN, MAX);
88                Self::check_in_range(v);
89                Self(v, PhantomData)
90            }
91
92            /// This constructor will check both range validity and that the value is in the range
93            /// at Compile time.
94            ///
95            /// The `V` number MUST be in range to compile correctly.
96            ///
97            /// For example, this code will compile just fine:
98            /// ```
99            #[doc=concat!("use light_ranged_integers::",stringify!($typename),";")]
100            #[doc=concat!("let m = ",stringify!($typename),"::<1,4>::new_const::<2>();")]
101            /// ```
102            ///
103            /// But this one will not compile, as 5 is outside of \[1,4\]
104            ///  ```rust,compile_fail
105            #[doc=concat!("use light_ranged_integers::",stringify!($typename),";")]
106            #[doc=concat!("let m = ",stringify!($typename),"::<1,4>::new_const::<5>();")]
107            /// ```
108            pub const fn new_const<const V: $i>() -> $typename::<MIN, MAX, OpMode>
109            {
110                let _ = Self::COMPTIME_RANGE_CHECK;
111                const_ranged::$const_typename::<MIN, MAX, V>::new().as_ranged::<OpMode>()
112            }
113
114
115            #[doc=concat!("Tries to construct a [",stringify!($typename),"]")]
116            ///
117            /// Checks the range during initialization.
118            /// If the value fits the range, returns a new Ranged value,
119            /// otherwise returns None
120            pub const fn new_try(value: $i) -> Option<Self>
121            {
122                let _ = Self::COMPTIME_RANGE_CHECK;
123                if value >= MIN && value <= MAX
124                {
125                    return Some(Self(value, PhantomData))
126                }
127                else
128                {
129                    return None
130                }
131            }
132
133            /// Returns a tuple containing the (MIN,MAX) interval limits
134            pub const fn get_limits(self) -> ($i,$i)
135            {
136                let _ = Self::COMPTIME_RANGE_CHECK;
137                (MIN,MAX)
138            }
139
140            /// Limits the value to a new minimum and maximum.
141            ///
142            /// Panics if the value does not fit the new range
143            pub fn limit<const NEW_MIN: $i, const NEW_MAX: $i>(self) -> $typename<NEW_MIN, NEW_MAX, OpMode>
144            {
145                let _ = Self::COMPTIME_RANGE_CHECK;
146                $typename::<NEW_MIN, NEW_MAX, OpMode>::new(self.0)
147            }
148
149            /// Limits the value to a new minimum and maximum.
150            ///
151            /// Adjusts the value by appliying the relevant [OpMode](op_mode::OpModeExt)
152            /// if the value does not fit the new range
153            pub fn limit_adjust<const NEW_MIN: $i, const NEW_MAX: $i>(self) -> $typename<NEW_MIN, NEW_MAX, OpMode>
154            {
155                let _ = Self::COMPTIME_RANGE_CHECK;
156                $typename::<NEW_MIN, NEW_MAX, OpMode>::new_adjust(self.0)
157            }
158
159
160            #[doc="Limits the value to a new minimum; keeps the previous maximum value limit."]
161            pub fn limit_min<const NEW_MIN:$i>(self) -> $typename<NEW_MIN, MAX, OpMode>
162            {
163                let _ = Self::COMPTIME_RANGE_CHECK;
164                self.limit::<NEW_MIN, MAX>()
165            }
166
167            #[doc="Limits the value to a new maximum; keeps the previous minimum value limit."]
168            pub fn limit_max<const NEW_MAX:$i>(self) -> $typename<MIN, NEW_MAX, OpMode>
169            {
170                let _ = Self::COMPTIME_RANGE_CHECK;
171                self.limit::<MIN, NEW_MAX>()
172            }
173
174            /// Returns the inner value alone
175            pub const fn inner(&self) -> $i
176            {
177                debug_assert!(self.0>=MIN && self.0<=MAX);
178                let _ = Self::COMPTIME_RANGE_CHECK;
179                self.0
180            }
181
182            /// Create a new Ranged number,
183            /// keeping the same interval
184            /// but applying the new mode
185            pub const fn as_mode<NewOpMode: op_mode::OpModeExt>(self) -> $typename<MIN,MAX,NewOpMode>
186            {
187                $typename::<MIN,MAX,NewOpMode>(self.0, PhantomData)
188            }
189
190            const fn check_in_range(v: $i)
191            {
192                assert!(v >= MIN && v <= MAX);
193            }
194        }
195
196        impl<OpMode, const MIN: $i, const MAX:$i> std::cmp::PartialEq<$i> for $typename<MIN, MAX, OpMode> where OpMode: op_mode::OpModeExt
197        {
198            fn eq(&self, other: &$i) -> bool
199            {
200                self.0.eq(other)
201            }
202        }
203        impl<OpMode, const MIN: $i, const MAX:$i> std::cmp::PartialEq for $typename<MIN, MAX, OpMode> where OpMode: op_mode::OpModeExt
204        {
205            fn eq(&self, other: &$typename<MIN, MAX, OpMode>) -> bool
206            {
207                self.0.eq(&other.0)
208            }
209        }
210        impl<OpMode, const MIN: $i, const MAX:$i> std::cmp::PartialOrd<$i> for $typename<MIN, MAX, OpMode> where OpMode: op_mode::OpModeExt
211        {
212            fn partial_cmp(&self, other: &$i) -> Option<std::cmp::Ordering>
213            {
214                self.0.partial_cmp(other)
215            }
216        }
217        impl<OpMode, const MIN: $i, const MAX:$i> std::cmp::PartialOrd for $typename<MIN, MAX, OpMode> where OpMode: op_mode::OpModeExt
218        {
219            fn partial_cmp(&self, other: &$typename<MIN, MAX, OpMode>) -> Option<std::cmp::Ordering>
220            {
221                self.0.partial_cmp(&other.0)
222            }
223        }
224
225        impl<OpMode, const MIN: $i, const MAX:$i> From<$i> for $typename<MIN,MAX,OpMode>
226            where OpMode: op_mode::OpModeExt
227        {
228            fn from(value: $i) -> Self {
229                Self::new(value)
230            }
231        }
232
233        impl<OpMode, const MIN: $i, const MAX:$i> std::fmt::Display for $typename<MIN,MAX,OpMode>
234            where OpMode: op_mode::OpModeExt
235        {
236            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
237                write!{f, "{}", self.inner()}
238            }
239        }
240    };
241    }
242
243gen_ranged_structs!(u8, RangedU8, ConstRangedU8);
244gen_ranged_structs!(u16, RangedU16, ConstRangedU16);
245gen_ranged_structs!(u32, RangedU32, ConstRangedU32);
246gen_ranged_structs!(u64, RangedU64, ConstRangedU64);
247gen_ranged_structs!(i8, RangedI8, ConstRangedI8);
248gen_ranged_structs!(i16, RangedI16, ConstRangedI16);
249gen_ranged_structs!(i32, RangedI32, ConstRangedI32);
250gen_ranged_structs!(i64, RangedI64, ConstRangedI64);
251
252// OPERATIONS IMPLEMENTATION
253mod wrap
254{
255    use super::*;
256
257    macro_rules! gen_add {
258        ($i:ty, $bigger:ty, $typename:ident) => {
259            impl<const MIN: $i, const MAX: $i> std::ops::Add<$i>
260                for $typename<MIN, MAX, op_mode::Wrap>
261            {
262                type Output = Self;
263                fn add(self, rhs: $i) -> Self::Output
264                {
265                    // KISS "keep it simple stupid"
266                    // there was a mathematically cool but longer implementation
267                    // Now I simply use a bigger type to avoid overflows
268                    // It still uses less variables than the "cool" version
269                    let min: $bigger = MIN as $bigger;
270                    let max: $bigger = MAX as $bigger;
271                    let interval_size: $bigger = max - min + 1;
272                    let rhs: $bigger = (rhs as $bigger).rem_euclid(interval_size);
273
274                    let res: $i = <$i>::try_from(
275                        ((((self.inner() as $bigger) - min) + rhs) % interval_size) + min
276                    )
277                    .unwrap();
278
279                    return $typename(res, PhantomData);
280                }
281            }
282            impl<const MIN: $i, const MAX: $i> std::ops::Sub<$i>
283                for $typename<MIN, MAX, op_mode::Wrap>
284            {
285                type Output = Self;
286                fn sub(self, rhs: $i) -> Self::Output
287                {
288                    // KISS "keep it simple stupid"
289                    // there was a mathematically cool but longer implementation
290                    // Now I simply use a bigger type to avoid overflows
291                    // It still uses less variables than the "cool" version
292                    let min: $bigger = MIN as $bigger;
293                    let max: $bigger = MAX as $bigger;
294                    let interval_size: $bigger = max - min + 1;
295                    let rhs: $bigger = (rhs as $bigger).rem_euclid(interval_size);
296
297                    // This is exactly the code for Addition, but
298                    // we use the modular arithmetic trick to
299                    // convert the Subtraction to an Addition
300                    // self - rhs (mod L) ≡ self + (L-rhs) (mod L)
301                    let res: $i = <$i>::try_from(
302                        ((((self.inner() as $bigger) - min) + (interval_size - rhs))
303                            % interval_size)
304                            + min
305                    )
306                    .unwrap();
307                    return $typename(res, PhantomData);
308                }
309            }
310        };
311    }
312
313    gen_add!(u8, u16, RangedU8);
314    gen_add!(u16, u32, RangedU16);
315    gen_add!(u32, u64, RangedU32);
316    gen_add!(u64, u128, RangedU64);
317    gen_add!(i8, i16, RangedI8);
318    gen_add!(i16, i32, RangedI16);
319    gen_add!(i32, i64, RangedI32);
320    gen_add!(i64, i128, RangedI64);
321}
322
323mod panic
324{
325    use super::*;
326    macro_rules! gen_panic_impl {
327        ($i:ty, $typename:ident) => {
328            // Additions
329            impl<const MIN: $i, const MAX: $i> std::ops::Add for $typename<MIN, MAX, op_mode::Panic>
330            {
331                type Output = Self;
332                fn add(self, rhs: $typename<MIN, MAX, op_mode::Panic>) -> Self::Output
333                {
334                    self + rhs.inner()
335                }
336            }
337            impl<const MIN: $i, const MAX: $i> std::ops::Add<$i>
338                for $typename<MIN, MAX, op_mode::Panic>
339            {
340                type Output = Self;
341                fn add(self, rhs: $i) -> Self::Output
342                {
343                    Self::new(self.inner().checked_add(rhs).unwrap())
344                }
345            }
346            impl<const MIN: $i, const MAX: $i> std::ops::AddAssign
347                for $typename<MIN, MAX, op_mode::Panic>
348            {
349                fn add_assign(&mut self, rhs: $typename<MIN, MAX, op_mode::Panic>)
350                {
351                    *self += rhs.inner();
352                }
353            }
354            impl<const MIN: $i, const MAX: $i> std::ops::AddAssign<$i>
355                for $typename<MIN, MAX, op_mode::Panic>
356            {
357                fn add_assign(&mut self, rhs: $i)
358                {
359                    *self = Self::new(self.inner().checked_add(rhs).unwrap());
360                }
361            }
362
363            // Subtraction
364            impl<const MIN: $i, const MAX: $i> std::ops::Sub for $typename<MIN, MAX, op_mode::Panic>
365            {
366                type Output = Self;
367                fn sub(self, rhs: $typename<MIN, MAX, op_mode::Panic>) -> Self::Output
368                {
369                    self - rhs.inner()
370                }
371            }
372            impl<const MIN: $i, const MAX: $i> std::ops::Sub<$i>
373                for $typename<MIN, MAX, op_mode::Panic>
374            {
375                type Output = Self;
376                fn sub(self, rhs: $i) -> Self::Output
377                {
378                    Self::new(self.inner().checked_sub(rhs).unwrap())
379                }
380            }
381            impl<const MIN: $i, const MAX: $i> std::ops::SubAssign
382                for $typename<MIN, MAX, op_mode::Panic>
383            {
384                fn sub_assign(&mut self, rhs: $typename<MIN, MAX, op_mode::Panic>)
385                {
386                    *self -= rhs.inner();
387                }
388            }
389            impl<const MIN: $i, const MAX: $i> std::ops::SubAssign<$i>
390                for $typename<MIN, MAX, op_mode::Panic>
391            {
392                fn sub_assign(&mut self, rhs: $i)
393                {
394                    *self = Self::new(self.inner().checked_sub(rhs).unwrap());
395                }
396            }
397
398            // Multiplication
399            impl<const MIN: $i, const MAX: $i> std::ops::Mul for $typename<MIN, MAX, op_mode::Panic>
400            {
401                type Output = Self;
402                fn mul(self, rhs: $typename<MIN, MAX, op_mode::Panic>) -> Self::Output
403                {
404                    self * rhs.inner()
405                }
406            }
407            impl<const MIN: $i, const MAX: $i> std::ops::Mul<$i>
408                for $typename<MIN, MAX, op_mode::Panic>
409            {
410                type Output = Self;
411                fn mul(self, rhs: $i) -> Self::Output
412                {
413                    Self::new(self.inner().checked_mul(rhs).unwrap())
414                }
415            }
416            impl<const MIN: $i, const MAX: $i> std::ops::MulAssign
417                for $typename<MIN, MAX, op_mode::Panic>
418            {
419                fn mul_assign(&mut self, rhs: $typename<MIN, MAX, op_mode::Panic>)
420                {
421                    *self = Self::new(self.inner().checked_mul(rhs.inner()).unwrap());
422                }
423            }
424            impl<const MIN: $i, const MAX: $i> std::ops::MulAssign<$i>
425                for $typename<MIN, MAX, op_mode::Panic>
426            {
427                fn mul_assign(&mut self, rhs: $i)
428                {
429                    *self = Self::new(self.inner().checked_mul(rhs).unwrap());
430                }
431            }
432
433            // Division
434            impl<const MIN: $i, const MAX: $i> std::ops::Div for $typename<MIN, MAX, op_mode::Panic>
435            {
436                type Output = Self;
437                fn div(self, rhs: $typename<MIN, MAX, op_mode::Panic>) -> Self::Output
438                {
439                    self / rhs.inner()
440                }
441            }
442            impl<const MIN: $i, const MAX: $i> std::ops::Div<$i>
443                for $typename<MIN, MAX, op_mode::Panic>
444            {
445                type Output = Self;
446                fn div(self, rhs: $i) -> Self::Output
447                {
448                    Self::new(self.inner().checked_div(rhs).unwrap())
449                }
450            }
451            impl<const MIN: $i, const MAX: $i> std::ops::DivAssign
452                for $typename<MIN, MAX, op_mode::Panic>
453            {
454                fn div_assign(&mut self, rhs: $typename<MIN, MAX, op_mode::Panic>)
455                {
456                    *self = Self::new(self.inner().checked_div(rhs.inner()).unwrap());
457                }
458            }
459            impl<const MIN: $i, const MAX: $i> std::ops::DivAssign<$i>
460                for $typename<MIN, MAX, op_mode::Panic>
461            {
462                fn div_assign(&mut self, rhs: $i)
463                {
464                    *self = Self::new(self.inner().checked_div(rhs).unwrap());
465                }
466            }
467        };
468    }
469
470    gen_panic_impl!(u8, RangedU8);
471    gen_panic_impl!(u16, RangedU16);
472    gen_panic_impl!(u32, RangedU32);
473    gen_panic_impl!(u64, RangedU64);
474    gen_panic_impl!(i8, RangedI8);
475    gen_panic_impl!(i16, RangedI16);
476    gen_panic_impl!(i32, RangedI32);
477    gen_panic_impl!(i64, RangedI64);
478}
479
480mod clamp
481{
482    use super::*;
483    macro_rules! gen_clamp_impl {
484        ($i:ty, $typename:ident) => {
485            // Additions
486            impl<const MIN: $i, const MAX: $i> std::ops::Add for $typename<MIN, MAX, op_mode::Clamp>
487            {
488                type Output = Self;
489                fn add(self, rhs: $typename<MIN, MAX, op_mode::Clamp>) -> Self::Output
490                {
491                    self + rhs.inner()
492                }
493            }
494            impl<const MIN: $i, const MAX: $i> std::ops::Add<$i>
495                for $typename<MIN, MAX, op_mode::Clamp>
496            {
497                type Output = Self;
498                fn add(self, rhs: $i) -> Self::Output
499                {
500                    Self::new_adjust(self.inner().saturating_add(rhs))
501                }
502            }
503            impl<const MIN: $i, const MAX: $i> std::ops::AddAssign
504                for $typename<MIN, MAX, op_mode::Clamp>
505            {
506                fn add_assign(&mut self, rhs: $typename<MIN, MAX, op_mode::Clamp>)
507                {
508                    *self = *self + rhs;
509                }
510            }
511            impl<const MIN: $i, const MAX: $i> std::ops::AddAssign<$i>
512                for $typename<MIN, MAX, op_mode::Clamp>
513            {
514                fn add_assign(&mut self, rhs: $i)
515                {
516                    *self = Self::new_adjust(self.inner().saturating_add(rhs));
517                }
518            }
519
520            // Subtraction
521            impl<const MIN: $i, const MAX: $i> std::ops::Sub for $typename<MIN, MAX, op_mode::Clamp>
522            {
523                type Output = Self;
524                fn sub(self, rhs: $typename<MIN, MAX, op_mode::Clamp>) -> Self::Output
525                {
526                    self - rhs.inner()
527                }
528            }
529            impl<const MIN: $i, const MAX: $i> std::ops::Sub<$i>
530                for $typename<MIN, MAX, op_mode::Clamp>
531            {
532                type Output = Self;
533                fn sub(self, rhs: $i) -> Self::Output
534                {
535                    Self::new_adjust(self.inner().saturating_sub(rhs))
536                }
537            }
538            impl<const MIN: $i, const MAX: $i> std::ops::SubAssign
539                for $typename<MIN, MAX, op_mode::Clamp>
540            {
541                fn sub_assign(&mut self, rhs: $typename<MIN, MAX, op_mode::Clamp>)
542                {
543                    *self -= rhs.inner();
544                }
545            }
546            impl<const MIN: $i, const MAX: $i> std::ops::SubAssign<$i>
547                for $typename<MIN, MAX, op_mode::Clamp>
548            {
549                fn sub_assign(&mut self, rhs: $i)
550                {
551                    *self = Self::new_adjust(self.inner().saturating_sub(rhs));
552                }
553            }
554
555            // Multiplication
556            impl<const MIN: $i, const MAX: $i> std::ops::Mul for $typename<MIN, MAX, op_mode::Clamp>
557            {
558                type Output = Self;
559                fn mul(self, rhs: $typename<MIN, MAX, op_mode::Clamp>) -> Self::Output
560                {
561                    self * rhs.inner()
562                }
563            }
564            impl<const MIN: $i, const MAX: $i> std::ops::Mul<$i>
565                for $typename<MIN, MAX, op_mode::Clamp>
566            {
567                type Output = Self;
568                fn mul(self, rhs: $i) -> Self::Output
569                {
570                    Self::new_adjust(self.inner().saturating_mul(rhs))
571                }
572            }
573            impl<const MIN: $i, const MAX: $i> std::ops::MulAssign
574                for $typename<MIN, MAX, op_mode::Clamp>
575            {
576                fn mul_assign(&mut self, rhs: $typename<MIN, MAX, op_mode::Clamp>)
577                {
578                    *self = *self * rhs;
579                }
580            }
581            impl<const MIN: $i, const MAX: $i> std::ops::MulAssign<$i>
582                for $typename<MIN, MAX, op_mode::Clamp>
583            {
584                fn mul_assign(&mut self, rhs: $i)
585                {
586                    *self = *self * rhs;
587                }
588            }
589
590            // Division
591            impl<const MIN: $i, const MAX: $i> std::ops::Div for $typename<MIN, MAX, op_mode::Clamp>
592            {
593                type Output = Self;
594                fn div(self, rhs: $typename<MIN, MAX, op_mode::Clamp>) -> Self::Output
595                {
596                    self / rhs.inner()
597                }
598            }
599            impl<const MIN: $i, const MAX: $i> std::ops::Div<$i>
600                for $typename<MIN, MAX, op_mode::Clamp>
601            {
602                type Output = Self;
603                fn div(self, rhs: $i) -> Self::Output
604                {
605                    Self::new_adjust(self.inner().saturating_div(rhs))
606                }
607            }
608            impl<const MIN: $i, const MAX: $i> std::ops::DivAssign
609                for $typename<MIN, MAX, op_mode::Clamp>
610            {
611                fn div_assign(&mut self, rhs: $typename<MIN, MAX, op_mode::Clamp>)
612                {
613                    *self = *self / rhs;
614                }
615            }
616            impl<const MIN: $i, const MAX: $i> std::ops::DivAssign<$i>
617                for $typename<MIN, MAX, op_mode::Clamp>
618            {
619                fn div_assign(&mut self, rhs: $i)
620                {
621                    *self = *self / rhs;
622                }
623            }
624        };
625    }
626
627    gen_clamp_impl!(u8, RangedU8);
628    gen_clamp_impl!(u16, RangedU16);
629    gen_clamp_impl!(u32, RangedU32);
630    gen_clamp_impl!(u64, RangedU64);
631    gen_clamp_impl!(i8, RangedI8);
632    gen_clamp_impl!(i16, RangedI16);
633    gen_clamp_impl!(i32, RangedI32);
634    gen_clamp_impl!(i64, RangedI64);
635}
636
637/// Compile time checked ranges
638mod const_ranged
639{
640    use super::*;
641    use crate::op_mode;
642    macro_rules! gen_const_ranged_structs {
643        ($i:ty, $typename:ident, $const_typename:ident) => {
644            #[derive(Clone, Copy)]
645            #[doc = concat!("A compile-time checked [",stringify!($typename),"] struct.\n\n")]
646            pub struct $const_typename<const MIN: $i, const MAX: $i, const V: $i>;
647            impl<const MIN: $i, const MAX: $i, const V: $i> $const_typename<MIN, MAX, V>
648            {
649                const RANGE_VALID: () = assert!(
650                    MIN < MAX,
651                    "The range is not valid. MIN must be smaller than MAX"
652                );
653                const IS_IN_RANGE: () = assert!(
654                    V >= MIN && V <= MAX,
655                    "Provided value V is outside of the range"
656                );
657
658                /// Creates a new compile-checked range number.
659                /// The number MUST be in range to compile correctly,
660                /// independently of the [OpMode](op_mode)
661                pub const fn new() -> Self
662                {
663                    let _ = Self::RANGE_VALID;
664                    let _ = Self::IS_IN_RANGE;
665                    return $const_typename::<MIN, MAX, V>;
666                }
667
668                /// Converts to a runtime Ranged value, assigning the provided OpMode
669                pub const fn as_ranged<OpMode: op_mode::OpModeExt>(
670                    &self
671                ) -> $typename<MIN, MAX, OpMode>
672                {
673                    return $typename::<MIN, MAX, OpMode>(V, PhantomData);
674                }
675            }
676        };
677    }
678
679    gen_const_ranged_structs!(u8, RangedU8, ConstRangedU8);
680    gen_const_ranged_structs!(u16, RangedU16, ConstRangedU16);
681    gen_const_ranged_structs!(u32, RangedU32, ConstRangedU32);
682    gen_const_ranged_structs!(u64, RangedU64, ConstRangedU64);
683    gen_const_ranged_structs!(i8, RangedI8, ConstRangedI8);
684    gen_const_ranged_structs!(i16, RangedI16, ConstRangedI16);
685    gen_const_ranged_structs!(i32, RangedI32, ConstRangedI32);
686    gen_const_ranged_structs!(i64, RangedI64, ConstRangedI64);
687}
688
689// // Shortcuts
690// #[doc = concat!("A ranged integer between the provided MIN and [", $i ,"::MAX].\n\n")]
691// pub type [<Ranged $i:upper Min>]<const MIN:$i, OpMode=op_mode::Panic> = [<Ranged $i:upper>]<MIN, {$i::MAX}, OpMode>;
692// #[doc = "A ranged integer between [" $i "::MIN] and the provided MAX.\n\n"]
693// pub type [<Ranged $i:upper Max>]<const MAX:$i, OpMode=op_mode::Panic> = [<Ranged $i:upper>]<{$i::MIN}, MAX, OpMode>;