simple_bits/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
4
5use core::ops::Range;
6
7/// Provides a simpler interface to extract from a given value and replace bits in a given value
8/// than manipulating the value directly using bit shifting and masking.
9pub trait BitsExt {
10    /// Extracts a single bit from the integer at the given index. Returns `true` if the bit is
11    /// set, `false` otherwise.
12    fn extract_bit(self, index: usize) -> bool;
13
14    /// Extracts the given range of bits from the integer.
15    fn extract_bits(self, range: Range<usize>) -> Self;
16
17    /// Replaces a single bit in the integer at the given index.
18    fn replace_bit(self, index: usize, value: bool) -> Self;
19
20    /// Replaces the given range of bits in the integer with the given value.
21    fn replace_bits(self, range: Range<usize>, value: Self) -> Self;
22}
23
24macro_rules! bits_ext_impl {
25    ($t:ident) => {
26        impl BitsExt for $t {
27            fn extract_bit(self, index: usize) -> bool {
28                (self >> index) & 1 == 1
29            }
30
31            fn extract_bits(self, range: Range<usize>) -> Self {
32                (self >> range.start) & ((1 << range.len()) - 1)
33            }
34
35            fn replace_bit(self, index: usize, value: bool) -> Self {
36                (self & !(1 << index)) | ((value as Self) << index)
37            }
38
39            fn replace_bits(self, range: Range<usize>, value: Self) -> Self {
40                let mask = (1 << range.len()) - 1;
41
42                (self & !(mask << range.start)) | ((value & mask) << range.start)
43            }
44        }
45    }
46}
47
48bits_ext_impl!(u8);
49bits_ext_impl!(u16);
50bits_ext_impl!(u32);
51bits_ext_impl!(u64);
52bits_ext_impl!(usize);
53
54bits_ext_impl!(i8);
55bits_ext_impl!(i16);
56bits_ext_impl!(i32);
57bits_ext_impl!(i64);
58bits_ext_impl!(isize);
59
60#[cfg(test)]
61mod tests {
62    #[test]
63    fn extract_bits() {
64        use crate::BitsExt;
65
66        assert_eq!(0xdeadbeef_u32.extract_bits(0..16), 0xbeef);
67        assert_eq!(0xdeadbeef_u32.extract_bits(16..32), 0xdead);
68    }
69
70    #[test]
71    fn replace_bits() {
72        use crate::BitsExt;
73
74        assert_eq!(0xdeadbeef_u32.replace_bits(0..16, 0xcafe), 0xdeadcafe);
75    }
76
77    #[test]
78    fn single_bit() {
79        use crate::BitsExt;
80
81        assert_eq!(0xf0_u8.extract_bit(7), true);
82        assert_eq!(0xf0_u8.replace_bit(7, true), 0xf0);
83        assert_eq!(0xf0_u8.replace_bit(7, false), 0x70);
84    }
85}