device_register_macro/
lib.rs1#![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
9enum Address {
11 Lit(syn::Lit),
13
14 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#[derive(darling::FromDeriveInput)]
55#[darling(attributes(register))]
56struct Register {
57 addr: Address,
59
60 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#[proc_macro_derive(RORegister, attributes(register))]
81pub fn ro_register(input: TokenStream) -> TokenStream {
82 let ast: DeriveInput = syn::parse(input).unwrap();
85
86 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#[proc_macro_derive(EORegister, attributes(register))]
105pub fn eo_register(input: TokenStream) -> TokenStream {
106 let ast = syn::parse(input).unwrap();
108
109 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#[proc_macro_derive(RERegister, attributes(register))]
117pub fn re_register(input: TokenStream) -> TokenStream {
118 let ast = syn::parse(input).unwrap();
120
121 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#[proc_macro_derive(WORegister, attributes(register))]
139pub fn wo_register(input: TokenStream) -> TokenStream {
140 let ast = syn::parse(input).unwrap();
142
143 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#[proc_macro_derive(RWRegister, attributes(register))]
151pub fn rw_register(input: TokenStream) -> TokenStream {
152 let ast = syn::parse(input).unwrap();
154
155 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}