const_bitfield/
lib.rs

1#![no_std]
2#![deny(missing_docs)]
3#![feature(const_mut_refs)]
4#![feature(const_trait_impl)]
5
6//! This crate provides macros to generate bitfield-like structs with const support.
7//!
8//! Due to offering const support, this library requires the usage of Rust nightly.
9//! Additionally, you must add the following feature flags to your crate root:
10//!
11//! ```rust
12//! #![feature(const_convert)]      // optional, when using from/into conversion
13//! #![feature(const_mut_refs)]     // always required
14//! #![feature(const_trait_impl)]   // always required
15//! ```
16//!
17//! This is required as some required features are currently gated behind these flags.
18//! Further documentation about usage can be found in the individual macros.
19
20/// This macro defines a new bitfield-like `struct` backed by a single uint-like type.
21/// A variable amount of getters and or setters can be specified on a bitwise level.
22/// Every operation automatically ensures that no bounds are being violated.
23///
24/// # Example
25/// ```rust
26/// #![feature(const_mut_refs)]
27/// #![feature(const_trait_impl)]
28///
29/// use const_bitfield::bitfield;
30///
31/// bitfield! {
32///     pub struct BitField(u16);
33///     u8, field1, set_field1: 7, 0;   // u8 getter/setter for bits 0..=7
34///     bool, field2, set_field2: 8;    // bool getter/setter for bit 8
35///     bool, field3, _: 9;             // bool getter for bit 9
36///     bool, _, set_field4: 10;        // bool setter for bit 10
37///     u8, field5, _: 12, 11;          // u8 getter for bits 11..=12
38///     u8, _, set_field6: 15, 13;      // u8 setter for bits 13..=15
39/// }
40/// ```
41#[macro_export]
42macro_rules! bitfield {
43    // Generate new bitfield with getters and setters
44    ($(#[$attributes:meta])* $visibility:vis struct $name:ident($type:ty); $($fields:tt)*) => {
45        $(#[$attributes])*
46        $visibility struct $name(pub $type);
47
48        $crate::bitfield! {@impl_range struct $name($type)}
49        impl $name {
50            $crate::bitfield! {@fields @getter $($fields)*}
51            $crate::bitfield! {@fields @setter $($fields)*}
52        }
53    };
54
55    // Impl: Implement BitRange<T> and BitRangeMut<T> for struct(pub T)
56    (@impl_range struct $name:ident($type:ty)) => {
57        impl<T> const $crate::BitRange<T> for $name
58        where
59            $type: ~const $crate::BitRange<T>
60        {
61            #[inline]
62            fn bits(&self, msb: usize, lsb: usize) -> T {
63                self.0.bits(msb, lsb)
64            }
65        }
66
67        impl<T> const $crate::BitRangeMut<T> for $name
68        where
69            $type: ~const $crate::BitRange<T> + ~const $crate::BitRangeMut<T>
70        {
71            #[inline]
72            fn set_bits(&mut self, msb: usize, lsb: usize, value: T) -> &mut Self {
73                self.0.set_bits(msb, lsb, value);
74                self
75            }
76        }
77    };
78
79    // Parse Fields: Process regular fields without from/into conversion
80    (@fields @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, $getter:tt, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => {
81        $crate::bitfield! {@fields @$variant $(#[$attributes])* $visibility $type, _, _, $getter, $setter: $($exprs),*; $($rest)*}
82    };
83
84    // Parse Fields: Process fields with from conversion
85    (@fields @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, from $from:ty, $getter:tt, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => {
86        $crate::bitfield! {@fields @$variant $(#[$attributes])* $visibility $type, $from, $type, $getter, $setter: $($exprs),*; $($rest)*}
87    };
88
89    // Parse Fields: Process fields with into conversion
90    (@fields @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, into $into:ty, $getter:tt, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => {
91        $crate::bitfield! {@fields @$variant $(#[$attributes])* $visibility $type, $type, $into, $getter, $setter: $($exprs),*; $($rest)*}
92    };
93
94    // Parse Fields: Process fields with from and into conversion for same type
95    (@fields @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, from into $from_into:ty, $getter:tt, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => {
96        $crate::bitfield! {@fields @$variant $(#[$attributes])* $visibility $type, $from_into, $from_into, $getter, $setter: $($exprs),*; $($rest)*}
97    };
98
99    // Parse Fields: Process fields with from and into conversion for different types
100    (@fields @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, from $from:ty, into $into:ty, $getter:tt, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => {
101        $crate::bitfield! {@fields @$variant $(#[$attributes])* $visibility $type, $from, $into, $getter, $setter: $($exprs),*; $($rest)*}
102    };
103
104    // Fields: Process each field one-by-one by splitting list head off
105    (@fields @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, $from:tt, $into:tt, $getter:tt, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => {
106        $crate::bitfield! {@field @$variant $(#[$attributes])* $visibility $type, $from, $into, $getter, $setter: $($exprs),*}
107        $crate::bitfield! {@fields @$variant $($rest)*}
108    };
109
110    // Fields: Stop case once all fields are processed
111    (@fields @$variant:tt) => {};
112
113    // Field: Propagate field with getter and setter to individual macros
114    (@field @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, $from:tt, $into:tt, $getter:ident, $setter:ident: $($exprs:expr),*) => {
115        $crate::bitfield! {@field @$variant $(#[$attributes])* $visibility $type, $from, $into, $getter, _: $($exprs),*}
116        $crate::bitfield! {@field @$variant $(#[$attributes])* $visibility $type, $from, $into, _, $setter: $($exprs),*}
117    };
118
119    // Field Getter: Bit Range (without conversion)
120    (@field @getter $(#[$attributes:meta])* $visibility:vis $type:ty, _, _, $getter:ident, _: $msb:expr, $lsb:expr) => {
121        $(#[$attributes])*
122        $visibility const fn $getter(&self) -> $type {
123            use $crate::BitRange;
124            self.bits($msb, $lsb)
125        }
126    };
127
128    // Field Getter: Bit Range (with conversion)
129    (@field @getter $(#[$attributes:meta])* $visibility:vis $type:ty, $from:ty, $into:ty, $getter:ident, _: $msb:expr, $lsb:expr) => {
130        $(#[$attributes])*
131        $visibility const fn $getter(&self) -> $into
132            where $into: ~const ::core::convert::From<$type>
133        {
134            use $crate::BitRange;
135            let raw_value: $type = self.bits($msb, $lsb);
136            let value: $into = <$into>::from(raw_value);
137            value
138        }
139    };
140
141    // Field Getter: Single Bit (without conversion)
142    (@field @getter $(#[$attributes:meta])* $visibility:vis $type:ty, _, _, $getter:ident, _: $bit:expr) => {
143        $(#[$attributes])*
144        $visibility const fn $getter(&self) -> bool {
145            use $crate::Bit;
146            self.bit($bit)
147        }
148    };
149
150    // Field Getter: Single Bit (with conversion)
151    (@field @getter $(#[$attributes:meta])* $visibility:vis $type:ty, $from:ty, $into:ty, $getter:ident, _: $bit:expr) => {
152        $(#[$attributes])*
153        $visibility const fn $getter(&self) -> $into
154            where $into: ~const ::core::convert::From<$type>
155        {
156            use $crate::Bit;
157            let raw_value: $type = self.bit($bit);
158            let value: $into = <$into>::from(raw_value);
159            value
160        }
161    };
162
163    // Field Getter: Disabled
164    (@field @getter $(#[$attributes:meta])* $visibility:vis $type:ty, $from:tt, $into:tt, _, $setter:ident: $($exprs:expr),*) => {};
165
166    // Field Setter: Bit Range (without conversion)
167    (@field @setter $(#[$attributes:meta])* $visibility:vis $type:ty, _, _, _, $setter:ident: $msb:expr, $lsb:expr) => {
168        $(#[$attributes])*
169        $visibility const fn $setter(&mut self, value: $type) -> &mut Self {
170            use $crate::BitRangeMut;
171            self.set_bits($msb, $lsb, value)
172        }
173    };
174
175    // Field Setter: Bit Range (with conversion)
176    (@field @setter $(#[$attributes:meta])* $visibility:vis $type:ty, $from:ty, $into:ty, _, $setter:ident: $msb:expr, $lsb:expr) => {
177        $(#[$attributes])*
178        $visibility const fn $setter(&mut self, value: $from) -> &mut Self
179            where $type: ~const ::core::convert::From<$from>
180        {
181            use $crate::BitRangeMut;
182            let raw_value: $type = <$type>::from(value);
183            self.set_bits($msb, $lsb, raw_value)
184        }
185    };
186
187    // Field Setter: Single Bit (without conversion)
188    (@field @setter $(#[$attributes:meta])* $visibility:vis $type:ty, _, _, _, $setter:ident: $bit:expr) => {
189        $(#[$attributes])*
190        $visibility const fn $setter(&mut self, value: $type) -> &mut Self {
191            use $crate::BitMut;
192            self.set_bit($bit, value)
193        }
194    };
195
196    // Field Setter: Single Bit (with conversion)
197    (@field @setter $(#[$attributes:meta])* $visibility:vis $type:ty, $from:ty, $into:ty, _, $setter:ident: $bit:expr) => {
198        $(#[$attributes])*
199        $visibility const fn $setter(&mut self, value: $from) -> &mut Self
200            where $type: ~const ::core::convert::From<$from>
201        {
202            use $crate::BitMut;
203            let raw_value: $type = <$type>::from(value);
204            self.set_bit($bit, raw_value)
205        }
206    };
207
208    // Field Setter: Disabled
209    (@field @setter $(#[$attributes:meta])* $visibility:vis $type:ty, $from:tt, $into:tt, $getter:ident, _: $($exprs:expr),*) => {};
210}
211
212/// A trait to retrieve a range of bits as type `V`.
213#[const_trait]
214pub trait BitRange<V> {
215    /// Get a range of bits between `lsb..=msb` and return as type `V`.
216    fn bits(&self, msb: usize, lsb: usize) -> V;
217}
218
219/// A trait to set a range of bits with the type `V`.
220#[const_trait]
221pub trait BitRangeMut<V>: BitRange<V> {
222    /// Set a range of bits between `lsb..=msb` using value `V`.
223    fn set_bits(&mut self, msb: usize, lsb: usize, value: V) -> &mut Self;
224}
225
226/// A trait to retrieve a single bit as a boolean.
227#[const_trait]
228pub trait Bit {
229    /// Get a single bit and return as boolean. (`true` = set, `false` = clear)
230    fn bit(&self, bit: usize) -> bool;
231}
232
233/// A trait to set a single bit as a boolean.
234#[const_trait]
235pub trait BitMut: Bit {
236    /// Set a single bit using a boolean. (`true` = set, `false` = clear)
237    fn set_bit(&mut self, bit: usize, value: bool) -> &mut Self;
238}
239
240impl<T: ~ const BitRange<u8>> const Bit for T {
241    fn bit(&self, bit: usize) -> bool {
242        self.bits(bit, bit) != 0
243    }
244}
245
246impl<T: ~ const BitRange<u8> + ~ const BitRangeMut<u8>> const BitMut for T {
247    fn set_bit(&mut self, bit: usize, value: bool) -> &mut Self {
248        self.set_bits(bit, bit, value as u8)
249    }
250}
251
252macro_rules! impl_bitrange {
253    // implement given range types for each storage type
254    ($variant:tt, ($storage_type:ty, $($rest:ty),*), ($($range_type:ty),*)) => {
255        impl_bitrange! {$variant, ($storage_type), ($($range_type),*)}
256        impl_bitrange! {$variant, ($($rest),*), ($($range_type),*)}
257    };
258
259    // implement given range types for storage type
260    ($variant:tt, ($storage_type:ty), ($($range_type:ty),*)) => {
261        $(impl_bitrange! {$variant, $storage_type, $range_type})*
262    };
263
264    // implement bit range for uint-based storage type
265    (uint, $storage_type:ty, $range_type:ty) => {
266        impl const BitRange<$range_type> for $storage_type {
267            #[inline]
268            fn bits(&self, msb: usize, lsb: usize) -> $range_type {
269                // treat both range bounds as inclusive
270                let msb = msb + 1;
271
272                // determine number of bits
273                let storage_bits = ::core::mem::size_of::<$storage_type>() * 8;
274                let range_bits = ::core::mem::size_of::<$range_type>() * 8;
275
276                // check input range boundaries
277                assert!(lsb < storage_bits, "lsb is out of bounds for bit range");
278                assert!(msb <= storage_bits, "msb is out of bounds for bit range");
279                assert!(lsb <= msb, "lsb must not be greater than msb for bit range");
280                assert!((msb - lsb) <= range_bits, "value truncated in bit range operation");
281
282                // shift away unnecessary high and low bits
283                (*self << (storage_bits - msb) >> (storage_bits - msb) >> lsb) as $range_type
284            }
285        }
286
287        impl const BitRangeMut<$range_type> for $storage_type {
288            #[inline]
289            fn set_bits(&mut self, msb: usize, lsb: usize, value: $range_type) -> &mut Self {
290                // treat both range bounds as inclusive
291                let msb = msb + 1;
292
293                // determine number of bits
294                let storage_bits = ::core::mem::size_of::<$storage_type>() * 8;
295
296                // check range boundaries
297                assert!(lsb < storage_bits, "lsb is out of bounds for bit range");
298                assert!(msb <= storage_bits, "msb is out of bounds for bit range");
299                assert!(lsb < msb, "lsb must not be greater than msb for bit range");
300
301                // ensure value does not get truncated
302                let new_value = value as $storage_type;
303                let dropped_bits = storage_bits - (msb - lsb);
304                assert!(
305                    (new_value << dropped_bits >> dropped_bits) as $range_type == value,
306                    "value truncated in bit range operation"
307                );
308
309                // calculate mask for clearing bits
310                let mask = !((!0 as $storage_type) << (storage_bits - msb) >> (storage_bits - msb) >> lsb << lsb);
311
312                // clear bits and OR with new value
313                *self = (*self & mask) | (new_value << lsb);
314                self
315            }
316        }
317    };
318}
319
320impl_bitrange! {uint, (u8, u16, u32, u64, u128), (u8, u16, u32, u64, u128)}
321impl_bitrange! {uint, (u8, u16, u32, u64, u128), (i8, i16, i32, i64, i128)}