rust_bitfield/
lib.rs

1#![allow(dead_code)]
2#![allow(non_snake_case)]
3#![allow(non_upper_case_globals)]
4
5/// A trait to get or set a single bit.
6///
7/// This trait is implemented for all type that implement `BitRange<T>`.
8pub trait Bit {
9    /// Get a single bit.
10    fn bit(&self, bit: usize) -> bool;
11
12    /// Set a single bit.
13    fn set_bit(&mut self, bit: usize, value: bool);
14}
15
16/// A trait to get or set ranges of bits.
17pub trait BitRange<T> {
18    /// Get a range of bits.
19    fn bit_range(&self, msb: usize, lsb: usize) -> T;
20    /// Set a range of bits.
21    fn set_bit_range(&mut self, msb: usize, lsb: usize, value: T);
22}
23
24/// A struct to support bits operations.
25pub struct Bits<T>(pub T);
26
27#[macro_export(local_inner_macros)]
28macro_rules! impl_bits {
29    () => {};
30    (@inner $T:tt => bool) => {
31        impl From<bool> for Bits<$T> {
32            fn from(value: bool) -> Self {
33                match value {
34                    true => Self(1 as $T),
35                    false => Self(0 as $T),
36                }
37            }
38        }
39        impl Into<bool> for Bits<$T> {
40            fn into(self) -> bool {
41                match self.0 {
42                    0 => false,
43                    _ => true,
44                }
45            }
46        }
47        impl Bit for Bits<$T> {
48            fn bit(&self, bit: usize) -> bool {
49                (self.0 & (1 << bit)) != 0
50            }
51
52            fn set_bit(&mut self, bit: usize, value: bool) {
53                match value {
54                    true => self.0 |= 1 << bit,
55                    false => self.0 &= !(1 << bit),
56                }
57            }
58        }
59    };
60    (@inner $T:tt => $U:tt) => {
61        impl From<$U> for Bits<$T> {
62            fn from(value: $U) -> Self {
63                Self(value as $T)
64            }
65        }
66        impl Into<$U> for Bits<$T> {
67            fn into(self) -> $U {
68                self.0 as $U
69            }
70        }
71        impl BitRange<$U> for Bits<$T> {
72            #[inline]
73            #[allow(unknown_lints)]
74            #[allow(cast_lossless)]
75            fn bit_range(&self, msb: usize, lsb: usize) -> $U {
76                let mask = ((1 << (msb - lsb + 1)) - 1) << lsb;
77                ((self.0 & mask) >> lsb) as $U
78            }
79
80            #[inline]
81            #[allow(unknown_lints)]
82            #[allow(cast_lossless)]
83            fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $U) {
84                let mask = ((1 << (msb - lsb + 1)) - 1) << lsb;
85                self.0 = (self.0 & !mask) | ((value as $T) << lsb);
86            }
87        }
88    };
89    ($T:tt => [$($U:tt),*]; $($rest:tt)*) => {
90        $(
91            impl_bits!{ @inner $T => $U }
92        )*
93        impl_bits!{ $($rest)* }
94    }
95}
96
97#[macro_export(local_inner_macros)]
98macro_rules! impl_bitrange {
99    () => {};
100    (@inner $T:ty => $U:ty) => {
101        impl From<$U> for Bits<$T> {
102            fn from(value: $U) -> Self {
103                Self(value as $T)
104            }
105        }
106        impl Into<$U> for Bits<$T> {
107            fn into(self) -> $U {
108                self.0 as $U
109            }
110        }
111        impl BitRange<$U> for Bits<$T> {
112            #[inline]
113            #[allow(unknown_lints)]
114            #[allow(cast_lossless)]
115            fn bit_range(&self, msb: usize, lsb: usize) -> $U {
116                let mask = ((1 << (msb - lsb + 1)) - 1) << lsb;
117                ((self.0 & mask) >> lsb) as $U
118            }
119
120            #[inline]
121            #[allow(unknown_lints)]
122            #[allow(cast_lossless)]
123            fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $U) {
124                let mask = ((1 << (msb - lsb + 1)) - 1) << lsb;
125                self.0 = (self.0 & !mask) | ((value as $T) << lsb);
126            }
127        }
128    };
129    ($T:ty => [$($U:ty),*]; $($rest:tt)*) => {
130        $(
131            impl_bitrange!{ @inner $T => $U }
132        )*
133        impl_bitrange!{ $($rest)* }
134    }
135}
136
137#[macro_export(local_inner_macros)]
138macro_rules! bitfield_fields {
139    // Empty.
140    () => {};
141    // Dummy.
142    (@field ($(#[$attribute:meta])*) ($($vis:tt)*) _, _ : $sty:tt [] in $slot:tt) => {
143    };
144    (@field ($(#[$attribute:meta])*) ($($vis:tt)*) _, _ : $sty:tt [$msb:tt..$lsb:tt] in $slot:tt as $vty:tt) => {
145    };
146    // Return all bits.
147    (@field ($(#[$attribute:meta])*) ($($vis:tt)*) $getter:tt, _ : $sty:tt [] in $slot:tt) => {
148        $(#[$attribute])*
149        $($vis)* fn $getter(&self) -> $sty {
150            self.$slot
151        }
152    };
153    // Return msb bit as bool.
154    (@field ($(#[$attribute:meta])*) ($($vis:tt)*) $getter:tt, _ : $sty:tt [$msb:tt..$lsb:tt] in $slot:tt as bool) => {
155        $(#[$attribute])*
156        $($vis)* fn $getter(&self) -> bool {
157            Bits::<$sty>(self.$slot).bit($msb)
158        }
159    };
160    // Return bit range of [msb..lsb] as U.
161    (@field ($(#[$attribute:meta])*) ($($vis:tt)*) $getter:tt, _ : $sty:tt [$msb:tt..$lsb:tt] in $slot:tt as $vty:tt) => {
162        $(#[$attribute])*
163        $($vis)* fn $getter(&self) -> $vty {
164            Bits::<$sty>(self.$slot).bit_range($msb, $lsb)
165        }
166    };
167    // Set all bits with T.
168    (@field ($(#[$attribute:meta])*) ($($vis:tt)*) _, $setter:tt : $sty:tt [] in $slot:tt) => {
169        $(#[$attribute])*
170        $($vis)* fn $setter(&mut self, value: $sty) -> &mut Self {
171            self.$slot = value;
172            self
173        }
174    };
175    // Set msb bit with bool.
176    (@field ($(#[$attribute:meta])*) ($($vis:tt)*) _, $setter:tt : $sty:tt [$msb:tt..$lsb:tt] in $slot:tt as bool) => {
177        $(#[$attribute])*
178        $($vis)* fn $setter(&mut self, value: bool) -> &mut Self {
179            let mut bits = Bits::<$sty>(self.$slot);
180            bits.set_bit($msb, value);
181            self.$slot = bits.into();
182            self
183        }
184    };
185    // Set bit range of [msb..lsb] with U.
186    (@field ($(#[$attribute:meta])*) ($($vis:tt)*) _, $setter:tt : $sty:tt [$msb:tt..$lsb:tt] in $slot:tt as $vty:tt) => {
187        $(#[$attribute])*
188        $($vis)* fn $setter(&mut self, value: $vty) -> &mut Self {
189            let mut bits = Bits::<$sty>(self.$slot);
190            bits.set_bit_range($msb, $lsb, value);
191            self.$slot = bits.into();
192            self
193        }
194    };
195    // Match: pub? <getter>,<setter> : <T> []
196    (($(#[$attribute:meta])*) $getter:tt, $setter:tt : $sty:tt []; $($rest:tt)*) => {
197        bitfield_fields!{ @field ($(#[$attribute])*) () $getter, _ : $sty [] in 0 }
198        bitfield_fields!{ @field ($(#[$attribute])*) () _, $setter : $sty [] in 0 }
199        bitfield_fields!{ $($rest)* }
200    };
201    ($(#[$attribute:meta])* pub $getter:tt, $setter:tt : $sty:tt []; $($rest:tt)*) => {
202        bitfield_fields!{ @field ($(#[$attribute])*) (pub) $getter, _ : $sty [] in 0 }
203        bitfield_fields!{ @field ($(#[$attribute])*) (pub) _, $setter : $sty [] in 0 }
204        bitfield_fields!{ $($rest)* }
205    };
206    // Match: pub? <getter>,<setter> : <T> [] in <slot>
207    ($(#[$attribute:meta])* $getter:tt, $setter:tt : $sty:tt [] in $slot:tt; $($rest:tt)*) => {
208        bitfield_fields!{ @field ($(#[$attribute])*) () $getter, _ : $sty [] in $slot }
209        bitfield_fields!{ @field ($(#[$attribute])*) () _, $setter : $sty [] in $slot }
210        bitfield_fields!{ $($rest)* }
211    };
212    ($(#[$attribute:meta])* pub $getter:tt, $setter:tt : $sty:tt [] in $slot:tt; $($rest:tt)*) => {
213        bitfield_fields!{ @field ($(#[$attribute])*) (pub) $getter, _ : $sty [] in $slot }
214        bitfield_fields!{ @field ($(#[$attribute])*) (pub) _, $setter : $sty [] in $slot }
215        bitfield_fields!{ $($rest)* }
216    };
217    // Match: pub? <getter>,<setter> : <T> [<msb>]
218    ($(#[$attribute:meta])* $getter:tt, $setter:tt : $sty:tt [$msb:tt]; $($rest:tt)*) => {
219        bitfield_fields!{ @field ($(#[$attribute])*) () $getter, _ : $sty [$msb..$msb] in 0 as $sty }
220        bitfield_fields!{ @field ($(#[$attribute])*) () _, $setter : $sty [$msb..$msb] in 0 as $sty }
221        bitfield_fields!{ $($rest)* }
222    };
223    ($(#[$attribute:meta])* pub $getter:tt, $setter:tt : $sty:tt [$msb:tt]; $($rest:tt)*) => {
224        bitfield_fields!{ @field ($(#[$attribute])*) (pub) $getter, _ : $sty [$msb..$msb] in 0 as $sty }
225        bitfield_fields!{ @field ($(#[$attribute])*) (pub) _, $setter : $sty [$msb..$msb] in 0 as $sty }
226        bitfield_fields!{ $($rest)* }
227    };
228    // Match: pub? <getter>,<setter> : <T> [<msb>] in <slot>
229    ($(#[$attribute:meta])* $getter:tt, $setter:tt : $sty:tt [$msb:tt] in $slot:tt; $($rest:tt)*) => {
230        bitfield_fields!{ @field ($(#[$attribute])*) () $getter, _ : $sty [$msb..$msb] in $slot as $sty }
231        bitfield_fields!{ @field ($(#[$attribute])*) () _, $setter : $sty [$msb..$msb] in $slot as $sty }
232        bitfield_fields!{ $($rest)* }
233    };
234    ($(#[$attribute:meta])* pub $getter:tt, $setter:tt : $sty:tt [$msb:tt] in $slot:tt; $($rest:tt)*) => {
235        bitfield_fields!{ @field ($(#[$attribute])*) (pub) $getter, _ : $sty [$msb..$msb] in $slot as $sty }
236        bitfield_fields!{ @field ($(#[$attribute])*) (pub) _, $setter : $sty [$msb..$msb] in $slot as $sty }
237        bitfield_fields!{ $($rest)* }
238    };
239    // Match: pub? <getter>,<setter> : <T> [<msb>] as <U>
240    ($(#[$attribute:meta])* $getter:tt, $setter:tt : $sty:tt [$msb:tt] as $vty:tt; $($rest:tt)*) => {
241        bitfield_fields!{ @field ($(#[$attribute])*) () $getter, _ : $sty [$msb..$msb] in 0 as $vty }
242        bitfield_fields!{ @field ($(#[$attribute])*) () _, $setter : $sty [$msb..$msb] in 0 as $vty }
243        bitfield_fields!{ $($rest)* }
244    };
245    ($(#[$attribute:meta])* pub $getter:tt, $setter:tt : $sty:tt [$msb:tt] as $vty:tt; $($rest:tt)*) => {
246        bitfield_fields!{ @field ($(#[$attribute])*) (pub) $getter, _ : $sty [$msb..$msb] in 0 as $vty }
247        bitfield_fields!{ @field ($(#[$attribute])*) (pub) _, $setter : $sty [$msb..$msb] in 0 as $vty }
248        bitfield_fields!{ $($rest)* }
249    };
250    // Match: pub? <getter>,<setter> : <T> [<msb>] in <slot> as <U>
251    ($(#[$attribute:meta])* $getter:tt, $setter:tt : $sty:tt [$msb:tt] in $slot:tt as $vty:tt; $($rest:tt)*) => {
252        bitfield_fields!{ @field ($(#[$attribute])*) () $getter, _ : $sty [$msb..$msb] in $slot as $vty }
253        bitfield_fields!{ @field ($(#[$attribute])*) () _, $setter : $sty [$msb..$msb] in $slot as $vty }
254        bitfield_fields!{ $($rest)* }
255    };
256    ($(#[$attribute:meta])* pub $getter:tt, $setter:tt : $sty:tt [$msb:tt] in $slot:tt as $vty:tt; $($rest:tt)*) => {
257        bitfield_fields!{ @field ($(#[$attribute])*) (pub) $getter, _ : $sty [$msb..$msb] in $slot as $vty }
258        bitfield_fields!{ @field ($(#[$attribute])*) (pub) _, $setter : $sty [$msb..$msb] in $slot as $vty }
259        bitfield_fields!{ $($rest)* }
260    };
261    // Match: pub? <getter>,<setter> : <T> [<msb>..<lsb>]
262    ($(#[$attribute:meta])* $getter:tt, $setter:tt : $sty:tt [$msb:tt..$lsb:tt]; $($rest:tt)*) => {
263        bitfield_fields!{ @field ($(#[$attribute])*) () $getter, _ : $sty [$msb..$lsb] in 0 as $sty }
264        bitfield_fields!{ @field ($(#[$attribute])*) () _, $setter : $sty [$msb..$lsb] in 0 as $sty }
265        bitfield_fields!{ $($rest)* }
266    };
267    ($(#[$attribute:meta])* pub $getter:tt, $setter:tt : $sty:tt [$msb:tt..$lsb:tt]; $($rest:tt)*) => {
268        bitfield_fields!{ @field ($(#[$attribute])*) (pub) $getter, _ : $sty [$msb..$lsb] in 0 as $sty }
269        bitfield_fields!{ @field ($(#[$attribute])*) (pub) _, $setter : $sty [$msb..$lsb] in 0 as $sty }
270        bitfield_fields!{ $($rest)* }
271    };
272    // Match: pub? <getter>,<setter> : <T> [<msb>..<lsb>] in <slot>
273    ($(#[$attribute:meta])* $getter:tt, $setter:tt : $sty:tt [$msb:tt..$lsb:tt] in $slot:tt; $($rest:tt)*) => {
274        bitfield_fields!{ @field ($(#[$attribute])*) () $getter, _ : $sty [$msb..$lsb] in $slot as $sty }
275        bitfield_fields!{ @field ($(#[$attribute])*) () _, $setter : $sty [$msb..$lsb] in $slot as $sty }
276        bitfield_fields!{ $($rest)* }
277    };
278    ($(#[$attribute:meta])* pub $getter:tt, $setter:tt : $sty:tt [$msb:tt..$lsb:tt] in $slot:tt; $($rest:tt)*) => {
279        bitfield_fields!{ @field ($(#[$attribute])*) (pub) $getter, _ : $sty [$msb..$lsb] in $slot as $sty }
280        bitfield_fields!{ @field ($(#[$attribute])*) (pub) _, $setter : $sty [$msb..$lsb] in $slot as $sty }
281        bitfield_fields!{ $($rest)* }
282    };
283    // Match: pub? <getter>,<setter> : <T> [<msb>..<lsb>] as <U>
284    ($(#[$attribute:meta])* $getter:tt, $setter:tt : $sty:tt [$msb:tt..$lsb:tt] as $vty:tt; $($rest:tt)*) => {
285        bitfield_fields!{ @field ($(#[$attribute])*) () $getter, _ : $sty [$msb..$lsb] in 0 as $vty }
286        bitfield_fields!{ @field ($(#[$attribute])*) () _, $setter : $sty [$msb..$lsb] in 0 as $vty }
287        bitfield_fields!{ $($rest)* }
288    };
289    ($(#[$attribute:meta])* pub $getter:tt, $setter:tt : $sty:tt [$msb:tt..$lsb:tt] as $vty:tt; $($rest:tt)*) => {
290        bitfield_fields!{ @field ($(#[$attribute])*) (pub) $getter, _ : $sty [$msb..$lsb] in 0 as $vty }
291        bitfield_fields!{ @field ($(#[$attribute])*) (pub) _, $setter : $sty [$msb..$lsb] in 0 as $vty }
292        bitfield_fields!{ $($rest)* }
293    };
294    // Match: pub? <getter>,<setter> : <T> [<msb>..<lsb>] in <slot> as <U>
295    ($(#[$attribute:meta])* $getter:tt, $setter:tt : $sty:tt [$msb:tt..$lsb:tt] in $slot:tt as $vty:tt; $($rest:tt)*) => {
296        bitfield_fields!{ @field ($(#[$attribute])*) () $getter, _ : $sty [$msb..$lsb] in $slot as $vty }
297        bitfield_fields!{ @field ($(#[$attribute])*) () _, $setter : $sty [$msb..$lsb] in $slot as $vty }
298        bitfield_fields!{ $($rest)* }
299    };
300    ($(#[$attribute:meta])* pub $getter:tt, $setter:tt : $sty:tt [$msb:tt..$lsb:tt] in $slot:tt as $vty:tt; $($rest:tt)*) => {
301        bitfield_fields!{ @field ($(#[$attribute])*) (pub) $getter, _ : $sty [$msb..$lsb] in $slot as $vty }
302        bitfield_fields!{ @field ($(#[$attribute])*) (pub) _, $setter : $sty [$msb..$lsb] in $slot as $vty }
303        bitfield_fields!{ $($rest)* }
304    };
305}
306
307impl_bits! {
308    i8 => [bool, i8, i16, i32, i64, u8, u16, u32, u64];
309    i16 => [bool, i8, i16, i32, i64, u8, u16, u32, u64];
310    i32 => [bool, i8, i16, i32, i64, u8, u16, u32, u64];
311    i64 => [bool, i8, i16, i32, i64, u8, u16, u32, u64];
312    u8 => [bool, i8, i16, i32, i64, u8, u16, u32, u64];
313    u16 => [bool, i8, i16, i32, i64, u8, u16, u32, u64];
314    u32 => [bool, i8, i16, i32, i64, u8, u16, u32, u64];
315    u64 => [bool, i8, i16, i32, i64, u8, u16, u32, u64];
316}
317
318#[cfg(test)]
319mod tests {
320    use super::*;
321
322    #[derive(Copy, Clone, Default, Debug)]
323    struct FooBar(u8,u16,u32,u64);
324
325    impl FooBar {
326        bitfield_fields! {
327            // u8
328            f1a, set_f1a : u8 [0];
329            f1b, set_f1b : u8 [1] in 0;
330            f1c, set_f1c : u8 [2] as bool;
331            f1d, set_f1d : u8 [4..3] in 0 as u8;
332            f1e, set_f1e : u8 [7..5] in 0 as u16;
333            pub all1, _ : u8 [] in 0;
334            // u16
335            f2a, set_f2a : u16 [15] in 1 as bool;
336            f2b, set_f2b : u16 [14..0] in 1;
337            pub all2, _ : u16 [] in 1;
338            // u32
339            f3a, set_f3a : u32 [7..0] in 2 as u8;
340            f3b, set_f3b : u32 [15..8] in 2 as u8;
341            f3c, set_f3c : u32 [15..8] in 2 as u8;
342            pub all3, _ : u32 [] in 2;
343            // u64
344            rsv, _ : u64 [] in 3;
345        }
346    }
347
348    #[test]
349    fn test_foobar() {
350        let mut a = FooBar(0x77, 0x55AA, 0xFF77_AA55, 0x0000_FFFF_FF77_AA55);
351        assert_eq!(1, a.f1a());
352        assert_eq!(1, a.f1b());
353        assert_eq!(true, a.f1c());
354        assert_eq!(false, a.set_f1c(false).f1c());
355        assert_eq!(0x73, a.all1());
356        assert_eq!(2, a.f1d());
357        assert_eq!(0, a.set_f1d(0).f1d());
358        assert_eq!(0x63, a.all1());
359        assert_eq!(3, a.f1e());
360        assert_eq!(7, a.set_f1e(7).f1e());
361        assert_eq!(0xE3, a.all1());
362        assert_eq!(0x0000_FFFF_FF77_AA55, a.rsv());
363    }
364}