device_register_macro/
lib.rs

1#![doc = include_str!("../README.md")]
2#![deny(unsafe_code, missing_docs)]
3
4use darling::{FromDeriveInput, FromMeta, ToTokens};
5use proc_macro::TokenStream;
6use quote::quote;
7use syn::DeriveInput;
8
9/// The valid values of an address
10enum Address {
11    /// A literal (float, int, bytestring, etc)
12    Lit(syn::Lit),
13
14    /// A path to support enums
15    Pat(syn::Pat),
16}
17
18impl ToTokens for Address {
19    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
20        match self {
21            Address::Lit(val) => val.to_tokens(tokens),
22            Address::Pat(val) => val.to_tokens(tokens),
23        }
24    }
25}
26impl FromMeta for Address {
27    fn from_meta(item: &syn::Meta) -> darling::Result<Self> {
28        match item {
29            syn::Meta::Path(_) => Self::from_word(),
30            syn::Meta::List(ref value) => Self::from_list(
31                &value
32                    .nested
33                    .iter()
34                    .cloned()
35                    .collect::<Vec<syn::NestedMeta>>()[..],
36            ),
37            syn::Meta::NameValue(ref value) => Self::from_value(&value.lit),
38        }
39        .map_err(|e| e.with_span(item))
40    }
41
42    fn from_value(value: &syn::Lit) -> darling::Result<Self> {
43        match value {
44            syn::Lit::Str(str) => {
45                let pattern: syn::Pat = str.parse()?;
46                Ok(Address::Pat(pattern))
47            }
48            val => Ok(Address::Lit(val.clone())),
49        }
50    }
51}
52
53/// The arguments passed to the register helper attribute
54#[derive(darling::FromDeriveInput)]
55#[darling(attributes(register))]
56struct Register {
57    /// The value of the address
58    addr: Address,
59
60    /// The type of the address, defaults to a u8
61    ty: Option<syn::Type>,
62}
63
64fn impl_register(ast: &syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
65    let name = &ast.ident;
66    let reg = Register::from_derive_input(ast)?;
67    let addr = reg.addr;
68    let ty = reg.ty.unwrap_or_else(|| syn::parse_str("u8").unwrap());
69    let (impl_gen, type_gen, where_gen) = &ast.generics.split_for_impl();
70    Ok(quote! {
71        #[allow(dead_code)]
72        impl #impl_gen device_register::Register for #name #type_gen #where_gen {
73            type Address = #ty;
74            const ADDRESS: Self::Address = #addr;
75        }
76    })
77}
78
79/// Create a read only register
80#[proc_macro_derive(RORegister, attributes(register))]
81pub fn ro_register(input: TokenStream) -> TokenStream {
82    // Parse the representation
83    // let args = parse_macro_input!(input as AttributeArgs);
84    let ast: DeriveInput = syn::parse(input).unwrap();
85
86    // Build the impl
87
88    let mut output = impl_register(&ast).unwrap_or_else(syn::Error::into_compile_error);
89    output.extend(impl_ro_register(&ast));
90    output.into()
91}
92
93fn impl_ro_register(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
94    let name = &ast.ident;
95    let (impl_gen, type_gen, where_gen) = &ast.generics.split_for_impl();
96
97    quote! {
98        #[allow(dead_code)]
99        impl #impl_gen device_register::ReadableRegister for #name #type_gen #where_gen{}
100    }
101}
102
103/// Create an edit only register
104#[proc_macro_derive(EORegister, attributes(register))]
105pub fn eo_register(input: TokenStream) -> TokenStream {
106    // Parse the representation
107    let ast = syn::parse(input).unwrap();
108
109    // Build the impl
110    let mut output = impl_register(&ast).unwrap_or_else(syn::Error::into_compile_error);
111    output.extend(impl_eo_register(&ast));
112    output.into()
113}
114
115/// Create a read/edit register
116#[proc_macro_derive(RERegister, attributes(register))]
117pub fn re_register(input: TokenStream) -> TokenStream {
118    // Parse the representation
119    let ast = syn::parse(input).unwrap();
120
121    // Build the impl
122    let mut output = impl_register(&ast).unwrap_or_else(syn::Error::into_compile_error);
123    output.extend(impl_ro_register(&ast));
124    output.extend(impl_eo_register(&ast));
125    output.into()
126}
127
128fn impl_eo_register(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
129    let name = &ast.ident;
130    let (impl_gen, type_gen, where_gen) = &ast.generics.split_for_impl();
131    quote! {
132        #[allow(dead_code)]
133        impl #impl_gen device_register::EditableRegister for #name #type_gen #where_gen {}
134    }
135}
136
137/// Create a write only register
138#[proc_macro_derive(WORegister, attributes(register))]
139pub fn wo_register(input: TokenStream) -> TokenStream {
140    // Parse the representation
141    let ast = syn::parse(input).unwrap();
142
143    // Build the impl
144    let mut output = impl_register(&ast).unwrap_or_else(syn::Error::into_compile_error);
145    output.extend(impl_wo_register(&ast));
146    output.into()
147}
148
149/// Create a read/write register
150#[proc_macro_derive(RWRegister, attributes(register))]
151pub fn rw_register(input: TokenStream) -> TokenStream {
152    // Parse the representation
153    let ast = syn::parse(input).unwrap();
154
155    // Build the impl
156    let mut output = impl_register(&ast).unwrap_or_else(syn::Error::into_compile_error);
157    output.extend(impl_ro_register(&ast));
158    output.extend(impl_eo_register(&ast));
159    output.extend(impl_wo_register(&ast));
160    output.into()
161}
162
163fn impl_wo_register(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
164    let name = &ast.ident;
165    let (impl_gen, type_gen, where_gen) = &ast.generics.split_for_impl();
166    quote! {
167        #[allow(dead_code)]
168        impl #impl_gen device_register::WritableRegister for #name #type_gen #where_gen {}
169    }
170}