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