u8bits/lib.rs
1#![no_std]
2#![deny(
3 missing_docs,
4 unused_extern_crates,
5 unused_import_braces,
6 unused_qualifications
7)]
8
9//! A macro to generate bit field like getters and setters on structs which
10//! represent an array of bytes.
11//!
12//! See the documentation of the macro for how to use it.
13
14pub use paste;
15
16/// Set the given 'value' in byte 'b' in the range of the given bit positions
17/// 'lsb' (least significant bit) and 'msb' (most significant bit) inclusive.
18/// the other bits are not touched.
19pub fn set_bit_range(b: &mut u8, lsb: u8, msb: u8, value: u8) {
20 let mask: u8 = !0u8 << (7 - msb) >> (7 - msb + lsb) << lsb;
21 *b &= !mask;
22 *b |= (value << lsb) & mask;
23}
24/// Return the 'value' of byte 'b' in the range of the given bit positions
25/// 'lsb' (least significant bit) and 'msb' (most significant bit) inclusive.
26pub fn get_bit_range(b: &u8, lsb: u8, msb: u8) -> u8 {
27 let mask: u8 = !0u8 << (7 - msb) >> (7 - msb + lsb) << lsb;
28 (*b & mask) >> lsb
29}
30/// Set the bit at position 'pos' of byte 'b'.
31pub fn set_bit(b: &mut u8, pos: u8, value: bool) {
32 let mask: u8 = !1u8 << pos;
33 *b &= !mask; if value { *b |= mask; }
34}
35/// Get the bit at position 'pos' of byte 'b'.
36pub fn get_bit(b: &u8, pos: u8) -> bool {
37 let mask: u8 = !1u8 << pos;
38 (*b & mask) == mask
39}
40
41
42/// This macro allows the generaion of bit field like getters
43/// and setters for a New Type struct of type [u8;N].
44/// There are bit wise accessors and bit range accessors.
45/// The bitwise operations map to an boolean value whereas the
46/// bit range operations use an provided type which has to implement
47/// the .into() conversion trait.
48/// The bit wise field declaration is as follows:
49///
50/// * Optional attributes (`#[...]`), documentation comments (`///`) are attributes;
51/// * the identifier, which will be suffixed by 'set_' and / or 'get_'
52/// * A colon
53/// * an 'r' or 'w' or 'rw' flag which indicates which accessor are created
54/// (read->get,write->set or both)
55/// * the byte number followed by a comma
56/// * the bit number
57///
58/// The bit range operations are as follows:
59///
60/// * Optional attributes (`#[...]`), documentation comments (`///`) are attributes;
61/// * An type, which has to provide the core conversion Into<u8> trait, followed by a comma
62/// * the identifier, which will be suffixed by 'set_' and / or 'get_'
63/// * A colon
64/// * an 'r' or 'w' or 'rw' flag which indicates which accessor are created
65/// (read->get,write->set or both)
66/// * the byte number followed by a comma
67/// * the lsb (least significant) bit number
68/// * the msb (most significant) bit number inclusive
69///
70/// So a typical declaration might look like:
71/// ```rust
72/// use u8bits::u8bits;
73///
74/// struct Bytes( [u8;2]);
75/// impl Bytes {
76/// u8bits! {
77/// /// foo is bit 4 of byte 0
78/// foo: rw 0,4;
79/// /// bar are bits 0..3 of byte 1
80/// u8, bar: rw 1,0,3;
81/// }
82/// }
83///
84/// ```
85/// which will expand to:
86/// ```rust
87/// struct Bytes([u8; 2]);
88/// impl Bytes {
89/// #[inline]
90/// #[doc = r" foo is bit 4 of byte 0"]
91/// pub fn get_foo(&self) -> bool { ::u8bits::get_bit(&self.0[0], 4) }
92/// #[inline]
93/// #[doc = r" foo is bit 4 of byte 0"]
94/// pub fn set_foo(&mut self, value: bool) {
95/// ::u8bits::set_bit(&mut self.0[0], 4, value)
96/// }
97/// #[inline]
98/// #[doc = r" bar are bits 0..3 of byte 1"]
99/// pub fn get_bar(&self) -> u8 {
100/// ::u8bits::get_bit_range(&self.0[1], 0, 3).into()
101/// }
102/// #[inline]
103/// #[doc = r" bar are bits 0..3 of byte 1"]
104/// pub fn set_bar(&mut self, value: u8) {
105/// ::u8bits::set_bit_range(&mut self.0[1], 0, 3, value.into())
106/// }
107/// }
108/// ```
109///
110/// For the use of bitfield like enums see for example the
111/// [surjective-enum](https://crates.io/crates/surjective-enum)
112/// crate or the test of this crate.
113#[macro_export]
114macro_rules! u8bits {
115 // bit range write
116 (@field $(#[$attr:meta])* $t:ty, $id:ident:
117 w $byte:expr, $lsb:expr, $msb:expr;) => {
118 paste::item! {
119 #[inline]
120 $(#[$attr])*
121 pub fn [<set_ $id>](&mut self, value: $t) {
122 ::u8bits::set_bit_range(&mut self.0[$byte], $lsb, $msb, value.into())
123 }
124 }
125 };
126 // bit range read, returns $t
127 (@field $(#[$attr:meta])* $t:ty, $id:ident:
128 r $byte:expr, $lsb:expr, $msb:expr;) => {
129 paste::item! {
130 #[inline]
131 $(#[$attr])*
132 pub fn [<get_ $id>](&self) -> $t {
133 ::u8bits::get_bit_range(&self.0[$byte], $lsb, $msb).into()
134 }
135 }
136 };
137 // bit range read and write
138 (@field $(#[$attr:meta])* $t:ty, $id:ident:
139 rw $byte:expr, $lsb:expr, $msb:expr;) => {
140 u8bits!{@field $(#[$attr])* $t, $id: r $byte, $lsb, $msb;}
141 u8bits!{@field $(#[$attr])* $t, $id: w $byte, $lsb, $msb;}
142 };
143 // single bit, write
144 (@field $(#[$attr:meta])* $id:ident: w $byte:expr, $bit:expr;) => {
145 paste::item! {
146 #[inline]
147 $(#[$attr])*
148 pub fn [<set_ $id>](&mut self, value: bool) {
149 ::u8bits::set_bit(&mut self.0[$byte], $bit, value)
150 }
151 }
152 };
153 // single bit, read
154 (@field $(#[$attr:meta])* $id:ident: r $byte:expr, $bit:expr;) => {
155 paste::item! {
156 #[inline]
157 $(#[$attr])*
158 pub fn [<get_ $id>](&self) -> bool {
159 ::u8bits::get_bit(&self.0[$byte], $bit)
160 }
161 }
162 };
163 // single bit, read and write
164 (@field $(#[$attr:meta])* $id:ident: rw $byte:expr, $bit:expr;) => {
165 u8bits!{@field $(#[$attr])* $id: r $byte, $bit;}
166 u8bits!{@field $(#[$attr])* $id: w $byte, $bit;}
167 };
168 // iteration, first is bit range
169 ( $(#[$attr:meta])* $t:ty, $id:ident: $f:ident $($expr:expr),+; $($rest:tt)*) => {
170 u8bits!{@field $(#[$attr])* $t, $id: $f $($expr),+;}
171 u8bits!{$($rest)*}
172 };
173 // iteration, first is single bit
174 ( $(#[$attr:meta])* $id:ident: $f:ident $($expr:expr),+; $($rest:tt)*) => {
175 u8bits!{@field $(#[$attr])* $id: $f $($expr),+;}
176 u8bits!{$($rest)*}
177 };
178 () => {};
179}
180