1use 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 #[doc= concat!(stringify!($typename), "<MIN, MAX, OpMode>")]
31 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 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 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 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 #[doc=concat!("use light_ranged_integers::",stringify!($typename),";")]
100 #[doc=concat!("let m = ",stringify!($typename),"::<1,4>::new_const::<2>();")]
101 #[doc=concat!("use light_ranged_integers::",stringify!($typename),";")]
106 #[doc=concat!("let m = ",stringify!($typename),"::<1,4>::new_const::<5>();")]
107 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 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 pub const fn get_limits(self) -> ($i,$i)
135 {
136 let _ = Self::COMPTIME_RANGE_CHECK;
137 (MIN,MAX)
138 }
139
140 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 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 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 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
252mod 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 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 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 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 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 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 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 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 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 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 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 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
637mod 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 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 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