checked_rs/
clamp.rs

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
90/// # Invariants
91/// - `VALUES` must be sorted in ascending order
92pub 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
102/// # Invariants
103/// - `VALID_RANGES` must be sorted in ascending order
104pub 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            // val is in the middle of two exact values
354            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            // val is in the middle of two exact values
372            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            // val is in the middle of two exact values
390            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            // val is in the middle of two ranges
415            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            // val is in the middle of two ranges
433            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            // val is in the middle of two ranges
451            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}