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