1use std::{
2 num,
3 ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, RangeInclusive, Rem, Sub},
4};
5
6use crate::{InherentBehavior, InherentLimits, OpBehaviorParams};
7use anyhow::Result;
8
9pub unsafe trait ClampedInteger<T: Copy>:
10 'static + Default + Eq + Ord + InherentLimits<T>
11{
12 fn from_primitive(val: T) -> Result<Self>;
13
14 unsafe fn from_primitive_unchecked(val: T) -> Self {
15 Self::from_primitive(val).unwrap_unchecked()
16 }
17
18 fn as_primitive(&self) -> &T;
19
20 fn into_primitive(&self) -> T {
21 *self.as_primitive()
22 }
23}
24
25macro_rules! impl_clamped_integer_for_basic_types {
26 ($($ty:ty),* $(,)?) => {
27 $(
28 impl InherentLimits<$ty> for $ty {
29 const MIN: $ty = <$ty>::MIN;
30 const MAX: $ty = <$ty>::MAX;
31 const MIN_INT: $ty = <$ty>::MIN;
32 const MAX_INT: $ty = <$ty>::MAX;
33
34 #[inline(always)]
35 fn is_zero(&self) -> bool {
36 *self == 0
37 }
38
39 #[inline(always)]
40 #[allow(unused_comparisons)]
41 fn is_negative(&self) -> bool {
42 *self < 0
43 }
44
45 #[inline(always)]
46 fn is_positive(&self) -> bool {
47 *self > 0
48 }
49 }
50
51 unsafe impl ClampedInteger<$ty> for $ty {
52 fn from_primitive(val: $ty) -> Result<Self> {
53 Ok(val)
54 }
55
56 fn as_primitive(&self) -> &$ty {
57 self
58 }
59 }
60 )*
61 };
62}
63
64impl_clamped_integer_for_basic_types! {
65 i8, i16, i32, i64, i128,
66 u8, u16, u32, u64, u128,
67 isize, usize,
68}
69
70#[derive(Debug, Clone)]
71#[repr(transparent)]
72pub struct ValueRangeInclusive<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
73 pub RangeInclusive<T>,
74);
75
76impl<T: 'static + Copy + Eq + Ord + InherentLimits<T>> ValueRangeInclusive<T> {
77 pub fn contains(&self, val: T) -> bool {
78 val >= *self.0.start() && val <= *self.0.end()
79 }
80
81 pub fn first_val(&self) -> T {
82 *self.0.start()
83 }
84
85 pub fn last_val(&self) -> T {
86 *self.0.end()
87 }
88}
89
90pub unsafe trait ExactValues<T: 'static + Copy + Eq + Ord>:
93 'static + Default + Eq + Ord
94{
95 const VALUES: &'static [T];
96
97 fn contains_value(val: T) -> bool {
98 Self::VALUES.contains(&val)
99 }
100}
101
102pub unsafe trait RangeValues<T: 'static + Copy + Eq + Ord + InherentLimits<T>>:
105 ClampedInteger<T> + InherentBehavior
106{
107 const VALID_RANGES: &'static [ValueRangeInclusive<T>];
108}
109
110pub unsafe trait SoftClamp<T: 'static + Copy + Eq + Ord + InherentLimits<T>>:
111 RangeValues<T>
112{
113}
114
115pub unsafe trait HardClamp<T: 'static + Copy + Eq + Ord + InherentLimits<T>>:
116 RangeValues<T>
117{
118}
119
120pub unsafe trait ClampedEnum<T: Copy>: ClampedInteger<T> + InherentBehavior {}
121
122#[derive(Debug, Clone, Copy, thiserror::Error)]
123pub enum ClampError<T: Copy> {
124 #[error("Value too small: {val} (min: {min})")]
125 TooSmall { val: T, min: T },
126 #[error("Value too large: {val} (max: {max})")]
127 TooLarge { val: T, max: T },
128 #[error("Value out of bounds: {val} (between ranges: {left_min}..={left_max} and {right_min}..={right_max})")]
129 OutOfBounds {
130 val: T,
131 left_min: T,
132 left_max: T,
133 right_min: T,
134 right_max: T,
135 },
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
139pub enum Panicking {}
140
141fn maybe_panic<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
142 op_name: &str,
143 val: T,
144 params: OpBehaviorParams<T>,
145) -> T {
146 match params {
147 OpBehaviorParams::Simple { min, max } => {
148 if val < min {
149 panic!("{} underflow", op_name);
150 }
151
152 if val > max {
153 panic!("{} overflow", op_name);
154 }
155
156 return val;
157 }
158 OpBehaviorParams::ExactsOnly(exacts) => {
159 for exact in exacts {
160 if val == *exact {
161 return val;
162 }
163 }
164
165 panic!("{} result is not an allowed exact value", op_name);
166 }
167 OpBehaviorParams::RangesOnly(ranges) => {
168 for range in ranges {
169 if range.contains(val) {
170 return val;
171 }
172 }
173
174 panic!("{} result is out of bounds", op_name);
175 }
176 OpBehaviorParams::ExactsAndRanges { exacts, ranges } => {
177 for exact in exacts {
178 if val == *exact {
179 return val;
180 }
181 }
182
183 for range in ranges {
184 if range.contains(val) {
185 return val;
186 }
187 }
188
189 panic!("{} result is out of bounds", op_name);
190 }
191 }
192}
193
194impl crate::Behavior for Panicking {
195 fn add<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
196 lhs: T,
197 rhs: T,
198 params: OpBehaviorParams<T>,
199 ) -> T
200 where
201 T: Add<Output = T>,
202 T::Output: Eq + Ord + Into<T>,
203 num::Saturating<T>: Add<Output = num::Saturating<T>>,
204 <num::Saturating<T> as Add>::Output: Eq + Ord + Into<num::Saturating<T>>,
205 {
206 maybe_panic("Addition", lhs + rhs, params)
207 }
208
209 fn sub<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
210 lhs: T,
211 rhs: T,
212 params: OpBehaviorParams<T>,
213 ) -> T
214 where
215 T: Sub<Output = T>,
216 T::Output: Eq + Ord + Into<T>,
217 num::Saturating<T>: Sub<Output = num::Saturating<T>>,
218 <num::Saturating<T> as Sub>::Output: Eq + Ord + Into<num::Saturating<T>>,
219 {
220 maybe_panic("Subtraction", lhs - rhs, params)
221 }
222
223 fn mul<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
224 lhs: T,
225 rhs: T,
226 params: OpBehaviorParams<T>,
227 ) -> T
228 where
229 T: Mul<Output = T>,
230 T::Output: Eq + Ord + Into<T>,
231 num::Saturating<T>: Mul<Output = num::Saturating<T>>,
232 <num::Saturating<T> as Mul>::Output: Eq + Ord + Into<num::Saturating<T>>,
233 {
234 maybe_panic("Multiplication", lhs * rhs, params)
235 }
236
237 fn div<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
238 lhs: T,
239 rhs: T,
240 params: OpBehaviorParams<T>,
241 ) -> T
242 where
243 T: Div<Output = T>,
244 T::Output: Eq + Ord + Into<T>,
245 num::Saturating<T>: Div<Output = num::Saturating<T>>,
246 <num::Saturating<T> as Div>::Output: Eq + Ord + Into<num::Saturating<T>>,
247 {
248 maybe_panic("Division", lhs / rhs, params)
249 }
250
251 fn rem<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
252 lhs: T,
253 rhs: T,
254 params: OpBehaviorParams<T>,
255 ) -> T
256 where
257 T: Rem<Output = T> + Sub<Output = T>,
258 <T as Rem>::Output: Eq + Ord + Into<T>,
259 <T as Sub>::Output: Eq + Ord + Into<T>,
260 num::Saturating<T>: Rem<Output = num::Saturating<T>>,
261 <num::Saturating<T> as Rem>::Output: Eq + Ord + Into<num::Saturating<T>>,
262 {
263 maybe_panic("Remainder", lhs % rhs, params)
264 }
265
266 fn bitand<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
267 lhs: T,
268 rhs: T,
269 params: OpBehaviorParams<T>,
270 ) -> T
271 where
272 T: BitAnd<Output = T> + Sub<Output = T>,
273 <T as BitAnd>::Output: Eq + Ord + Into<T>,
274 <T as Sub>::Output: Eq + Ord + Into<T>,
275 num::Saturating<T>: BitAnd<Output = num::Saturating<T>>,
276 <num::Saturating<T> as BitAnd>::Output: Eq + Ord + Into<num::Saturating<T>>,
277 {
278 maybe_panic("Bitwise AND", lhs & rhs, params)
279 }
280
281 fn bitor<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
282 lhs: T,
283 rhs: T,
284 params: OpBehaviorParams<T>,
285 ) -> T
286 where
287 T: BitOr<Output = T> + Sub<Output = T>,
288 <T as BitOr>::Output: Eq + Ord + Into<T>,
289 <T as Sub>::Output: Eq + Ord + Into<T>,
290 num::Saturating<T>: BitOr<Output = num::Saturating<T>>,
291 <num::Saturating<T> as BitOr>::Output: Eq + Ord + Into<num::Saturating<T>>,
292 {
293 maybe_panic("Bitwise OR", lhs | rhs, params)
294 }
295
296 fn bitxor<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
297 lhs: T,
298 rhs: T,
299 params: OpBehaviorParams<T>,
300 ) -> T
301 where
302 T: BitXor<Output = T> + Sub<Output = T>,
303 <T as BitXor>::Output: Eq + Ord + Into<T>,
304 <T as Sub>::Output: Eq + Ord + Into<T>,
305 num::Saturating<T>: BitXor<Output = num::Saturating<T>>,
306 <num::Saturating<T> as BitXor>::Output: Eq + Ord + Into<num::Saturating<T>>,
307 {
308 maybe_panic("Bitwise XOR", lhs ^ rhs, params)
309 }
310
311 fn neg<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
312 val: T,
313 params: OpBehaviorParams<T>,
314 ) -> T
315 where
316 T: Neg<Output = T> + Sub<Output = T>,
317 <T as Neg>::Output: Eq + Ord + Into<T>,
318 <T as Sub>::Output: Eq + Ord + Into<T>,
319 num::Saturating<T>: Neg<Output = num::Saturating<T>>,
320 <num::Saturating<T> as Neg>::Output: Eq + Ord + Into<num::Saturating<T>>,
321 {
322 maybe_panic("Negation", -val, params)
323 }
324
325 fn not<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
326 val: T,
327 params: OpBehaviorParams<T>,
328 ) -> T
329 where
330 T: Not<Output = T> + Sub<Output = T>,
331 <T as Not>::Output: Eq + Ord + Into<T>,
332 <T as Sub>::Output: Eq + Ord + Into<T>,
333 num::Saturating<T>: Not<Output = num::Saturating<T>>,
334 <num::Saturating<T> as Not>::Output: Eq + Ord + Into<num::Saturating<T>>,
335 {
336 maybe_panic("Bitwise NOT", !val, params)
337 }
338}
339
340#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
341pub enum Saturating {}
342
343fn left_saturating_exacts<T: Copy + Eq + Ord + InherentLimits<T>>(
344 val: T,
345 exacts: &[T],
346) -> Option<T> {
347 for (left, right) in exacts.windows(2).map(|w| (w[0], w[1])) {
348 if val == left || val == right {
349 return Some(val);
350 }
351
352 if val > left && val < right {
353 return Some(left);
355 }
356 }
357
358 None
359}
360
361fn right_saturating_exacts<T: Copy + Eq + Ord + InherentLimits<T>>(
362 val: T,
363 exacts: &[T],
364) -> Option<T> {
365 for (left, right) in exacts.windows(2).map(|w| (w[0], w[1])) {
366 if val == left || val == right {
367 return Some(val);
368 }
369
370 if val > left && val < right {
371 return Some(right);
373 }
374 }
375
376 None
377}
378
379fn nearest_saturating_exacts<T: Copy + Eq + Ord + InherentLimits<T> + Sub<Output = T>>(
380 val: T,
381 exacts: &[T],
382) -> Option<T> {
383 for (left, right) in exacts.windows(2).map(|w| (w[0], w[1])) {
384 if val == left || val == right {
385 return Some(val);
386 }
387
388 if val > left && val < right {
389 let left_diff = val - left;
391 let right_diff = right - val;
392
393 if left_diff < right_diff {
394 return Some(left);
395 } else {
396 return Some(right);
397 }
398 }
399 }
400
401 None
402}
403
404fn left_saturating_ranges<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
405 val: T,
406 ranges: &[ValueRangeInclusive<T>],
407) -> Option<T> {
408 for (left, right) in ranges.windows(2).map(|w| (&w[0], &w[1])) {
409 if left.contains(val) {
410 return Some(val);
411 }
412
413 if val > left.last_val() && val < right.first_val() {
414 return Some(left.last_val());
416 }
417 }
418
419 None
420}
421
422fn right_saturating_ranges<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
423 val: T,
424 ranges: &[ValueRangeInclusive<T>],
425) -> Option<T> {
426 for (left, right) in ranges.windows(2).map(|w| (&w[0], &w[1])) {
427 if left.contains(val) {
428 return Some(val);
429 }
430
431 if val > left.last_val() && val < right.first_val() {
432 return Some(right.first_val());
434 }
435 }
436
437 None
438}
439
440fn nearest_saturating_ranges<T: 'static + Copy + Eq + Ord + InherentLimits<T> + Sub<Output = T>>(
441 val: T,
442 ranges: &[ValueRangeInclusive<T>],
443) -> Option<T> {
444 for (left, right) in ranges.windows(2).map(|w| (&w[0], &w[1])) {
445 if left.contains(val) {
446 return Some(val);
447 }
448
449 if val > left.last_val() && val < right.first_val() {
450 let left_diff = val - left.last_val();
452 let right_diff = right.first_val() - val;
453
454 if left_diff < right_diff {
455 return Some(left.last_val());
456 } else {
457 return Some(right.first_val());
458 }
459 }
460 }
461
462 None
463}
464
465#[inline(always)]
466fn resolve_saturation_left<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
467 val: T,
468 params: OpBehaviorParams<T>,
469) -> T {
470 match params {
471 OpBehaviorParams::Simple { min, max } => {
472 if val < min {
473 min
474 } else if val > max {
475 max
476 } else {
477 val
478 }
479 }
480 OpBehaviorParams::ExactsOnly(exacts) => {
481 #[cfg(debug_assertions)]
482 {
483 if exacts.len() == 0 {
484 panic!("No values provided");
485 }
486 }
487
488 if let Some(val) = left_saturating_exacts(val, exacts) {
489 val
490 } else if val < exacts[0] {
491 exacts[0]
492 } else {
493 exacts[exacts.len() - 1]
494 }
495 }
496 OpBehaviorParams::RangesOnly(ranges) => {
497 #[cfg(debug_assertions)]
498 {
499 if ranges.len() == 0 {
500 panic!("No ranges provided");
501 }
502 }
503
504 if let Some(val) = left_saturating_ranges(val, ranges) {
505 return val;
506 }
507
508 let lower_limit = ranges[0].first_val();
509 let upper_limit = ranges[ranges.len() - 1].last_val();
510
511 if val < lower_limit {
512 lower_limit
513 } else {
514 upper_limit
515 }
516 }
517 OpBehaviorParams::ExactsAndRanges { exacts, ranges } => {
518 #[cfg(debug_assertions)]
519 {
520 if exacts.len() == 0 {
521 panic!("No values provided");
522 }
523 }
524
525 #[cfg(debug_assertions)]
526 {
527 if exacts.len() == 0 {
528 panic!("No ranges provided");
529 }
530 }
531
532 if let Some(val) = left_saturating_exacts(val, exacts) {
533 return val;
534 }
535
536 if let Some(val) = left_saturating_ranges(val, ranges) {
537 return val;
538 }
539
540 let lower_limit = exacts[0].min(ranges[0].first_val());
541 let upper_limit = exacts[exacts.len() - 1].max(ranges[ranges.len() - 1].last_val());
542
543 if val < lower_limit {
544 lower_limit
545 } else {
546 upper_limit
547 }
548 }
549 }
550}
551
552#[inline(always)]
553fn resolve_saturation_right<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
554 val: T,
555 params: OpBehaviorParams<T>,
556) -> T {
557 match params {
558 OpBehaviorParams::Simple { min, max } => {
559 if val < min {
560 min
561 } else if val > max {
562 max
563 } else {
564 val
565 }
566 }
567 OpBehaviorParams::ExactsOnly(exacts) => {
568 #[cfg(debug_assertions)]
569 {
570 if exacts.len() == 0 {
571 panic!("No values provided");
572 }
573 }
574
575 if let Some(val) = right_saturating_exacts(val, exacts) {
576 val
577 } else if val < exacts[0] {
578 exacts[0]
579 } else {
580 exacts[exacts.len() - 1]
581 }
582 }
583 OpBehaviorParams::RangesOnly(ranges) => {
584 #[cfg(debug_assertions)]
585 {
586 if ranges.len() == 0 {
587 panic!("No ranges provided");
588 }
589 }
590
591 if let Some(val) = right_saturating_ranges(val, ranges) {
592 return val;
593 }
594
595 let lower_limit = ranges[0].first_val();
596 let upper_limit = ranges[ranges.len() - 1].last_val();
597
598 if val < lower_limit {
599 lower_limit
600 } else {
601 upper_limit
602 }
603 }
604 OpBehaviorParams::ExactsAndRanges { exacts, ranges } => {
605 #[cfg(debug_assertions)]
606 {
607 if exacts.len() == 0 {
608 panic!("No values provided");
609 }
610 }
611
612 #[cfg(debug_assertions)]
613 {
614 if exacts.len() == 0 {
615 panic!("No ranges provided");
616 }
617 }
618
619 if let Some(val) = right_saturating_exacts(val, exacts) {
620 return val;
621 }
622
623 if let Some(val) = right_saturating_ranges(val, ranges) {
624 return val;
625 }
626
627 let lower_limit = exacts[0].min(ranges[0].first_val());
628 let upper_limit = exacts[exacts.len() - 1].max(ranges[ranges.len() - 1].last_val());
629
630 if val < lower_limit {
631 lower_limit
632 } else {
633 upper_limit
634 }
635 }
636 }
637}
638
639#[inline(always)]
640fn resolve_saturation_nearest<
641 T: 'static + Copy + Eq + Ord + InherentLimits<T> + Sub<Output = T>,
642>(
643 val: T,
644 params: OpBehaviorParams<T>,
645) -> T {
646 match params {
647 OpBehaviorParams::Simple { min, max } => {
648 if val < min {
649 min
650 } else if val > max {
651 max
652 } else {
653 val
654 }
655 }
656 OpBehaviorParams::ExactsOnly(exacts) => {
657 #[cfg(debug_assertions)]
658 {
659 if exacts.len() == 0 {
660 panic!("No values provided");
661 }
662 }
663
664 if let Some(val) = nearest_saturating_exacts(val, exacts) {
665 val
666 } else if val < exacts[0] {
667 exacts[0]
668 } else {
669 exacts[exacts.len() - 1]
670 }
671 }
672 OpBehaviorParams::RangesOnly(ranges) => {
673 #[cfg(debug_assertions)]
674 {
675 if ranges.len() == 0 {
676 panic!("No ranges provided");
677 }
678 }
679
680 if let Some(val) = nearest_saturating_ranges(val, ranges) {
681 return val;
682 }
683
684 let lower_limit = ranges[0].first_val();
685 let upper_limit = ranges[ranges.len() - 1].last_val();
686
687 if val < lower_limit {
688 lower_limit
689 } else {
690 upper_limit
691 }
692 }
693 OpBehaviorParams::ExactsAndRanges { exacts, ranges } => {
694 #[cfg(debug_assertions)]
695 {
696 if exacts.len() == 0 {
697 panic!("No values provided");
698 }
699 }
700
701 #[cfg(debug_assertions)]
702 {
703 if exacts.len() == 0 {
704 panic!("No ranges provided");
705 }
706 }
707
708 if let Some(val) = nearest_saturating_exacts(val, exacts) {
709 return val;
710 }
711
712 if let Some(val) = nearest_saturating_ranges(val, ranges) {
713 return val;
714 }
715
716 let lower_limit = exacts[0].min(ranges[0].first_val());
717 let upper_limit = exacts[exacts.len() - 1].max(ranges[ranges.len() - 1].last_val());
718
719 if val < lower_limit {
720 lower_limit
721 } else {
722 upper_limit
723 }
724 }
725 }
726}
727
728impl crate::Behavior for Saturating {
729 fn add<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
730 lhs: T,
731 rhs: T,
732 params: OpBehaviorParams<T>,
733 ) -> T
734 where
735 T: Add<Output = T>,
736 T::Output: Eq + Ord + Into<T>,
737 num::Saturating<T>: Add<Output = num::Saturating<T>>,
738 <num::Saturating<T> as Add>::Output: Eq + Ord + Into<num::Saturating<T>>,
739 {
740 let lhs = num::Saturating(lhs);
741 let rhs = num::Saturating(rhs);
742 let num::Saturating(val) = lhs + rhs;
743
744 resolve_saturation_left(val, params)
745 }
746
747 fn sub<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
748 lhs: T,
749 rhs: T,
750 params: OpBehaviorParams<T>,
751 ) -> T
752 where
753 T: Sub<Output = T>,
754 T::Output: Eq + Ord + Into<T>,
755 num::Saturating<T>: Sub<Output = num::Saturating<T>>,
756 <num::Saturating<T> as Sub>::Output: Eq + Ord + Into<num::Saturating<T>>,
757 {
758 let lhs = num::Saturating(lhs);
759 let rhs = num::Saturating(rhs);
760 let num::Saturating(val) = lhs - rhs;
761
762 resolve_saturation_right(val, params)
763 }
764
765 fn mul<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
766 lhs: T,
767 rhs: T,
768 params: OpBehaviorParams<T>,
769 ) -> T
770 where
771 T: Mul<Output = T>,
772 T::Output: Eq + Ord + Into<T>,
773 num::Saturating<T>: Mul<Output = num::Saturating<T>>,
774 <num::Saturating<T> as Mul>::Output: Eq + Ord + Into<num::Saturating<T>>,
775 {
776 let lhs = num::Saturating(lhs);
777 let rhs = num::Saturating(rhs);
778 let num::Saturating(val) = lhs * rhs;
779
780 resolve_saturation_left(val, params)
781 }
782
783 fn div<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
784 lhs: T,
785 rhs: T,
786 params: OpBehaviorParams<T>,
787 ) -> T
788 where
789 T: Div<Output = T>,
790 T::Output: Eq + Ord + Into<T>,
791 num::Saturating<T>: Div<Output = num::Saturating<T>>,
792 <num::Saturating<T> as Div>::Output: Eq + Ord + Into<num::Saturating<T>>,
793 {
794 let lhs = num::Saturating(lhs);
795 let rhs = num::Saturating(rhs);
796 let num::Saturating(val) = lhs / rhs;
797
798 resolve_saturation_right(val, params)
799 }
800
801 fn rem<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
802 lhs: T,
803 rhs: T,
804 params: OpBehaviorParams<T>,
805 ) -> T
806 where
807 T: Rem<Output = T> + Sub<Output = T>,
808 <T as Rem>::Output: Eq + Ord + Into<T>,
809 <T as Sub>::Output: Eq + Ord + Into<T>,
810 num::Saturating<T>: Rem<Output = num::Saturating<T>>,
811 <num::Saturating<T> as Rem>::Output: Eq + Ord + Into<num::Saturating<T>>,
812 {
813 let lhs = num::Saturating(lhs);
814 let rhs = num::Saturating(rhs);
815 let num::Saturating(val) = lhs % rhs;
816
817 resolve_saturation_nearest(val, params)
818 }
819
820 fn bitand<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
821 lhs: T,
822 rhs: T,
823 params: OpBehaviorParams<T>,
824 ) -> T
825 where
826 T: BitAnd<Output = T> + Sub<Output = T>,
827 <T as BitAnd>::Output: Eq + Ord + Into<T>,
828 <T as Sub>::Output: Eq + Ord + Into<T>,
829 num::Saturating<T>: BitAnd<Output = num::Saturating<T>>,
830 <num::Saturating<T> as BitAnd>::Output: Eq + Ord + Into<num::Saturating<T>>,
831 {
832 let lhs = num::Saturating(lhs);
833 let rhs = num::Saturating(rhs);
834 let num::Saturating(val) = lhs & rhs;
835
836 resolve_saturation_nearest(val, params)
837 }
838
839 fn bitor<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
840 lhs: T,
841 rhs: T,
842 params: OpBehaviorParams<T>,
843 ) -> T
844 where
845 T: BitOr<Output = T> + Sub<Output = T>,
846 <T as BitOr>::Output: Eq + Ord + Into<T>,
847 <T as Sub>::Output: Eq + Ord + Into<T>,
848 num::Saturating<T>: BitOr<Output = num::Saturating<T>>,
849 <num::Saturating<T> as BitOr>::Output: Eq + Ord + Into<num::Saturating<T>>,
850 {
851 let lhs = num::Saturating(lhs);
852 let rhs = num::Saturating(rhs);
853 let num::Saturating(val) = lhs | rhs;
854
855 resolve_saturation_nearest(val, params)
856 }
857
858 fn bitxor<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
859 lhs: T,
860 rhs: T,
861 params: OpBehaviorParams<T>,
862 ) -> T
863 where
864 T: BitXor<Output = T> + Sub<Output = T>,
865 <T as BitXor>::Output: Eq + Ord + Into<T>,
866 <T as Sub>::Output: Eq + Ord + Into<T>,
867 num::Saturating<T>: BitXor<Output = num::Saturating<T>>,
868 <num::Saturating<T> as BitXor>::Output: Eq + Ord + Into<num::Saturating<T>>,
869 {
870 let lhs = num::Saturating(lhs);
871 let rhs = num::Saturating(rhs);
872 let num::Saturating(val) = lhs ^ rhs;
873
874 resolve_saturation_nearest(val, params)
875 }
876
877 fn neg<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
878 val: T,
879 params: OpBehaviorParams<T>,
880 ) -> T
881 where
882 T: Neg<Output = T> + Sub<Output = T>,
883 <T as Neg>::Output: Eq + Ord + Into<T>,
884 <T as Sub>::Output: Eq + Ord + Into<T>,
885 num::Saturating<T>: Neg<Output = num::Saturating<T>>,
886 <num::Saturating<T> as Neg>::Output: Eq + Ord + Into<num::Saturating<T>>,
887 {
888 let val = num::Saturating(val);
889 let num::Saturating(val) = -val;
890
891 if <T as InherentLimits<T>>::is_zero(&val) {
892 resolve_saturation_nearest(val, params)
893 } else if <T as InherentLimits<T>>::is_negative(&val) {
894 resolve_saturation_right(val, params)
895 } else {
896 resolve_saturation_left(val, params)
897 }
898 }
899
900 fn not<T: 'static + Copy + Eq + Ord + InherentLimits<T>>(
901 val: T,
902 params: OpBehaviorParams<T>,
903 ) -> T
904 where
905 T: Not<Output = T> + Sub<Output = T>,
906 <T as Not>::Output: Eq + Ord + Into<T>,
907 <T as Sub>::Output: Eq + Ord + Into<T>,
908 num::Saturating<T>: Not<Output = num::Saturating<T>>,
909 <num::Saturating<T> as Not>::Output: Eq + Ord + Into<num::Saturating<T>>,
910 {
911 let val = num::Saturating(val);
912 let num::Saturating(val) = !val;
913
914 if <T as InherentLimits<T>>::is_zero(&val) {
915 resolve_saturation_nearest(val, params)
916 } else if <T as InherentLimits<T>>::is_negative(&val) {
917 resolve_saturation_right(val, params)
918 } else {
919 resolve_saturation_left(val, params)
920 }
921 }
922}