Skip to main content

register_macros/
lib.rs

1use darling::{FromMeta, ast::NestedMeta};
2use syn::{ItemStruct, parse_macro_input};
3
4use crate::register::Register;
5
6mod field;
7mod register;
8mod util;
9
10const SUPPORTED_WIDTHS: [usize; 5] = [8usize, 16usize, 32usize, 64usize, 128usize];
11
12#[derive(Debug, darling::FromMeta)]
13#[darling(and_then = verify_args)]
14struct MacroArgs {
15    size: usize,
16
17    #[darling(default = || true)]
18    read: bool,
19
20    #[darling(default = || true)]
21    write: bool,
22}
23
24fn verify_args(args: MacroArgs) -> darling::Result<MacroArgs> {
25    if !SUPPORTED_WIDTHS.contains(&args.size) {
26        return Err(darling::Error::custom(format!(
27            "Invalid size: {}, expected one of: {:?}",
28            args.size, SUPPORTED_WIDTHS
29        ))
30        .with_span(&args.size));
31    }
32
33    Ok(args)
34}
35
36/// Generate register handling code for a register definition.
37///
38/// This macro may only be used on structs, and supports only registers with the widths of 8 bits,
39/// 16 bits, 32 bits, 64 bits, or 128 bits.
40///
41/// This size *must* be declared as an attribute parameter, like so:
42/// ```ignore
43/// #[register(size = 16)]
44/// struct MyRegister {}
45/// ```
46///
47/// Fields may be declared in a similar syntax to the fields of a normal struct. They must define,
48/// as attributes, the least significant bit (lsb) and most significant bit (msb). They must also
49/// specify their sign via the "type" of the field. This type must either be "u" for unsigned or
50/// "i" for signed. They may also optionally specify whether or not that field may be read or
51/// written to, defaulting to true.
52///
53/// ```ignore
54/// #[register(size = 16)]
55/// struct MyRegister {
56///     // Readable, writable, unsigned
57///     #[field(lsb = 0, msb = 7)]
58///     lower: u,
59///
60///     // Readable, signed
61///     #[field(lsb = 8, msb = 15, write = false)]
62///     upper: i,
63/// }
64///
65/// let mut reg = MyRegister::new(0x04AD);
66/// assert_eq!(reg.get_lower(), 0xAD);
67/// assert_eq!(reg.get_upper(), 4);
68/// assert!(reg.set_lower(-4).is_ok());
69/// assert_eq!(reg.get_lower(), -4);
70/// ```
71#[proc_macro_attribute]
72pub fn register(
73    _attr: proc_macro::TokenStream,
74    item: proc_macro::TokenStream,
75) -> proc_macro::TokenStream {
76    let nested_meta = match NestedMeta::parse_meta_list(_attr.into()) {
77        Ok(v) => v,
78        Err(e) => return e.to_compile_error().into(),
79    };
80    let macro_args = match MacroArgs::from_list(&nested_meta) {
81        Ok(v) => v,
82        Err(e) => return e.write_errors().into(),
83    };
84    let strct = parse_macro_input!(item as ItemStruct);
85    let reg = Register::new(strct, macro_args);
86    reg.implement().into()
87}