lazy_bytes_cast/bits.rs
1use core::{mem, fmt, ops, hash};
2
3#[repr(transparent)]
4#[derive(Clone, Copy, Default)]
5///Wrapper to provide access to bit fields
6///
7///```
8///use lazy_bytes_cast::Bits;
9///
10///let mut bits = Bits(u32::max_value());
11///assert!(!bits.empty());
12///
13///assert!(bits.get(1));
14///
15///bits = bits.set(1);
16///assert!(bits.get(1));
17///
18///bits = bits.toggle(1);
19///assert!(!bits.get(1));
20///
21///bits = bits.unset(1);
22///assert!(!bits.get(1));
23///
24///bits = bits.toggle(1);
25///assert!(bits.get(1));
26///
27///bits = bits.reset();
28///assert_eq!(bits, 0);
29///assert!(bits.empty());
30///
31///assert!(!bits.get(1));
32///
33///assert_eq!(bits.len(), core::mem::size_of_val(&bits) * 8);
34///
35///bits = Bits(u32::min_value());
36///assert!(bits.empty());
37///assert!(!bits.get(1));
38///
39///bits = bits.set(1);
40///assert!(bits.get(1));
41///
42///bits = bits.unset(1);
43///assert!(!bits.get(1));
44///
45///bits = bits.set(26);
46///assert!(bits.get(26));
47///assert!(bits.get(90)); //90 % 32 == 26
48///bits = bits.set(91);
49///assert!(bits.get(26));
50///
51///bits = bits.flip();
52///assert!(!bits.get(26));
53///assert!(bits.get(5));
54///```
55pub struct Bits<T>(pub T);
56
57macro_rules! impl_bits {
58 ($($ty:ident),*) => {$(
59 impl Bits<$ty> {
60 #[inline(always)]
61 ///Get bit by index.
62 pub const fn get(&self, idx: u32) -> bool {
63 self.0.wrapping_shr(idx) & 1 != 0
64 }
65
66 #[inline(always)]
67 ///Set bit by index and return updated value.
68 pub const fn set(self, idx: u32) -> Self {
69 const ONE: $ty = 1;
70
71 Self(self.0 | ONE.wrapping_shl(idx))
72 }
73
74 #[inline(always)]
75 ///Unset bit by index and return updated value.
76 pub const fn unset(self, idx: u32) -> Self {
77 Self(self.0 & !(1 << idx))
78 }
79
80 #[inline(always)]
81 ///Unset bit by index and return updated value.
82 pub const fn toggle(self, idx: u32) -> Self {
83 Self(self.0 ^ (1 << idx))
84 }
85
86 #[inline(always)]
87 ///Returns whether all bits are unset
88 pub const fn empty(&self) -> bool {
89 self.0 == 0
90 }
91
92 #[inline(always)]
93 ///Unset all bits and returns updated value
94 pub const fn reset(&self) -> Self {
95 Self(0)
96 }
97
98 #[inline(always)]
99 ///Flip all bits and returns updated value
100 pub const fn flip(&self) -> Self {
101 Self(self.0.reverse_bits())
102 }
103
104 #[inline(always)]
105 ///Returns number of bits inside.
106 pub const fn len(&self) -> usize {
107 Self::size()
108 }
109
110 #[inline(always)]
111 ///Returns number of bits inside.
112 pub const fn size() -> usize {
113 mem::size_of::<$ty>() * 8
114 }
115 }
116
117 impl PartialEq<Bits<$ty>> for $ty {
118 #[inline(always)]
119 fn eq(&self, other: &Bits<$ty>) -> bool {
120 PartialEq::eq(self, &other.0)
121 }
122 }
123
124 impl fmt::Debug for Bits<$ty> {
125 #[inline(always)]
126 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
127 fmt::Debug::fmt(&self.0, fmt)
128 }
129 }
130
131 impl fmt::Display for Bits<$ty> {
132 #[inline(always)]
133 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
134 fmt::Display::fmt(&self.0, fmt)
135 }
136 }
137
138 impl fmt::Binary for Bits<$ty> {
139 #[inline(always)]
140 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
141 fmt::Binary::fmt(&self.0, fmt)
142 }
143 }
144
145 impl PartialEq<$ty> for Bits<$ty> {
146 #[inline(always)]
147 fn eq(&self, other: &$ty) -> bool {
148 PartialEq::eq(&self.0, other)
149 }
150 }
151
152 impl ops::Deref for Bits<$ty> {
153 type Target = $ty;
154 #[inline(always)]
155 fn deref(&self) -> &Self::Target {
156 &self.0
157 }
158 }
159
160 impl ops::DerefMut for Bits<$ty> {
161 #[inline(always)]
162 fn deref_mut(&mut self) -> &mut Self::Target {
163 &mut self.0
164 }
165 }
166
167 impl hash::Hash for Bits<$ty> {
168 #[inline(always)]
169 fn hash<H: hash::Hasher>(&self, state: &mut H) {
170 hash::Hash::hash(&self.0, state)
171 }
172 }
173
174 impl From<$ty> for Bits<$ty> {
175 #[inline(always)]
176 fn from(val: $ty) -> Self {
177 Self(val)
178 }
179 }
180
181 impl Into<$ty> for Bits<$ty> {
182 #[inline(always)]
183 fn into(self) -> $ty {
184 self.0
185 }
186 }
187 )*};
188}
189
190impl_bits!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);