zkp_u256/traits/
binary.rs

1// TODO
2#![allow(clippy::module_name_repetitions)]
3use num_traits::PrimInt;
4use std::ops::{
5    BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, ShlAssign, Shr,
6    ShrAssign,
7};
8
9/// This is a subset of `num_traits::PrimInt`
10// TODO: Submit upstream PR
11pub trait Binary:
12    Sized
13    + Not<Output = Self>
14    + BitAnd<Output = Self>
15    + BitOr<Output = Self>
16    + BitXor<Output = Self>
17    + Shl<usize, Output = Self>
18    + Shr<usize, Output = Self>
19{
20    fn num_bits() -> usize;
21
22    // TODO: What about adding some bit get/set functions?
23    // TODO: What about adding digit/limb get/set functions?
24
25    fn bit(&self, i: usize) -> bool;
26
27    fn count_ones(&self) -> usize;
28    fn count_zeros(&self) -> usize;
29    fn leading_zeros(&self) -> usize;
30    fn trailing_zeros(&self) -> usize;
31
32    fn rotate_left(&self, n: usize) -> Self;
33    fn rotate_right(&self, n: usize) -> Self;
34
35    // TODO: Deprecate these
36    fn bits(&self) -> usize {
37        Self::num_bits() - self.leading_zeros()
38    }
39
40    /// Returns the position of the most significant set bit, if any.
41    fn most_significant_bit(&self) -> Option<usize> {
42        (Self::num_bits() - 1).checked_sub(self.leading_zeros())
43    }
44}
45
46/// Implement Binary for all primitive integers.
47impl<T: PrimInt> Binary for T {
48    #[inline(always)]
49    fn num_bits() -> usize {
50        Self::zero().count_zeros() as usize
51    }
52
53    fn bit(&self, i: usize) -> bool {
54        (*self >> i) & Self::one() == Self::one()
55    }
56
57    fn count_ones(&self) -> usize {
58        <Self as PrimInt>::count_ones(*self) as usize
59    }
60
61    fn count_zeros(&self) -> usize {
62        <Self as PrimInt>::count_zeros(*self) as usize
63    }
64
65    fn leading_zeros(&self) -> usize {
66        <Self as PrimInt>::leading_zeros(*self) as usize
67    }
68
69    fn trailing_zeros(&self) -> usize {
70        <Self as PrimInt>::trailing_zeros(*self) as usize
71    }
72
73    fn rotate_left(&self, n: usize) -> Self {
74        // Std `rotate_left` uses `u32` instead of `usize`
75        #[allow(clippy::cast_possible_truncation)]
76        <Self as PrimInt>::rotate_left(*self, n as u32)
77    }
78
79    fn rotate_right(&self, n: usize) -> Self {
80        // Std `rotate_left` uses `u32` instead of `usize`
81        #[allow(clippy::cast_possible_truncation)]
82        <Self as PrimInt>::rotate_right(*self, n as u32)
83    }
84}
85
86pub trait BinaryOps<Rhs = Self, Output = Self>:
87    Not<Output = Output>
88    + BitAnd<Rhs, Output = Output>
89    + BitOr<Rhs, Output = Output>
90    + BitXor<Rhs, Output = Output>
91{
92}
93
94pub trait BinaryAssignOps<Rhs = Self>:
95    BitAndAssign<Rhs> + BitOrAssign<Rhs> + BitXorAssign<Rhs> + ShlAssign<usize> + ShrAssign<usize>
96{
97}
98
99impl<T, Rhs> BinaryAssignOps<Rhs> for T where
100    T: BitAndAssign<Rhs>
101        + BitOrAssign<Rhs>
102        + BitXorAssign<Rhs>
103        + ShlAssign<usize>
104        + ShrAssign<usize>
105{
106}
107
108// Does not compile without lifetime annotations
109#[allow(single_use_lifetimes)]
110pub trait BinaryAssignRef: for<'r> BinaryAssignOps<&'r Self> {}
111
112// Does not compile without lifetime annotations
113#[allow(single_use_lifetimes)]
114impl<T> BinaryAssignRef for T where T: for<'r> BinaryAssignOps<&'r T> {}