modular_bitfield_impl/lib.rs
1#![recursion_limit = "256"]
2#![forbid(unsafe_code)]
3
4extern crate proc_macro;
5
6#[macro_use]
7mod errors;
8mod bitfield;
9mod bitfield_specifier;
10mod define_specifiers;
11
12use proc_macro::TokenStream;
13
14/// Generates the `B1`, `B2`, ..., `B128` bitfield specifiers.
15///
16/// Only of use witihn the `modular_bitfield` crate itself.
17#[proc_macro]
18pub fn define_specifiers(input: TokenStream) -> TokenStream {
19 define_specifiers::generate(input.into()).into()
20}
21
22/// Applicable to structs to turn their fields into compact bitfields.
23///
24/// # Generated API
25///
26/// By default this generates the following API:
27///
28/// - **Constructors:**
29///
30/// 1. `new()`: Initializes all bits to 0 even if 0 bits may be invalid.
31/// Note that invalid bit patterns are supported in that getters and setters will
32/// be protecting accesses.
33///
34/// - **Getters:**
35///
36/// For every field `f` we generate the following getters:
37///
38/// 1. `f()`: Returns the value of `f` and might panic
39/// if the value contains an invalid bit pattern.
40/// 2. `f_or_err()`: Returns the value of `f` or an error
41/// if the value contains an invalid bit pattern.
42///
43/// - **Setters:**
44///
45/// For every field `f` we generate the following setters:
46///
47/// 1. `set_f(new_value)`: Sets the value of `f` to `new_value` and might panic
48/// if `new_value` is out of bounds for the bit width of `f`.
49/// 2. `set_f_checked(new_value)`: Sets the value of `f` to `new` or returns an error
50/// if `new_value` if out of bounds for the bit width of `f`.
51/// 3. `with_f(new_value)`: Similar to `set_f` but consumes and returns `Self`.
52/// Primarily useful for method chaining.
53/// 4. `with_f_checked(new_value)`: Similar to `set_f_checked` but consumes and returns `Self`.
54/// Primarily useful for method chaining.
55///
56/// - **Conversions:**
57///
58/// - `from_bytes(bytes)`: Allows to constructor the bitfield type from a fixed array of bytes.
59/// - `into_bytes()`: Allows to convert the bitfield into its underlying byte representation.
60///
61/// # Parameters
62///
63/// The following parameters for the `#[bitfield]` macro are supported:
64///
65/// ## Parameter: `bytes = N`
66///
67/// This ensures at compilation time that the resulting `#[bitfield]` struct consists of
68/// exactly `N` bytes. Yield a compilation error if this does not hold true.
69///
70/// ### Example
71///
72/// ```
73/// # use modular_bitfield::prelude::*;
74/// #[bitfield(bytes = 2)]
75/// pub struct SingedInt {
76/// sign: bool, // 1 bit
77/// value: B15, // 15 bits
78/// }
79/// ```
80///
81/// ## Parameter: `filled: bool`
82///
83/// If `filled` is `true` ensures that the `#[bitfield]` struct defines all bits and
84/// therefore has a bitwidth that is divisible by 8. If `filled` is `false` ensures the
85/// exact opposite.
86///
87/// The default value is: `true`
88///
89/// ### Example
90///
91/// ```
92/// # use modular_bitfield::prelude::*;
93/// #[bitfield(filled = false)]
94/// pub struct Package {
95/// is_received: bool, // 1 bit
96/// is_alive: bool, // 1 bit
97/// status: B2, // 2 bits
98/// }
99/// ```
100///
101/// ## Parameter: `bits = N`
102///
103/// With the `bits: int` parameter it is possible to control the targeted bit width of
104/// a `#[bitfield]` annoated struct. Using `bits = N` guarantees that the resulting bitfield
105/// struct will have a bit width of exactly `N`.
106///
107/// ### Example 1
108///
109/// ```
110/// # use modular_bitfield::prelude::*;
111/// #[bitfield(bits = 16)]
112/// pub struct Package {
113/// is_received: bool, // 1 bit
114/// is_alive: bool, // 1 bit
115/// status: B14, // 14 bits
116/// }
117/// ```
118///
119/// ### Example 2
120///
121/// The `bits: int` parameter is especially useful when using this in conjunction with
122/// `#[derive(BitfieldSpecifier)] and `filled = false` as shown in the below example.
123///
124/// ```
125/// # use modular_bitfield::prelude::*;
126/// #[bitfield(bits = 5)]
127/// #[derive(BitfieldSpecifier)]
128/// pub struct Package {
129/// is_received: bool, // 1 bit
130/// is_alive: bool, // 1 bit
131/// status: B3, // 3 bits
132/// }
133/// ```
134///
135/// ## Field Parameter: `#[bits = N]`
136///
137/// To ensure at compile time that a field of a `#[bitfield]` struct has a bit width of exactly
138/// `N` a user may add `#[bits = N]` to the field in question.
139///
140/// ### Example
141///
142/// ```
143/// # use modular_bitfield::prelude::*;
144/// # #[bitfield(filled = false)]
145/// # #[derive(BitfieldSpecifier)]
146/// # pub struct Header {
147/// # is_received: bool, // 1 bit
148/// # is_alive: bool, // 1 bit
149/// # status: B2, // 2 bits
150/// # }
151/// #[bitfield]
152/// pub struct Base {
153/// #[bits = 4]
154/// header: Header, // 4 bits
155/// content: B28, // 28 bits
156/// }
157/// ```
158///
159/// ## Field Parameter: `#[skip(..)]`
160///
161/// It is possible to skip the entire code generation for getters or setters with the `#[skip]`
162/// field attribute.
163/// This is useful if a field just needs to be read or written exclusively. Skipping both
164/// setters and getters is useful if you want to have undefined blocks within your bitfields.
165///
166/// ### Example
167///
168/// ```
169/// # use modular_bitfield::prelude::*;
170/// #[bitfield]
171/// pub struct Sparse {
172/// #[skip(getters)]
173/// no_getters: B4,
174/// #[skip(setters)]
175/// no_setters: B4,
176/// #[skip]
177/// skipped_entirely: B4,
178/// #[skip(getters, setters)]
179/// skipped_entirely_2: B2,
180/// #[skip(getters)] #[skip(setters)]
181/// skipped_entirely_2: B2,
182/// }
183/// ```
184///
185/// ### Trick: Wildcards
186///
187/// If you are completely uninterested in a field of a bitfield, for example when specifying
188/// some undefined bits in your bitfield you can use double wildcards as their names:
189///
190/// ```
191/// # use modular_bitfield::prelude::*;
192/// #[bitfield]
193/// pub struct Sparse {
194/// #[skip] __: B10,
195/// a: bool,
196/// #[skip] __: B10,
197/// b: bool,
198/// #[skip] __: B10,
199/// }
200/// ```
201///
202/// # Features
203///
204/// ## Support: `#[derive(BitfieldSpecifier)]`
205///
206/// If a `#[bitfield]` struct is annotated with a `#[derive(BitfieldSpecifier)]` attribute
207/// an implementation of the `Specifier` trait will be generated for it. This has the effect
208/// that the bitfield struct itself can be used as the type of a field of another bitfield type.
209///
210/// This feature is limited to bitfield types that have a total bit width of 128 bit or fewer.
211/// This restriction is ensured at compile time.
212///
213/// ### Example
214///
215/// ```
216/// # use modular_bitfield::prelude::*;
217/// #[bitfield(filled = false)]
218/// #[derive(BitfieldSpecifier)]
219/// pub struct Header {
220/// is_received: bool, // 1 bit
221/// is_alive: bool, // 1 bit
222/// status: B2, // 2 bits
223/// }
224/// ```
225///
226/// Now the above `Header` bitfield type can be used in yet another `#[bitfield]` annotated type:
227///
228/// ```
229/// # use modular_bitfield::prelude::*;
230/// # #[bitfield(filled = false)]
231/// # #[derive(BitfieldSpecifier)]
232/// # pub struct Header {
233/// # is_received: bool, // 1 bit
234/// # is_alive: bool, // 1 bit
235/// # status: B2, // 2 bits
236/// # }
237/// #[bitfield]
238/// pub struct Base {
239/// header: Header, // 4 bits
240/// content: B28, // 28 bits
241/// }
242/// ```
243///
244/// ## Support: `#[derive(Debug)]`
245///
246/// If a `#[derive(Debug)]` is found by the `#[bitfield]` a naturally formatting implementation
247/// is going to be generated that clearly displays all the fields and their values as the user
248/// would expect.
249/// Also invalid bit patterns for fields are clearly displayed under this implementation.
250///
251/// ### Example
252///
253/// ```
254/// # use modular_bitfield::prelude::*;
255/// #[bitfield]
256/// #[derive(Debug)]
257/// pub struct Package {
258/// is_received: bool, // 1 bit
259/// is_alive: bool, // 1 bit
260/// status: B6, // 6 bits
261/// }
262///
263/// let package = Package::new()
264/// .with_is_received(false)
265/// .with_is_alive(true)
266/// .with_status(3);
267/// println!("{:?}", package);
268/// assert_eq!(
269/// format!("{:?}", package),
270/// "Package { is_received: false, is_alive: true, status: 3 }",
271/// );
272/// ```
273///
274/// ## Support: `#[repr(uN)]`
275///
276/// It is possible to additionally annotate a `#[bitfield]` annotated struct with `#[repr(uN)]`
277/// where `uN` is one of `u8`, `u16`, `u32`, `u64` or `u128` in order to make it conveniently
278/// interchangeable with such an unsigned integer value.
279///
280/// As an effect to the user this implements `From` implementations between the chosen primitive
281/// and the bitfield as well as ensuring at compile time that the bit width of the bitfield struct
282/// matches the bit width of the primitive.
283///
284/// ### Example
285///
286/// ```
287/// # use modular_bitfield::prelude::*;
288/// #[bitfield]
289/// #[repr(u16)]
290/// pub struct SignedU16 {
291/// sign: bool, // 1 bit
292/// abs_value: B15, // 15 bits
293/// }
294///
295/// let sint = SignedU16::from(0b0111_0001);
296/// assert_eq!(sint.sign(), true);
297/// assert_eq!(sint.abs_value(), 0b0011_1000);
298/// assert_eq!(u16::from(sint), 0b0111_0001_u16);
299/// ```
300#[proc_macro_attribute]
301pub fn bitfield(args: TokenStream, input: TokenStream) -> TokenStream {
302 bitfield::analyse_and_expand(args.into(), input.into()).into()
303}
304
305/// Derive macro for Rust `enums` to implement `Specifier` trait.
306///
307/// This allows such an enum to be used as a field of a `#[bitfield]` struct.
308/// The annotated enum must not have any variants with associated data and
309/// by default must have a number of variants that is equal to the power of 2.
310///
311/// If a user wants to circumvent the latter restriction they can add
312/// `#[bits = N]` below the `#[derive(BitfieldSpecifier)]` line in order to
313/// signal to the code generation that the enum may have a relaxed number
314/// of variants.
315///
316/// # Example
317///
318/// ## Example: Basic Usage
319///
320/// In the following we define a `MaybeWeekday` enum that lists all weekdays
321/// as well as an invalid day so that we have a power-of-two number of variants.
322///
323/// ```
324/// use modular_bitfield::prelude::*;
325///
326/// #[derive(BitfieldSpecifier)]
327/// pub enum Weekday {
328/// Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday, None
329/// }
330/// ```
331///
332/// ## Example: `#[bits = N]`
333///
334/// If we want to get rid of the `None` variant we need to add `#[bits = 3]`:
335///
336/// ```
337/// # use modular_bitfield::prelude::*;
338/// #
339/// #[derive(BitfieldSpecifier)]
340/// #[bits = 3]
341/// pub enum Weekday {
342/// Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
343/// }
344/// ```
345///
346/// ## Example: Discriminants
347///
348/// It is possible to explicitly assign discriminants to some of the days.
349/// In our case this is useful since our week starts at sunday:
350///
351/// ```
352/// # use modular_bitfield::prelude::*;
353/// #
354/// #[derive(BitfieldSpecifier)]
355/// #[bits = 3]
356/// pub enum Weekday {
357/// Monday = 1,
358/// Tuesday = 2,
359/// Wednesday = 3,
360/// Thursday = 4,
361/// Friday = 5,
362/// Saturday = 6,
363/// Sunday = 0,
364/// }
365/// ```
366///
367/// ## Example: Use in `#[bitfield]`
368///
369/// Given the above `Weekday` enum that starts at `Sunday` and uses 3 bits in total
370/// we can now use it in a `#[bitfield]` annotated struct as follows:
371///
372/// ```
373/// # use modular_bitfield::prelude::*;
374/// #
375/// # #[derive(BitfieldSpecifier)]
376/// # #[bits = 3]
377/// # pub enum Weekday {
378/// # Monday = 1,
379/// # Tuesday = 2,
380/// # Wednesday = 3,
381/// # Thursday = 4,
382/// # Friday = 5,
383/// # Saturday = 6,
384/// # Sunday = 0,
385/// # }
386/// #[bitfield]
387/// pub struct MeetingTimeSlot {
388/// day: Weekday,
389/// from: B6,
390/// to: B6,
391/// expired: bool,
392/// }
393/// ```
394///
395/// The above `MeetingTimeSlot` uses exactly 16 bits and defines our `Weekday` enum as
396/// compact `day` bitfield. The `from` and `to` require 6 bits each and finally the
397/// `expired` flag requires a single bit.
398///
399/// ## Example: Interacting
400///
401/// A user can interact with the above `MeetingTimeSlot` and `Weekday` definitions in
402/// the following ways:
403///
404/// ```
405/// # use modular_bitfield::prelude::*;
406/// #
407/// # #[derive(BitfieldSpecifier, Debug, PartialEq)]
408/// # #[bits = 3]
409/// # pub enum Weekday {
410/// # Monday = 1,
411/// # Tuesday = 2,
412/// # Wednesday = 3,
413/// # Thursday = 4,
414/// # Friday = 5,
415/// # Saturday = 6,
416/// # Sunday = 0,
417/// # }
418/// # #[bitfield]
419/// # pub struct MeetingTimeSlot {
420/// # day: Weekday,
421/// # from: B6,
422/// # to: B6,
423/// # expired: bool,
424/// # }
425/// #
426/// let mut slot = MeetingTimeSlot::new()
427/// .with_day(Weekday::Friday)
428/// .with_from(14) // 14:00 CEST
429/// .with_to(15); // 15:00 CEST
430/// assert_eq!(slot.day(), Weekday::Friday);
431/// assert_eq!(slot.from(), 14);
432/// assert_eq!(slot.to(), 15);
433/// assert!(!slot.expired());
434/// ```
435#[proc_macro_derive(BitfieldSpecifier, attributes(bits))]
436pub fn bitfield_specifier(input: TokenStream) -> TokenStream {
437 bitfield_specifier::generate(input.into()).into()
438}