1use super::{FixedUInt, MachineWord};
24use crate::machineword::ConstMachineWord;
25use const_num_traits::Nct;
26use const_num_traits::{
27 CheckedPow, OverflowingAdd, OverflowingMul, OverflowingSub, StrictAdd, StrictDiv, StrictMul,
28 StrictPow, StrictRem, StrictShl, StrictShr, StrictSub,
29};
30
31c0nst::c0nst! {
32 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictAdd for FixedUInt<T, N, Nct> {
33 type Output = FixedUInt<T, N, Nct>;
34 fn strict_add(self, v: Self) -> Self {
35 let (res, overflow) = <Self as OverflowingAdd>::overflowing_add(self, v);
36 if overflow {
37 panic!("FixedUInt: strict_add overflowed");
38 }
39 res
40 }
41 }
42
43 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictSub for FixedUInt<T, N, Nct> {
44 type Output = FixedUInt<T, N, Nct>;
45 fn strict_sub(self, v: Self) -> Self {
46 let (res, overflow) = <Self as OverflowingSub>::overflowing_sub(self, v);
47 if overflow {
48 panic!("FixedUInt: strict_sub underflowed");
49 }
50 res
51 }
52 }
53
54 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictMul for FixedUInt<T, N, Nct> {
55 type Output = FixedUInt<T, N, Nct>;
56 fn strict_mul(self, v: Self) -> Self {
57 let (res, overflow) = <Self as OverflowingMul>::overflowing_mul(self, v);
58 if overflow {
59 panic!("FixedUInt: strict_mul overflowed");
60 }
61 res
62 }
63 }
64
65 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictDiv for FixedUInt<T, N, Nct> {
66 type Output = FixedUInt<T, N, Nct>;
67 fn strict_div(self, v: Self) -> Self {
68 self / v
71 }
72 }
73
74 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictRem for FixedUInt<T, N, Nct> {
75 type Output = FixedUInt<T, N, Nct>;
76 fn strict_rem(self, v: Self) -> Self {
77 self % v
78 }
79 }
80
81 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictShl for FixedUInt<T, N, Nct> {
82 type Output = FixedUInt<T, N, Nct>;
83 fn strict_shl(self, rhs: u32) -> Self {
84 let shift = rhs as usize;
85 if shift >= Self::BIT_SIZE {
86 panic!("FixedUInt: strict_shl shift exceeds bit width");
87 }
88 self << shift
89 }
90 }
91
92 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictShr for FixedUInt<T, N, Nct> {
93 type Output = FixedUInt<T, N, Nct>;
94 fn strict_shr(self, rhs: u32) -> Self {
95 let shift = rhs as usize;
96 if shift >= Self::BIT_SIZE {
97 panic!("FixedUInt: strict_shr shift exceeds bit width");
98 }
99 self >> shift
100 }
101 }
102
103 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictPow for FixedUInt<T, N, Nct> {
104 type Output = FixedUInt<T, N, Nct>;
105 fn strict_pow(self, exp: u32) -> Self {
106 match <Self as CheckedPow>::checked_pow(self, exp) {
107 Some(v) => v,
108 None => panic!("FixedUInt: strict_pow overflowed"),
109 }
110 }
111 }
112
113 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictAdd for &FixedUInt<T, N, Nct> {
116 type Output = FixedUInt<T, N, Nct>;
117 fn strict_add(self, v: Self) -> FixedUInt<T, N, Nct> {
118 <FixedUInt<T, N, Nct> as StrictAdd>::strict_add(FixedUInt::from_array(self.array), FixedUInt::from_array(v.array))
119 }
120 }
121
122 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictSub for &FixedUInt<T, N, Nct> {
123 type Output = FixedUInt<T, N, Nct>;
124 fn strict_sub(self, v: Self) -> FixedUInt<T, N, Nct> {
125 <FixedUInt<T, N, Nct> as StrictSub>::strict_sub(FixedUInt::from_array(self.array), FixedUInt::from_array(v.array))
126 }
127 }
128
129 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictMul for &FixedUInt<T, N, Nct> {
130 type Output = FixedUInt<T, N, Nct>;
131 fn strict_mul(self, v: Self) -> FixedUInt<T, N, Nct> {
132 <FixedUInt<T, N, Nct> as StrictMul>::strict_mul(FixedUInt::from_array(self.array), FixedUInt::from_array(v.array))
133 }
134 }
135
136 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictDiv for &FixedUInt<T, N, Nct> {
137 type Output = FixedUInt<T, N, Nct>;
138 fn strict_div(self, v: Self) -> FixedUInt<T, N, Nct> {
139 <FixedUInt<T, N, Nct> as StrictDiv>::strict_div(FixedUInt::from_array(self.array), FixedUInt::from_array(v.array))
140 }
141 }
142
143 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictRem for &FixedUInt<T, N, Nct> {
144 type Output = FixedUInt<T, N, Nct>;
145 fn strict_rem(self, v: Self) -> FixedUInt<T, N, Nct> {
146 <FixedUInt<T, N, Nct> as StrictRem>::strict_rem(FixedUInt::from_array(self.array), FixedUInt::from_array(v.array))
147 }
148 }
149
150 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictShl for &FixedUInt<T, N, Nct> {
151 type Output = FixedUInt<T, N, Nct>;
152 fn strict_shl(self, rhs: u32) -> FixedUInt<T, N, Nct> {
153 <FixedUInt<T, N, Nct> as StrictShl>::strict_shl(FixedUInt::from_array(self.array), rhs)
154 }
155 }
156
157 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictShr for &FixedUInt<T, N, Nct> {
158 type Output = FixedUInt<T, N, Nct>;
159 fn strict_shr(self, rhs: u32) -> FixedUInt<T, N, Nct> {
160 <FixedUInt<T, N, Nct> as StrictShr>::strict_shr(FixedUInt::from_array(self.array), rhs)
161 }
162 }
163
164 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> StrictPow for &FixedUInt<T, N, Nct> {
165 type Output = FixedUInt<T, N, Nct>;
166 fn strict_pow(self, exp: u32) -> FixedUInt<T, N, Nct> {
167 <FixedUInt<T, N, Nct> as StrictPow>::strict_pow(FixedUInt::from_array(self.array), exp)
168 }
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 type U16 = FixedUInt<u8, 2, Nct>;
177
178 #[test]
179 fn strict_add_ok() {
180 assert_eq!(
181 StrictAdd::strict_add(U16::from(10u8), U16::from(20u8)),
182 U16::from(30u8)
183 );
184 }
185
186 #[test]
187 #[should_panic(expected = "strict_add overflowed")]
188 fn strict_add_overflows() {
189 let _ = StrictAdd::strict_add(U16::from(0xFFFFu16), U16::from(1u8));
190 }
191
192 #[test]
193 fn strict_sub_ok() {
194 assert_eq!(
195 StrictSub::strict_sub(U16::from(30u8), U16::from(10u8)),
196 U16::from(20u8)
197 );
198 }
199
200 #[test]
201 #[should_panic(expected = "strict_sub underflowed")]
202 fn strict_sub_underflows() {
203 let _ = StrictSub::strict_sub(U16::from(0u8), U16::from(1u8));
204 }
205
206 #[test]
207 fn strict_mul_ok() {
208 assert_eq!(
209 StrictMul::strict_mul(U16::from(7u8), U16::from(13u8)),
210 U16::from(91u8)
211 );
212 }
213
214 #[test]
215 #[should_panic(expected = "strict_mul overflowed")]
216 fn strict_mul_overflows() {
217 let _ = StrictMul::strict_mul(U16::from(0x1000u16), U16::from(0x1000u16));
218 }
219
220 #[test]
221 fn strict_shl_ok() {
222 assert_eq!(StrictShl::strict_shl(U16::from(1u8), 8), U16::from(256u16));
223 }
224
225 #[test]
226 #[should_panic(expected = "strict_shl shift exceeds bit width")]
227 fn strict_shl_too_wide() {
228 let _ = StrictShl::strict_shl(U16::from(1u8), 16);
229 }
230
231 #[test]
232 fn strict_shr_ok() {
233 assert_eq!(StrictShr::strict_shr(U16::from(256u16), 4), U16::from(16u8));
234 }
235
236 #[test]
237 #[should_panic(expected = "strict_shr shift exceeds bit width")]
238 fn strict_shr_too_wide() {
239 let _ = StrictShr::strict_shr(U16::from(1u8), 16);
240 }
241
242 #[test]
243 fn strict_div_ok() {
244 assert_eq!(
245 StrictDiv::strict_div(U16::from(100u8), U16::from(10u8)),
246 U16::from(10u8)
247 );
248 }
249
250 #[test]
251 fn strict_rem_ok() {
252 assert_eq!(
253 StrictRem::strict_rem(U16::from(100u8), U16::from(7u8)),
254 U16::from(2u8)
255 );
256 }
257
258 #[test]
259 fn strict_pow_ok() {
260 assert_eq!(StrictPow::strict_pow(U16::from(2u8), 8), U16::from(256u16));
261 }
262
263 #[test]
264 #[should_panic(expected = "strict_pow overflowed")]
265 fn strict_pow_overflows() {
266 let _ = StrictPow::strict_pow(U16::from(2u8), 16);
267 }
268
269 #[test]
270 fn strict_ref() {
271 let a = U16::from(10u8);
272 let b = U16::from(20u8);
273 assert_eq!(StrictAdd::strict_add(&a, &b), U16::from(30u8));
274 }
275
276 c0nst::c0nst! {
278 pub c0nst fn const_strict_add<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(a: FixedUInt<T, N, Nct>, b: FixedUInt<T, N, Nct>) -> FixedUInt<T, N, Nct> {
279 StrictAdd::strict_add(a, b)
280 }
281 pub c0nst fn const_strict_sub<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(a: FixedUInt<T, N, Nct>, b: FixedUInt<T, N, Nct>) -> FixedUInt<T, N, Nct> {
282 StrictSub::strict_sub(a, b)
283 }
284 pub c0nst fn const_strict_mul<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(a: FixedUInt<T, N, Nct>, b: FixedUInt<T, N, Nct>) -> FixedUInt<T, N, Nct> {
285 StrictMul::strict_mul(a, b)
286 }
287 pub c0nst fn const_strict_div<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(a: FixedUInt<T, N, Nct>, b: FixedUInt<T, N, Nct>) -> FixedUInt<T, N, Nct> {
288 StrictDiv::strict_div(a, b)
289 }
290 pub c0nst fn const_strict_rem<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(a: FixedUInt<T, N, Nct>, b: FixedUInt<T, N, Nct>) -> FixedUInt<T, N, Nct> {
291 StrictRem::strict_rem(a, b)
292 }
293 pub c0nst fn const_strict_shl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(a: FixedUInt<T, N, Nct>, rhs: u32) -> FixedUInt<T, N, Nct> {
294 StrictShl::strict_shl(a, rhs)
295 }
296 pub c0nst fn const_strict_shr<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(a: FixedUInt<T, N, Nct>, rhs: u32) -> FixedUInt<T, N, Nct> {
297 StrictShr::strict_shr(a, rhs)
298 }
299 pub c0nst fn const_strict_pow<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(a: FixedUInt<T, N, Nct>, exp: u32) -> FixedUInt<T, N, Nct> {
300 StrictPow::strict_pow(a, exp)
301 }
302 }
303
304 #[test]
305 fn nightly_const_eval_strict() {
306 assert_eq!(
307 const_strict_add(U16::from(10u8), U16::from(20u8)),
308 U16::from(30u8)
309 );
310 assert_eq!(
311 const_strict_mul(U16::from(6u8), U16::from(7u8)),
312 U16::from(42u8)
313 );
314 assert_eq!(const_strict_shl(U16::from(1u8), 4), U16::from(16u8));
315 assert_eq!(const_strict_pow(U16::from(2u8), 8), U16::from(256u16));
316
317 #[cfg(feature = "nightly")]
318 {
319 const A: U16 = FixedUInt::from_array([10, 0]);
320 const B: U16 = FixedUInt::from_array([20, 0]);
321 const TWO: U16 = FixedUInt::from_array([2, 0]);
322 const THIRTY: U16 = FixedUInt::from_array([30, 0]);
323 const TEN: U16 = FixedUInt::from_array([10, 0]);
324 const TWO_HUNDRED: U16 = FixedUInt::from_array([200, 0]);
325 const SIXTEEN: U16 = FixedUInt::from_array([16, 0]);
326 const TWO_FIFTY_SIX: U16 = FixedUInt::from_array([0, 1]);
327
328 const ADD: U16 = const_strict_add(A, B);
329 const SUB: U16 = const_strict_sub(THIRTY, A);
330 const MUL: U16 = const_strict_mul(TEN, TWO);
331 const DIV: U16 = const_strict_div(TWO_HUNDRED, TEN);
332 const REM: U16 = const_strict_rem(TWO_HUNDRED, FixedUInt::from_array([7, 0]));
333 const SHL: U16 = const_strict_shl(TWO, 3);
334 const SHR: U16 = const_strict_shr(SIXTEEN, 2);
335 const POW: U16 = const_strict_pow(TWO, 8);
336
337 assert_eq!(ADD, FixedUInt::from_array([30, 0]));
338 assert_eq!(SUB, FixedUInt::from_array([20, 0]));
339 assert_eq!(MUL, FixedUInt::from_array([20, 0]));
340 assert_eq!(DIV, FixedUInt::from_array([20, 0]));
341 assert_eq!(REM, FixedUInt::from_array([4, 0]));
342 assert_eq!(SHL, FixedUInt::from_array([16, 0]));
343 assert_eq!(SHR, FixedUInt::from_array([4, 0]));
344 assert_eq!(POW, TWO_FIFTY_SIX);
345 }
346 }
347}