ruint/
bit_arr.rs

1use crate::{ParseError, Uint};
2use core::{
3    ops::{
4        BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Index, Not, Shl, ShlAssign,
5        Shr, ShrAssign,
6    },
7    str::FromStr,
8};
9
10#[cfg(feature = "alloc")]
11#[allow(unused_imports)]
12use alloc::{borrow::Cow, vec::Vec};
13
14/// A newtype wrapper around [`Uint`] that restricts operations to those
15/// relevant for bit arrays.
16#[derive(Clone, Copy, Default, Eq, PartialEq, Hash)]
17#[cfg_attr(feature = "alloc", derive(Debug))]
18pub struct Bits<const BITS: usize, const LIMBS: usize>(Uint<BITS, LIMBS>);
19
20impl<const BITS: usize, const LIMBS: usize> From<Uint<BITS, LIMBS>> for Bits<BITS, LIMBS> {
21    #[inline]
22    fn from(value: Uint<BITS, LIMBS>) -> Self {
23        Self(value)
24    }
25}
26
27impl<const BITS: usize, const LIMBS: usize> From<Bits<BITS, LIMBS>> for Uint<BITS, LIMBS> {
28    #[inline]
29    fn from(value: Bits<BITS, LIMBS>) -> Self {
30        value.0
31    }
32}
33
34impl<const BITS: usize, const LIMBS: usize> FromStr for Bits<BITS, LIMBS> {
35    type Err = <Uint<BITS, LIMBS> as FromStr>::Err;
36
37    #[inline]
38    fn from_str(src: &str) -> Result<Self, Self::Err> {
39        src.parse().map(Self)
40    }
41}
42
43impl<const BITS: usize, const LIMBS: usize> Bits<BITS, LIMBS> {
44    /// The size of this integer type in 64-bit limbs.
45    pub const LIMBS: usize = Uint::<BITS, LIMBS>::LIMBS;
46
47    /// The size of this integer type in bits.
48    pub const BITS: usize = Uint::<BITS, LIMBS>::BITS;
49
50    /// The size of this integer type in bits.
51    pub const BYTES: usize = Uint::<BITS, LIMBS>::BYTES;
52
53    /// The value zero. This is the only value that exists in all [`Uint`]
54    /// types.
55    pub const ZERO: Self = Self(Uint::<BITS, LIMBS>::ZERO);
56
57    /// Returns the inner [Uint].
58    #[must_use]
59    #[inline(always)]
60    pub const fn into_inner(self) -> Uint<BITS, LIMBS> {
61        self.0
62    }
63
64    /// Returns a reference to the inner [Uint].
65    #[must_use]
66    #[inline(always)]
67    pub const fn as_uint(&self) -> &Uint<BITS, LIMBS> {
68        &self.0
69    }
70
71    /// Returns a mutable reference to the inner [Uint].
72    #[must_use]
73    #[inline(always)]
74    pub fn as_uint_mut(&mut self) -> &mut Uint<BITS, LIMBS> {
75        &mut self.0
76    }
77}
78
79macro_rules! forward_attributes {
80    ($fnname:ident, $item:item $(,must_use: true)?) => {
81        #[doc = concat!("See [`Uint::", stringify!($fnname),"`] for documentation.")]
82        #[inline(always)]
83        #[must_use]
84        $item
85    };
86    ($fnname:ident, $item:item,must_use: false) => {
87        #[doc = concat!("See [`Uint::", stringify!($fnname),"`] for documentation.")]
88        #[inline(always)]
89        $item
90    };
91}
92
93// Limitations of declarative macro matching force us to break down on argument
94// patterns.
95macro_rules! forward {
96    ($(fn $fnname:ident(self) -> $res:ty;)*) => {
97        $(
98            forward_attributes!(
99                $fnname,
100                pub fn $fnname(self) -> $res {
101                    Uint::$fnname(self.0).into()
102                }
103            );
104        )*
105    };
106    ($(fn $fnname:ident$(<$(const $generic_arg:ident: $generic_ty:ty),+>)?(&self) -> $res:ty;)*) => {
107        $(
108            forward_attributes!(
109                $fnname,
110                pub fn $fnname$(<$(const $generic_arg: $generic_ty),+>)?(&self) -> $res {
111                    Uint::$fnname(&self.0).into()
112                }
113            );
114        )*
115    };
116    ($(unsafe fn $fnname:ident(&mut self) -> $res:ty;)*) => {
117        $(
118            forward_attributes!(
119                $fnname,
120                pub unsafe fn $fnname(&mut self) -> $res {
121                    Uint::$fnname(&mut self.0).into()
122                }
123            );
124        )*
125    };
126    ($(fn $fnname:ident(self, $arg:ident: $arg_ty:ty) -> Option<Self>;)*) => {
127        $(
128            forward_attributes!(
129                $fnname,
130                pub fn $fnname(self, $arg: $arg_ty) -> Option<Self> {
131                    Uint::$fnname(self.0, $arg).map(Bits::from)
132                }
133            );
134        )*
135    };
136    ($(fn $fnname:ident(self, $arg:ident: $arg_ty:ty) -> (Self, bool);)*) => {
137        $(
138            forward_attributes!(
139                $fnname,
140                pub fn $fnname(self, $arg: $arg_ty) -> (Self, bool) {
141                    let (value, flag) = Uint::$fnname(self.0, $arg);
142                    (value.into(), flag)
143                }
144            );
145        )*
146    };
147    ($(fn $fnname:ident(self, $arg:ident: $arg_ty:ty) -> $res:ty;)*) => {
148        $(
149            forward_attributes!(
150                $fnname,
151                pub fn $fnname(self, $arg: $arg_ty) -> $res {
152                    Uint::$fnname(self.0, $arg).into()
153                }
154            );
155        )*
156    };
157    ($(fn $fnname:ident$(<$(const $generic_arg:ident: $generic_ty:ty),+>)?($($arg:ident: $arg_ty:ty),+) -> Option<Self>;)*) => {
158        $(
159            forward_attributes!(
160                $fnname,
161                pub fn $fnname$(<$(const $generic_arg: $generic_ty),+>)?($($arg: $arg_ty),+) -> Option<Self> {
162                    Uint::$fnname($($arg),+).map(Bits::from)
163                }
164            );
165        )*
166    };
167    ($(fn $fnname:ident$(<$(const $generic_arg:ident: $generic_ty:ty),+>)?($($arg:ident: $arg_ty:ty),+) -> Result<Self, $err_ty:ty>;)*) => {
168        $(
169            forward_attributes!(
170                $fnname,
171                pub fn $fnname$(<$(const $generic_arg: $generic_ty),+>)?($($arg: $arg_ty),+) -> Result<Self, $err_ty> {
172                    Uint::$fnname($($arg),+).map(Bits::from)
173                },
174                must_use: false
175            );
176        )*
177    };
178    ($(fn $fnname:ident$(<$(const $generic_arg:ident: $generic_ty:ty),+>)?($($arg:ident: $arg_ty:ty),+) -> $res:ty;)*) => {
179        $(
180            forward_attributes!(
181                $fnname,
182                pub fn $fnname$(<$(const $generic_arg: $generic_ty),+>)?($($arg: $arg_ty),+) -> $res {
183                    Uint::$fnname($($arg),+).into()
184                }
185            );
186        )*
187    };
188    ($(const fn $fnname:ident$(<$(const $generic_arg:ident: $generic_ty:ty),+>)?($($arg:ident: $arg_ty:ty),+) -> Self;)*) => {
189        $(
190            forward_attributes!(
191                $fnname,
192                pub const fn $fnname$(<$(const $generic_arg: $generic_ty),+>)?($($arg: $arg_ty),+) -> Self {
193                    Bits(Uint::$fnname($($arg),+))
194                }
195            );
196        )*
197    };
198    ($(const fn $fnname:ident$(<$(const $generic_arg:ident: $generic_ty:ty),+>)?(&self) -> $res_ty:ty;)*) => {
199        $(
200            forward_attributes!(
201                $fnname,
202                pub const fn $fnname$(<$(const $generic_arg: $generic_ty),+>)?(&self) -> $res_ty {
203                    Uint::$fnname(&self.0)
204                }
205            );
206        )*
207    };
208}
209
210#[allow(clippy::missing_safety_doc, clippy::missing_errors_doc)]
211impl<const BITS: usize, const LIMBS: usize> Bits<BITS, LIMBS> {
212    forward! {
213        fn reverse_bits(self) -> Self;
214    }
215    #[cfg(feature = "alloc")]
216    forward! {
217        fn as_le_bytes(&self) -> Cow<'_, [u8]>;
218        fn to_be_bytes_vec(&self) -> Vec<u8>;
219    }
220    forward! {
221        fn to_le_bytes<const BYTES: usize>(&self) -> [u8; BYTES];
222        fn to_be_bytes<const BYTES: usize>(&self) -> [u8; BYTES];
223        fn leading_zeros(&self) -> usize;
224        fn leading_ones(&self) -> usize;
225        fn trailing_zeros(&self) -> usize;
226        fn trailing_ones(&self) -> usize;
227    }
228    forward! {
229        unsafe fn as_limbs_mut(&mut self) -> &mut [u64; LIMBS];
230    }
231    forward! {
232        fn checked_shl(self, rhs: usize) -> Option<Self>;
233        fn checked_shr(self, rhs: usize) -> Option<Self>;
234    }
235    forward! {
236        fn overflowing_shl(self, rhs: usize) -> (Self, bool);
237        fn overflowing_shr(self, rhs: usize) -> (Self, bool);
238    }
239    forward! {
240        fn wrapping_shl(self, rhs: usize) -> Self;
241        fn wrapping_shr(self, rhs: usize) -> Self;
242        fn rotate_left(self, rhs: usize) -> Self;
243        fn rotate_right(self, rhs: usize) -> Self;
244    }
245    forward! {
246        fn try_from_be_slice(bytes: &[u8]) -> Option<Self>;
247        fn try_from_le_slice(bytes: &[u8]) -> Option<Self>;
248    }
249    forward! {
250        fn from_str_radix(src: &str, radix: u64) -> Result<Self, ParseError>;
251    }
252    forward! {
253        fn from_be_bytes<const BYTES: usize>(bytes: [u8; BYTES]) -> Self;
254        fn from_le_bytes<const BYTES: usize>(bytes: [u8; BYTES]) -> Self;
255    }
256    forward! {
257        const fn from_limbs(limbs: [u64; LIMBS]) -> Self;
258    }
259    forward! {
260        const fn as_limbs(&self) -> &[u64; LIMBS];
261    }
262}
263
264impl<const BITS: usize, const LIMBS: usize> Index<usize> for Bits<BITS, LIMBS> {
265    type Output = bool;
266
267    #[inline]
268    fn index(&self, index: usize) -> &Self::Output {
269        if self.0.bit(index) {
270            &true
271        } else {
272            &false
273        }
274    }
275}
276
277impl<const BITS: usize, const LIMBS: usize> Not for Bits<BITS, LIMBS> {
278    type Output = Self;
279
280    #[inline]
281    fn not(self) -> Self {
282        self.0.not().into()
283    }
284}
285
286impl<const BITS: usize, const LIMBS: usize> Not for &Bits<BITS, LIMBS> {
287    type Output = Bits<BITS, LIMBS>;
288
289    #[inline]
290    fn not(self) -> Bits<BITS, LIMBS> {
291        self.0.not().into()
292    }
293}
294
295macro_rules! impl_bit_op {
296    ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => {
297        impl<const BITS: usize, const LIMBS: usize> $trait_assign<Bits<BITS, LIMBS>>
298            for Bits<BITS, LIMBS>
299        {
300            #[inline(always)]
301            fn $fn_assign(&mut self, rhs: Bits<BITS, LIMBS>) {
302                self.0.$fn_assign(&rhs.0);
303            }
304        }
305        impl<const BITS: usize, const LIMBS: usize> $trait_assign<&Bits<BITS, LIMBS>>
306            for Bits<BITS, LIMBS>
307        {
308            #[inline(always)]
309            fn $fn_assign(&mut self, rhs: &Bits<BITS, LIMBS>) {
310                self.0.$fn_assign(rhs.0);
311            }
312        }
313        impl<const BITS: usize, const LIMBS: usize> $trait<Bits<BITS, LIMBS>>
314            for Bits<BITS, LIMBS>
315        {
316            type Output = Bits<BITS, LIMBS>;
317
318            #[inline(always)]
319            fn $fn(mut self, rhs: Bits<BITS, LIMBS>) -> Self::Output {
320                self.0.$fn_assign(rhs.0);
321                self
322            }
323        }
324        impl<const BITS: usize, const LIMBS: usize> $trait<&Bits<BITS, LIMBS>>
325            for Bits<BITS, LIMBS>
326        {
327            type Output = Bits<BITS, LIMBS>;
328
329            #[inline(always)]
330            fn $fn(mut self, rhs: &Bits<BITS, LIMBS>) -> Self::Output {
331                self.0.$fn_assign(rhs.0);
332                self
333            }
334        }
335        impl<const BITS: usize, const LIMBS: usize> $trait<Bits<BITS, LIMBS>>
336            for &Bits<BITS, LIMBS>
337        {
338            type Output = Bits<BITS, LIMBS>;
339
340            #[inline(always)]
341            fn $fn(self, mut rhs: Bits<BITS, LIMBS>) -> Self::Output {
342                rhs.0.$fn_assign(self.0);
343                rhs
344            }
345        }
346        impl<const BITS: usize, const LIMBS: usize> $trait<&Bits<BITS, LIMBS>>
347            for &Bits<BITS, LIMBS>
348        {
349            type Output = Bits<BITS, LIMBS>;
350
351            #[inline(always)]
352            fn $fn(self, rhs: &Bits<BITS, LIMBS>) -> Self::Output {
353                self.0.clone().$fn(rhs.0).into()
354            }
355        }
356    };
357}
358
359impl_bit_op!(BitOr, bitor, BitOrAssign, bitor_assign);
360impl_bit_op!(BitAnd, bitand, BitAndAssign, bitand_assign);
361impl_bit_op!(BitXor, bitxor, BitXorAssign, bitxor_assign);
362
363macro_rules! impl_shift {
364    ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => {
365        impl<const BITS: usize, const LIMBS: usize> $trait_assign<usize> for Bits<BITS, LIMBS> {
366            #[inline(always)]
367            fn $fn_assign(&mut self, rhs: usize) {
368                self.0.$fn_assign(rhs);
369            }
370        }
371
372        impl<const BITS: usize, const LIMBS: usize> $trait_assign<&usize> for Bits<BITS, LIMBS> {
373            #[inline(always)]
374            fn $fn_assign(&mut self, rhs: &usize) {
375                self.0.$fn_assign(rhs);
376            }
377        }
378
379        impl<const BITS: usize, const LIMBS: usize> $trait<usize> for Bits<BITS, LIMBS> {
380            type Output = Self;
381
382            #[inline(always)]
383            fn $fn(self, rhs: usize) -> Self {
384                self.0.$fn(rhs).into()
385            }
386        }
387
388        impl<const BITS: usize, const LIMBS: usize> $trait<usize> for &Bits<BITS, LIMBS> {
389            type Output = Bits<BITS, LIMBS>;
390
391            #[inline(always)]
392            fn $fn(self, rhs: usize) -> Self::Output {
393                self.0.$fn(rhs).into()
394            }
395        }
396
397        impl<const BITS: usize, const LIMBS: usize> $trait<&usize> for Bits<BITS, LIMBS> {
398            type Output = Self;
399
400            #[inline(always)]
401            fn $fn(self, rhs: &usize) -> Self {
402                self.0.$fn(rhs).into()
403            }
404        }
405
406        impl<const BITS: usize, const LIMBS: usize> $trait<&usize> for &Bits<BITS, LIMBS> {
407            type Output = Bits<BITS, LIMBS>;
408
409            #[inline(always)]
410            fn $fn(self, rhs: &usize) -> Self::Output {
411                self.0.$fn(rhs).into()
412            }
413        }
414    };
415}
416
417impl_shift!(Shl, shl, ShlAssign, shl_assign);
418impl_shift!(Shr, shr, ShrAssign, shr_assign);