1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#![no_std]
#![deny(
    missing_docs,
    unused_extern_crates,
    unused_import_braces,
    unused_qualifications
)]

//! A macro to generate bit field like getters and setters on structs which
//! represent an array of bytes.
//!
//!  See the documentation of the macro for how to use it.

pub use paste;

/// Set the given 'value' in byte 'b' in the range of the given bit positions
/// 'lsb' (least significant bit) and 'msb' (most significant bit) inclusive.
/// the other bits are not touched.
pub fn set_bit_range(b: &mut u8, lsb: u8, msb: u8, value: u8) {
    let mask: u8 = !0u8 << (7 - msb) >> (7 - msb + lsb) << lsb;
    *b &= !mask;
    *b |= (value << lsb) & mask;
}
/// Return the 'value' of byte 'b' in the range of the given bit positions
/// 'lsb' (least significant bit) and 'msb' (most significant bit) inclusive.
pub fn get_bit_range(b: &u8, lsb: u8, msb: u8) -> u8 {
    let mask: u8 = !0u8 << (7 - msb) >> (7 - msb + lsb) << lsb;
    (*b & mask) >> lsb
}
/// Set the bit at position 'pos' of byte 'b'.  
pub fn set_bit(b: &mut u8, pos: u8, value: bool) {
    let mask: u8 = !1u8 << pos;
    *b &= !mask; if value { *b |= mask; }
}
/// Get the bit at position 'pos' of byte 'b'.
pub fn get_bit(b: &u8, pos: u8) -> bool {
    let mask: u8 = !1u8 << pos;
    (*b & mask) == mask
}


/// This macro allows the generaion of bit field like getters
/// and setters for a New Type struct of type [u8;N].
/// There are bit wise accessors and bit range accessors.
/// The bitwise operations map to an boolean value whereas the
/// bit range operations use an provided type which has to implement
/// the .into() conversion trait. 
/// The bit wise field declaration is as follows:
///
/// * Optional attributes (`#[...]`), documentation comments (`///`) are attributes; 
/// * the identifier, which will be suffixed by 'set_' and / or 'get_'
/// * A colon
/// * an 'r' or 'w' or 'rw' flag which indicates which accessor are created
///   (read->get,write->set or both)
/// * the byte number followed by a comma
/// * the bit number
///
/// The bit range operations are as follows:
/// 
/// * Optional attributes (`#[...]`), documentation comments (`///`) are attributes; 
/// * An type, which has to provide the core conversion Into<u8> trait, followed by a comma
/// * the identifier, which will be suffixed by 'set_' and / or 'get_'
/// * A colon
/// * an 'r' or 'w' or 'rw' flag which indicates which accessor are created
///   (read->get,write->set or both)
/// * the byte number followed by a comma
/// * the lsb (least significant) bit number
/// * the msb (most significant) bit number inclusive
///
/// So a typical declaration might look like:  
/// ```rust
/// use u8bits::u8bits;
///
/// struct Bytes( [u8;2]);
/// impl Bytes {
///    u8bits! {
///        /// foo is bit 4 of byte 0
///        foo: rw 0,4;
///        /// bar are bits 0..3 of byte 1
///        u8, bar: rw 1,0,3;
///    }
/// }
/// 
/// ```
/// which will expand to:
/// ```rust
/// struct Bytes([u8; 2]);
///     impl Bytes {
///         #[inline]
///         #[doc = r" foo is bit 4 of byte 0"]
///         pub fn get_foo(&self) -> bool { ::u8bits::get_bit(&self.0[0], 4) }
///         #[inline]
///         #[doc = r" foo is bit 4 of byte 0"]
///         pub fn set_foo(&mut self, value: bool) {
///             ::u8bits::set_bit(&mut self.0[0], 4, value)
///         }
///         #[inline]
///         #[doc = r" bar are bits 0..3 of byte 1"]
///         pub fn get_bar(&self) -> u8 {
///             ::u8bits::get_bit_range(&self.0[1], 0, 3).into()
///         }
///         #[inline]
///         #[doc = r" bar are bits 0..3 of byte 1"]
///         pub fn set_bar(&mut self, value: u8) {
///             ::u8bits::set_bit_range(&mut self.0[1], 0, 3, value.into())
///         }
///     }
/// ```
///
/// For the use of bitfield like enums see for example the
/// [surjective-enum](https://crates.io/crates/surjective-enum)
/// crate or the test of this crate. 
#[macro_export]
macro_rules! u8bits {
    // bit range write
    (@field $(#[$attr:meta])* $t:ty, $id:ident:
     w $byte:expr, $lsb:expr, $msb:expr;) => {
        paste::item! {
            #[inline]
            $(#[$attr])*
            pub fn [<set_ $id>](&mut self, value: $t) {
                ::u8bits::set_bit_range(&mut self.0[$byte], $lsb, $msb, value.into())
            }
        }
    };
    // bit range read, returns $t
    (@field $(#[$attr:meta])* $t:ty, $id:ident:
     r $byte:expr, $lsb:expr, $msb:expr;) => {
        paste::item! {
            #[inline]
            $(#[$attr])*
            pub fn [<get_ $id>](&self) -> $t {
                ::u8bits::get_bit_range(&self.0[$byte], $lsb, $msb).into()
            }
        }
    };
    // bit range read and write
    (@field $(#[$attr:meta])* $t:ty, $id:ident:
     rw $byte:expr, $lsb:expr, $msb:expr;) => {
        u8bits!{@field $(#[$attr])* $t, $id: r $byte, $lsb, $msb;}
        u8bits!{@field $(#[$attr])* $t, $id: w $byte, $lsb, $msb;}
    };
    // single bit, write
    (@field $(#[$attr:meta])* $id:ident: w $byte:expr, $bit:expr;) => {
        paste::item! {
            #[inline]
            $(#[$attr])* 
            pub fn [<set_ $id>](&mut self, value: bool) {
                ::u8bits::set_bit(&mut self.0[$byte], $bit, value)
            }
        }
    };
    // single bit, read
    (@field $(#[$attr:meta])* $id:ident: r $byte:expr, $bit:expr;) => {
        paste::item! {
            #[inline]
            $(#[$attr])*
            pub fn [<get_ $id>](&self) -> bool {
                ::u8bits::get_bit(&self.0[$byte], $bit)
            }
        }
    };
    // single bit, read and write
    (@field $(#[$attr:meta])* $id:ident: rw $byte:expr, $bit:expr;) => {
        u8bits!{@field $(#[$attr])* $id: r $byte, $bit;}
        u8bits!{@field $(#[$attr])* $id: w $byte, $bit;}
    };
    // iteration, first is bit range
    ( $(#[$attr:meta])* $t:ty, $id:ident: $f:ident $($expr:expr),+; $($rest:tt)*) => {
        u8bits!{@field $(#[$attr])* $t, $id: $f $($expr),+;}
        u8bits!{$($rest)*}
    };
    // iteration, first is single bit
    ( $(#[$attr:meta])* $id:ident: $f:ident $($expr:expr),+; $($rest:tt)*) => {
        u8bits!{@field $(#[$attr])* $id: $f $($expr),+;}
        u8bits!{$($rest)*}
    };
    () => {};
}