1#![no_std]
2#![doc = include_str!("../README.md")]
3#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
4
5use core::ops::Range;
6
7pub trait BitsExt {
10 fn extract_bit(self, index: usize) -> bool;
13
14 fn extract_bits(self, range: Range<usize>) -> Self;
16
17 fn replace_bit(self, index: usize, value: bool) -> Self;
19
20 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}