Skip to main content

fixed_bigint/fixeduint/
multiple_impl.rs

1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Multiple-of operations for FixedUInt.
16
17use super::{FixedUInt, MachineWord};
18use crate::const_numtraits::{ConstCheckedAdd, ConstMultiple, ConstZero};
19use crate::machineword::ConstMachineWord;
20
21c0nst::c0nst! {
22    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstMultiple for FixedUInt<T, N> {
23        fn is_multiple_of(&self, rhs: &Self) -> bool {
24            if rhs.is_zero() {
25                false
26            } else {
27                (*self % *rhs).is_zero()
28            }
29        }
30
31        fn next_multiple_of(self, rhs: Self) -> Self {
32            match self.checked_next_multiple_of(rhs) {
33                Some(v) => v,
34                None => panic!("next_multiple_of: rhs is zero or result overflows"),
35            }
36        }
37
38        fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
39            if rhs.is_zero() {
40                return None;
41            }
42            let rem = self % rhs;
43            if rem.is_zero() {
44                Some(self)
45            } else {
46                // self + (rhs - rem)
47                let add = rhs - rem;
48                ConstCheckedAdd::checked_add(&self, &add)
49            }
50        }
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn test_is_multiple_of() {
60        type U16 = FixedUInt<u8, 2>;
61
62        assert!(ConstMultiple::is_multiple_of(
63            &U16::from(0u8),
64            &U16::from(5u8)
65        ));
66        assert!(ConstMultiple::is_multiple_of(
67            &U16::from(10u8),
68            &U16::from(5u8)
69        ));
70        assert!(ConstMultiple::is_multiple_of(
71            &U16::from(15u8),
72            &U16::from(5u8)
73        ));
74        assert!(!ConstMultiple::is_multiple_of(
75            &U16::from(11u8),
76            &U16::from(5u8)
77        ));
78        assert!(ConstMultiple::is_multiple_of(
79            &U16::from(100u8),
80            &U16::from(10u8)
81        ));
82        assert!(!ConstMultiple::is_multiple_of(
83            &U16::from(101u8),
84            &U16::from(10u8)
85        ));
86
87        // rhs == 0 returns false
88        assert!(!ConstMultiple::is_multiple_of(
89            &U16::from(10u8),
90            &U16::from(0u8)
91        ));
92    }
93
94    #[test]
95    fn test_next_multiple_of() {
96        type U16 = FixedUInt<u8, 2>;
97
98        // Already a multiple
99        assert_eq!(
100            ConstMultiple::next_multiple_of(U16::from(10u8), U16::from(5u8)),
101            U16::from(10u8)
102        );
103        assert_eq!(
104            ConstMultiple::next_multiple_of(U16::from(0u8), U16::from(5u8)),
105            U16::from(0u8)
106        );
107
108        // Not a multiple
109        assert_eq!(
110            ConstMultiple::next_multiple_of(U16::from(11u8), U16::from(5u8)),
111            U16::from(15u8)
112        );
113        assert_eq!(
114            ConstMultiple::next_multiple_of(U16::from(12u8), U16::from(5u8)),
115            U16::from(15u8)
116        );
117        assert_eq!(
118            ConstMultiple::next_multiple_of(U16::from(14u8), U16::from(5u8)),
119            U16::from(15u8)
120        );
121
122        // Larger values
123        assert_eq!(
124            ConstMultiple::next_multiple_of(U16::from(101u8), U16::from(10u8)),
125            U16::from(110u8)
126        );
127    }
128
129    #[test]
130    fn test_checked_next_multiple_of() {
131        type U16 = FixedUInt<u8, 2>;
132
133        // Normal cases
134        assert_eq!(
135            ConstMultiple::checked_next_multiple_of(U16::from(11u8), U16::from(5u8)),
136            Some(U16::from(15u8))
137        );
138
139        // rhs == 0
140        assert_eq!(
141            ConstMultiple::checked_next_multiple_of(U16::from(10u8), U16::from(0u8)),
142            None
143        );
144
145        // Already a multiple (no overflow)
146        let large = U16::from(65530u16);
147        assert_eq!(
148            ConstMultiple::checked_next_multiple_of(large, U16::from(10u8)),
149            Some(large)
150        ); // 65530 % 10 = 0, so returns itself
151
152        // Overflow case
153        let large2 = U16::from(65531u16);
154        assert_eq!(
155            ConstMultiple::checked_next_multiple_of(large2, U16::from(10u8)),
156            None
157        ); // 65531 + 9 = 65540 > 65535, overflow
158    }
159
160    c0nst::c0nst! {
161        pub c0nst fn const_is_multiple_of<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
162            a: &FixedUInt<T, N>,
163            b: &FixedUInt<T, N>,
164        ) -> bool {
165            ConstMultiple::is_multiple_of(a, b)
166        }
167
168        pub c0nst fn const_next_multiple_of<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
169            a: FixedUInt<T, N>,
170            b: FixedUInt<T, N>,
171        ) -> FixedUInt<T, N> {
172            ConstMultiple::next_multiple_of(a, b)
173        }
174    }
175
176    #[test]
177    fn test_const_multiple() {
178        type U16 = FixedUInt<u8, 2>;
179
180        assert!(const_is_multiple_of(&U16::from(10u8), &U16::from(5u8)));
181        assert_eq!(
182            const_next_multiple_of(U16::from(11u8), U16::from(5u8)),
183            U16::from(15u8)
184        );
185
186        #[cfg(feature = "nightly")]
187        {
188            const TEN: U16 = FixedUInt { array: [10, 0] };
189            const FIVE: U16 = FixedUInt { array: [5, 0] };
190            const IS_MULT: bool = const_is_multiple_of(&TEN, &FIVE);
191            assert!(IS_MULT);
192
193            const ELEVEN: U16 = FixedUInt { array: [11, 0] };
194            const NEXT: U16 = const_next_multiple_of(ELEVEN, FIVE);
195            assert_eq!(NEXT, FixedUInt { array: [15, 0] });
196        }
197    }
198}