• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kaidokert / fixed-bigint-rs / 22010898048

14 Feb 2026 04:09AM UTC coverage: 95.274% (-0.2%) from 95.434%
22010898048

push

github

web-flow
Constify bitwise ops (Not, And, Or, Xor, Shl, Shr) (#63)

* Constify bitwise ops (Not, And, Or, Xor, Shl, Shr)

Bitwise ops constified #58

47 of 49 new or added lines in 2 files covered. (95.92%)

1774 of 1862 relevant lines covered (95.27%)

1294.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.15
/src/fixeduint/bit_ops_impl.rs
1
use super::{const_shl_impl, const_shr_impl, FixedUInt, MachineWord};
2

3
use crate::const_numtrait::ConstZero;
4
use crate::machineword::ConstMachineWord;
5
use crate::patch_num_traits::{OverflowingShl, OverflowingShr};
6

7
c0nst::c0nst! {
8
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Not for FixedUInt<T, N> {
9
        type Output = Self;
10
        fn not(self) -> Self::Output {
11
            let mut ret = <Self as ConstZero>::zero();
12
            let mut i = 0;
13
            while i < N {
14
                ret.array[i] = !self.array[i];
15
                i += 1;
16
            }
17
            ret
18
        }
19
    }
20

21
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitAnd<&FixedUInt<T, N>> for &FixedUInt<T, N> {
22
        type Output = FixedUInt<T, N>;
23
        fn bitand(self, other: &FixedUInt<T, N>) -> Self::Output {
24
            let mut ret = <FixedUInt<T, N> as ConstZero>::zero();
25
            let mut i = 0;
26
            while i < N {
27
                ret.array[i] = self.array[i] & other.array[i];
28
                i += 1;
29
            }
30
            ret
31
        }
32
    }
33

34
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitAnd for FixedUInt<T, N> {
35
        type Output = Self;
36
        fn bitand(self, other: Self) -> Self::Output {
37
            (&self).bitand(&other)
38
        }
39
    }
40

41
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitAnd<&FixedUInt<T, N>> for FixedUInt<T, N> {
42
        type Output = Self;
43
        fn bitand(self, other: &FixedUInt<T, N>) -> Self::Output {
44
            (&self).bitand(other)
45
        }
46
    }
47

48
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitAnd<FixedUInt<T, N>> for &FixedUInt<T, N> {
49
        type Output = FixedUInt<T, N>;
50
        fn bitand(self, other: FixedUInt<T, N>) -> Self::Output {
51
            self.bitand(&other)
52
        }
53
    }
54

55
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitAndAssign for FixedUInt<T, N> {
56
        fn bitand_assign(&mut self, other: Self) {
57
            let mut i = 0;
58
            while i < N {
59
                self.array[i] &= other.array[i];
60
                i += 1;
61
            }
62
        }
63
    }
64

65
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitOr<&FixedUInt<T, N>> for &FixedUInt<T, N> {
66
        type Output = FixedUInt<T, N>;
67
        fn bitor(self, other: &FixedUInt<T, N>) -> Self::Output {
68
            let mut ret = <FixedUInt<T, N> as ConstZero>::zero();
69
            let mut i = 0;
70
            while i < N {
71
                ret.array[i] = self.array[i] | other.array[i];
72
                i += 1;
73
            }
74
            ret
75
        }
76
    }
77

78
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitOr for FixedUInt<T, N> {
79
        type Output = Self;
80
        fn bitor(self, other: Self) -> Self::Output {
81
            (&self).bitor(&other)
82
        }
83
    }
84

85
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitOr<&FixedUInt<T, N>> for FixedUInt<T, N> {
86
        type Output = Self;
87
        fn bitor(self, other: &FixedUInt<T, N>) -> Self::Output {
88
            (&self).bitor(other)
89
        }
90
    }
91

92
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitOr<FixedUInt<T, N>> for &FixedUInt<T, N> {
93
        type Output = FixedUInt<T, N>;
94
        fn bitor(self, other: FixedUInt<T, N>) -> Self::Output {
95
            self.bitor(&other)
96
        }
97
    }
98

99
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitOrAssign for FixedUInt<T, N> {
100
        fn bitor_assign(&mut self, other: Self) {
101
            let mut i = 0;
102
            while i < N {
103
                self.array[i] |= other.array[i];
104
                i += 1;
105
            }
106
        }
107
    }
108

109
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitXor<&FixedUInt<T, N>> for &FixedUInt<T, N> {
110
        type Output = FixedUInt<T, N>;
111
        fn bitxor(self, other: &FixedUInt<T, N>) -> Self::Output {
112
            let mut ret = <FixedUInt<T, N> as ConstZero>::zero();
113
            let mut i = 0;
114
            while i < N {
115
                ret.array[i] = self.array[i] ^ other.array[i];
116
                i += 1;
117
            }
118
            ret
119
        }
120
    }
121

122
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitXor for FixedUInt<T, N> {
123
        type Output = Self;
124
        fn bitxor(self, other: Self) -> Self::Output {
125
            (&self).bitxor(&other)
126
        }
127
    }
128

129
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitXor<&FixedUInt<T, N>> for FixedUInt<T, N> {
130
        type Output = Self;
131
        fn bitxor(self, other: &FixedUInt<T, N>) -> Self::Output {
132
            (&self).bitxor(other)
133
        }
134
    }
135

136
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitXor<FixedUInt<T, N>> for &FixedUInt<T, N> {
137
        type Output = FixedUInt<T, N>;
138
        fn bitxor(self, other: FixedUInt<T, N>) -> Self::Output {
139
            self.bitxor(&other)
140
        }
141
    }
142

143
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::BitXorAssign for FixedUInt<T, N> {
144
        fn bitxor_assign(&mut self, other: Self) {
145
            let mut i = 0;
146
            while i < N {
147
                self.array[i] ^= other.array[i];
148
                i += 1;
149
            }
150
        }
151
    }
152

153
    // Primary Shl/Shr implementations
154
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shl<usize> for FixedUInt<T, N> {
155
        type Output = Self;
156
        fn shl(self, bits: usize) -> Self::Output {
157
            let mut result = self;
158
            const_shl_impl(&mut result, bits);
159
            result
160
        }
161
    }
162

163
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shr<usize> for FixedUInt<T, N> {
164
        type Output = Self;
165
        fn shr(self, bits: usize) -> Self::Output {
166
            let mut result = self;
167
            const_shr_impl(&mut result, bits);
168
            result
169
        }
170
    }
171

172
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shl<u32> for FixedUInt<T, N> {
173
        type Output = Self;
174
        fn shl(self, bits: u32) -> Self::Output {
175
            self.shl(bits as usize)
176
        }
177
    }
178

179
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shr<u32> for FixedUInt<T, N> {
180
        type Output = Self;
181
        fn shr(self, bits: u32) -> Self::Output {
182
            self.shr(bits as usize)
183
        }
184
    }
185

186
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shl<&usize> for FixedUInt<T, N> {
187
        type Output = Self;
188
        fn shl(self, bits: &usize) -> Self::Output {
189
            self.shl(*bits)
190
        }
191
    }
192

193
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shr<&usize> for FixedUInt<T, N> {
194
        type Output = Self;
195
        fn shr(self, bits: &usize) -> Self::Output {
196
            self.shr(*bits)
197
        }
198
    }
199

200
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shl<&u32> for FixedUInt<T, N> {
201
        type Output = Self;
202
        fn shl(self, bits: &u32) -> Self::Output {
203
            self.shl(*bits as usize)
204
        }
205
    }
206

207
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shr<&u32> for FixedUInt<T, N> {
208
        type Output = Self;
209
        fn shr(self, bits: &u32) -> Self::Output {
210
            self.shr(*bits as usize)
211
        }
212
    }
213

214
    // Shl/Shr for &FixedUInt
215
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shl<usize> for &FixedUInt<T, N> {
216
        type Output = FixedUInt<T, N>;
217
        fn shl(self, bits: usize) -> Self::Output {
218
            (*self).shl(bits)
219
        }
220
    }
221

222
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shr<usize> for &FixedUInt<T, N> {
223
        type Output = FixedUInt<T, N>;
224
        fn shr(self, bits: usize) -> Self::Output {
225
            (*self).shr(bits)
226
        }
227
    }
228

229
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shl<u32> for &FixedUInt<T, N> {
230
        type Output = FixedUInt<T, N>;
231
        fn shl(self, bits: u32) -> Self::Output {
232
            (*self).shl(bits as usize)
233
        }
234
    }
235

236
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shr<u32> for &FixedUInt<T, N> {
237
        type Output = FixedUInt<T, N>;
238
        fn shr(self, bits: u32) -> Self::Output {
239
            (*self).shr(bits as usize)
240
        }
241
    }
242

243
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shl<&usize> for &FixedUInt<T, N> {
244
        type Output = FixedUInt<T, N>;
245
        fn shl(self, bits: &usize) -> Self::Output {
246
            (*self).shl(*bits)
247
        }
248
    }
249

250
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shr<&usize> for &FixedUInt<T, N> {
251
        type Output = FixedUInt<T, N>;
252
        fn shr(self, bits: &usize) -> Self::Output {
253
            (*self).shr(*bits)
254
        }
255
    }
256

257
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shl<&u32> for &FixedUInt<T, N> {
258
        type Output = FixedUInt<T, N>;
259
        fn shl(self, bits: &u32) -> Self::Output {
260
            (*self).shl(*bits as usize)
261
        }
262
    }
263

264
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Shr<&u32> for &FixedUInt<T, N> {
265
        type Output = FixedUInt<T, N>;
266
        fn shr(self, bits: &u32) -> Self::Output {
267
            (*self).shr(*bits as usize)
268
        }
269
    }
270

271
    // ShlAssign/ShrAssign
272
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::ShlAssign<usize> for FixedUInt<T, N> {
273
        fn shl_assign(&mut self, bits: usize) {
274
            const_shl_impl(self, bits);
275
        }
276
    }
277

278
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::ShrAssign<usize> for FixedUInt<T, N> {
279
        fn shr_assign(&mut self, bits: usize) {
280
            const_shr_impl(self, bits);
281
        }
282
    }
283

284
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::ShlAssign<&usize> for FixedUInt<T, N> {
285
        fn shl_assign(&mut self, bits: &usize) {
286
            const_shl_impl(self, *bits);
287
        }
288
    }
289

290
    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::ShrAssign<&usize> for FixedUInt<T, N> {
291
        fn shr_assign(&mut self, bits: &usize) {
292
            const_shr_impl(self, *bits);
293
        }
294
    }
295
}
2,516✔
296

297
// OverflowingShl/Shr from patch_num_traits (not core::ops)
298
impl<T: MachineWord, const N: usize> OverflowingShl for FixedUInt<T, N> {
299
    fn overflowing_shl(self, bits: u32) -> (Self, bool) {
72✔
300
        let bitsu = bits as usize;
72✔
301
        let (shift, overflow) = if bitsu >= Self::BIT_SIZE {
72✔
302
            // Use modulo for correct wrapping with non-power-of-2 bit sizes
303
            let shift = if Self::BIT_SIZE == 0 {
36✔
NEW
304
                0
×
305
            } else {
306
                bitsu % Self::BIT_SIZE
36✔
307
            };
308
            (shift, true)
36✔
309
        } else {
310
            (bitsu, false)
36✔
311
        };
312
        let res = core::ops::Shl::<usize>::shl(self, shift);
72✔
313
        (res, overflow)
72✔
314
    }
72✔
315
}
316

317
impl<T: MachineWord, const N: usize> OverflowingShr for FixedUInt<T, N> {
318
    fn overflowing_shr(self, bits: u32) -> (Self, bool) {
72✔
319
        let bitsu = bits as usize;
72✔
320
        let (shift, overflow) = if bitsu >= Self::BIT_SIZE {
72✔
321
            // Use modulo for correct wrapping with non-power-of-2 bit sizes
322
            let shift = if Self::BIT_SIZE == 0 {
36✔
NEW
323
                0
×
324
            } else {
325
                bitsu % Self::BIT_SIZE
36✔
326
            };
327
            (shift, true)
36✔
328
        } else {
329
            (bitsu, false)
36✔
330
        };
331
        let res = core::ops::Shr::<usize>::shr(self, shift);
72✔
332
        (res, overflow)
72✔
333
    }
72✔
334
}
335

336
// num_traits wrappers
337
impl<T: MachineWord, const N: usize> num_traits::WrappingShl for FixedUInt<T, N> {
338
    fn wrapping_shl(&self, bits: u32) -> Self {
24✔
339
        self.overflowing_shl(bits).0
24✔
340
    }
24✔
341
}
342

343
impl<T: MachineWord, const N: usize> num_traits::WrappingShr for FixedUInt<T, N> {
344
    fn wrapping_shr(&self, bits: u32) -> Self {
24✔
345
        self.overflowing_shr(bits).0
24✔
346
    }
24✔
347
}
348

349
impl<T: MachineWord, const N: usize> num_traits::CheckedShl for FixedUInt<T, N> {
350
    fn checked_shl(&self, bits: u32) -> Option<Self> {
24✔
351
        let res = self.overflowing_shl(bits);
24✔
352
        if res.1 {
24✔
353
            None
12✔
354
        } else {
355
            Some(res.0)
12✔
356
        }
357
    }
24✔
358
}
359

360
impl<T: MachineWord, const N: usize> num_traits::CheckedShr for FixedUInt<T, N> {
361
    fn checked_shr(&self, bits: u32) -> Option<Self> {
24✔
362
        let res = self.overflowing_shr(bits);
24✔
363
        if res.1 {
24✔
364
            None
12✔
365
        } else {
366
            Some(res.0)
12✔
367
        }
368
    }
24✔
369
}
370

371
#[cfg(test)]
372
mod tests {
373
    use super::*;
374

375
    #[test]
376
    fn test_bitand_combinations() {
1✔
377
        let a = FixedUInt::<u8, 2>::from(12u8); // 1100
1✔
378
        let b = FixedUInt::<u8, 2>::from(10u8); // 1010
1✔
379
        let expected = FixedUInt::<u8, 2>::from(8u8); // 1000
1✔
380

381
        // value & value
382
        assert_eq!(a & b, expected);
1✔
383
        // value & ref
384
        assert_eq!(a & &b, expected);
1✔
385
        // ref & value
386
        assert_eq!(&a & b, expected);
1✔
387
        // ref & ref
388
        assert_eq!(&a & &b, expected);
1✔
389
    }
1✔
390

391
    #[test]
392
    fn test_bitor_combinations() {
1✔
393
        let a = FixedUInt::<u8, 2>::from(12u8); // 1100
1✔
394
        let b = FixedUInt::<u8, 2>::from(10u8); // 1010
1✔
395
        let expected = FixedUInt::<u8, 2>::from(14u8); // 1110
1✔
396

397
        // value | value
398
        assert_eq!(a | b, expected);
1✔
399
        // value | ref
400
        assert_eq!(a | &b, expected);
1✔
401
        // ref | value
402
        assert_eq!(&a | b, expected);
1✔
403
        // ref | ref
404
        assert_eq!(&a | &b, expected);
1✔
405
    }
1✔
406

407
    #[test]
408
    fn test_bitxor_combinations() {
1✔
409
        let a = FixedUInt::<u8, 2>::from(12u8); // 1100
1✔
410
        let b = FixedUInt::<u8, 2>::from(10u8); // 1010
1✔
411
        let expected = FixedUInt::<u8, 2>::from(6u8); // 0110
1✔
412

413
        // value ^ value
414
        assert_eq!(a ^ b, expected);
1✔
415
        // value ^ ref
416
        assert_eq!(a ^ &b, expected);
1✔
417
        // ref ^ value
418
        assert_eq!(&a ^ b, expected);
1✔
419
        // ref ^ ref
420
        assert_eq!(&a ^ &b, expected);
1✔
421
    }
1✔
422

423
    #[test]
424
    fn test_shl_combinations() {
1✔
425
        let a = FixedUInt::<u8, 2>::from(2u8); // 0010
1✔
426
        let shift: usize = 2;
1✔
427
        let expected = FixedUInt::<u8, 2>::from(8u8); // 1000
1✔
428

429
        // value << value
430
        assert_eq!(a << shift, expected);
1✔
431
        // value << ref
432
        assert_eq!(a << &shift, expected);
1✔
433
        // ref << value
434
        assert_eq!(&a << shift, expected);
1✔
435
        // ref << ref
436
        assert_eq!(&a << &shift, expected);
1✔
437

438
        // Same with u32
439
        let shift32: u32 = 2;
1✔
440
        assert_eq!(a << shift32, expected);
1✔
441
        assert_eq!(a << &shift32, expected);
1✔
442
        assert_eq!(&a << shift32, expected);
1✔
443
        assert_eq!(&a << &shift32, expected);
1✔
444
    }
1✔
445

446
    #[test]
447
    fn test_shr_combinations() {
1✔
448
        let a = FixedUInt::<u8, 2>::from(8u8); // 1000
1✔
449
        let shift: usize = 2;
1✔
450
        let expected = FixedUInt::<u8, 2>::from(2u8); // 0010
1✔
451

452
        // value >> value
453
        assert_eq!(a >> shift, expected);
1✔
454
        // value >> ref
455
        assert_eq!(a >> &shift, expected);
1✔
456
        // ref >> value
457
        assert_eq!(&a >> shift, expected);
1✔
458
        // ref >> ref
459
        assert_eq!(&a >> &shift, expected);
1✔
460

461
        // Same with u32
462
        let shift32: u32 = 2;
1✔
463
        assert_eq!(a >> shift32, expected);
1✔
464
        assert_eq!(a >> &shift32, expected);
1✔
465
        assert_eq!(&a >> shift32, expected);
1✔
466
        assert_eq!(&a >> &shift32, expected);
1✔
467
    }
1✔
468

469
    #[test]
470
    fn test_const_bitops() {
1✔
471
        type TestInt = FixedUInt<u8, 2>;
472

473
        let a = TestInt::from(0b11001100u8);
1✔
474
        let b = TestInt::from(0b10101010u8);
1✔
475

476
        // Test not
477
        let not_a = !a;
1✔
478
        assert_eq!(not_a.array[0], 0b00110011);
1✔
479
        assert_eq!(not_a.array[1], 0xFF);
1✔
480

481
        // Test bitand
482
        assert_eq!(a & b, TestInt::from(0b10001000u8));
1✔
483

484
        // Test bitor
485
        assert_eq!(a | b, TestInt::from(0b11101110u8));
1✔
486

487
        // Test bitxor
488
        assert_eq!(a ^ b, TestInt::from(0b01100110u8));
1✔
489

490
        // Test shl
491
        assert_eq!(TestInt::from(1u8) << 4usize, TestInt::from(16u8));
1✔
492

493
        // Test shr
494
        assert_eq!(TestInt::from(16u8) >> 2usize, TestInt::from(4u8));
1✔
495

496
        #[cfg(feature = "nightly")]
497
        {
498
            const A: TestInt = FixedUInt {
499
                array: [0b11001100, 0],
500
            };
501
            const B: TestInt = FixedUInt {
502
                array: [0b10101010, 0],
503
            };
504

505
            const NOT_A: TestInt = !A;
506
            const AND_AB: TestInt = A & B;
507
            const OR_AB: TestInt = A | B;
508
            const XOR_AB: TestInt = A ^ B;
509
            const SHL_1: TestInt = FixedUInt { array: [1u8, 0] } << 4usize;
510
            const SHR_16: TestInt = FixedUInt { array: [16u8, 0] } >> 2usize;
511

512
            assert_eq!(NOT_A.array[0], 0b00110011);
513
            assert_eq!(AND_AB.array[0], 0b10001000);
514
            assert_eq!(OR_AB.array[0], 0b11101110);
515
            assert_eq!(XOR_AB.array[0], 0b01100110);
516
            assert_eq!(SHL_1.array[0], 16);
517
            assert_eq!(SHR_16.array[0], 4);
518
        }
519
    }
1✔
520
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc