serial_sensors_proto_derive/
lib.rs

1extern crate proc_macro;
2
3use darling::ast::Fields;
4use darling::{FromDeriveInput, FromMeta, FromVariant};
5use proc_macro::TokenStream;
6use quote::{format_ident, quote};
7use std::collections::HashSet;
8use syn::{parse_macro_input, DeriveInput, Field, Path, Type};
9
10#[derive(Debug, FromMeta)]
11struct SensorAttributes {
12    id: u8,
13    data: Path,
14    components: u8,
15}
16
17#[derive(Debug, FromVariant)]
18#[darling(attributes(sensor))]
19struct Version1DataVariant {
20    ident: syn::Ident,
21    fields: Fields<Field>,
22    #[darling(flatten)]
23    sensor: SensorAttributes,
24}
25
26#[derive(Debug, FromDeriveInput)]
27#[darling(attributes(sensor), supports(enum_newtype))]
28struct Version1Data {
29    ident: syn::Ident,
30    data: darling::ast::Data<Version1DataVariant, darling::util::Ignored>,
31}
32
33#[proc_macro_derive(SerialSensors, attributes(sensor))]
34pub fn derive_serial_sensors(input: TokenStream) -> TokenStream {
35    let input = parse_macro_input!(input as DeriveInput);
36    let version1_data = Version1Data::from_derive_input(&input).expect("Failed to parse input");
37
38    let name = &version1_data.ident;
39
40    let mut sensor_match_arms = Vec::new();
41    let mut field_match_arms = Vec::new();
42    let mut num_components_match_arms = Vec::new();
43    let mut from_impls = Vec::new();
44    let mut encode_match_arms = Vec::new();
45    let mut decode_match_arms = Vec::new();
46    let mut components_lookup_match_arms = Vec::new();
47    let mut sensor_ids_variants = Vec::new();
48
49    let mut sensor_types = HashSet::new();
50    let mut duplicate_error = None;
51
52    if let darling::ast::Data::Enum(variants) = &version1_data.data {
53        for variant in variants {
54            let variant_name = &variant.ident;
55            let sensor_type = &variant.sensor.id;
56            let field_type = &variant.sensor.data;
57            let num_components = variant.sensor.components;
58
59            let variant_name_str = variant_name.to_string();
60
61            if !sensor_types.insert(sensor_type) {
62                duplicate_error = Some(quote! {
63                    compile_error!(concat!("Duplicate sensor type found (", #sensor_type, ") at ", #variant_name_str));
64                });
65                break;
66            }
67
68            // Extract the type of the variant's field
69            let variant_field_type = &variant.fields.fields[0].ty;
70
71            from_impls.push(quote! {
72                impl crate::CompileTimeTypeInformation for #variant_field_type {
73                    const TYPE_ID: u8 = #sensor_type;
74                    const VALUE_TYPE: crate::ValueType = #field_type;
75                    const NUM_COMPONENTS: u8 = #num_components;
76                }
77
78                impl core::convert::From< #variant_field_type > for #name {
79                    fn from(value: #variant_field_type) -> #name {
80                        #name :: #variant_name ( value )
81                    }
82                }
83
84                impl TryFrom< #name > for #variant_field_type {
85                    type Error = ();
86
87                    fn try_from(value: #name) -> Result<#variant_field_type, Self::Error> {
88                        match value {
89                            #name :: #variant_name (value) => Ok(value),
90                            _ => Err(())
91                        }
92                    }
93                }
94            });
95
96            sensor_match_arms.push(quote! {
97                #name::#variant_name(_) => #sensor_type,
98            });
99
100            field_match_arms.push(quote! {
101                #name::#variant_name(_) => #field_type,
102            });
103
104            num_components_match_arms.push(quote! {
105                #name::#variant_name(_) => #num_components,
106            });
107
108            encode_match_arms.push(quote! {
109                #name::#variant_name(value) => ::bincode::Encode::encode(&value, encoder)?,
110            });
111
112            decode_match_arms.push(quote! {
113                (#sensor_type, #field_type) => {
114                    let value: #variant_field_type = ::bincode::Decode::decode(decoder)?;
115                    Ok(#name :: #variant_name ( value ))
116                }
117            });
118
119            components_lookup_match_arms.push(quote! {
120                (#sensor_type, #field_type) => Ok(#num_components),
121            });
122
123            let upper_variant = format_ident!("{}", variant_name.to_string().to_uppercase());
124
125            let type_name_str = name.to_string();
126            let name = quote! { concat!{ "[`", #type_name_str, "::", #variant_name_str, "`]" } };
127            sensor_ids_variants.push(quote! {
128                /// [`SensorId`] const for the
129                #[doc = #name ]
130                /// type.
131                pub const #upper_variant : SensorId = SensorId(0x00, #sensor_type, #field_type);
132            });
133        }
134    }
135
136    let expanded = if let Some(error) = duplicate_error {
137        error
138    } else {
139        quote! {
140            impl #name {
141                /// Provides the sensor type ID.
142                pub const fn sensor_type_id(&self) -> u8 {
143                    match self {
144                        #( #sensor_match_arms )*
145                    }
146                }
147
148                /// Provides the value type.
149                pub const fn value_type(&self) -> crate::ValueType {
150                    match self {
151                        #( #field_match_arms )*
152                    }
153                }
154
155                /// Provides the number of components of the data type.
156                pub const fn num_components(&self) -> u8 {
157                    match self {
158                        #( #num_components_match_arms )*
159                    }
160                }
161
162                /// Provides the number of components of the data type.
163                pub const fn components(sensor_id: u8, value_type: crate::ValueType) -> Result<u8, crate::ComponentLookupError> {
164                    match (sensor_id, value_type) {
165                        #( #components_lookup_match_arms )*
166                        _ => Err(ComponentLookupError::UnknownType)
167                    }
168                }
169            }
170
171            impl crate::RuntimeTypeInformation for #name {
172                fn sensor_type_id(&self) -> u8 {
173                    match self {
174                        #( #sensor_match_arms )*
175                    }
176                }
177
178                fn value_type(&self) -> crate::ValueType {
179                    match self {
180                        #( #field_match_arms )*
181                    }
182                }
183
184                fn num_components(&self) -> u8 {
185                    match self {
186                        #( #num_components_match_arms )*
187                    }
188                }
189            }
190
191            /// Provides generic [`SensorId`] implementations.
192            pub struct SensorIds;
193
194            impl SensorIds {
195                #( #sensor_ids_variants )*
196            }
197
198            #( #from_impls )*
199
200            impl ::bincode::Encode for #name {
201                fn encode<__E: ::bincode::enc::Encoder>(
202                    &self,
203                    encoder: &mut __E,
204                ) -> core::result::Result<(), ::bincode::error::EncodeError> {
205                    use crate::RuntimeTypeInformation;
206                    bincode::Encode::encode(&self.sensor_type_id(), encoder)?;
207                    bincode::Encode::encode(&(self.value_type() as u8), encoder)?;
208                    // don't encode the component count; sensor ID and type are enough
209                    match self {
210                        #( #encode_match_arms )*
211                    }
212                    Ok(())
213                }
214            }
215
216            impl ::bincode::Decode for #name {
217                fn decode<__D: bincode::de::Decoder>(
218                    decoder: &mut __D,
219                ) -> Result<Self, ::bincode::error::DecodeError> {
220                    let type_id: u8 = bincode::Decode::decode(decoder)?;
221                    let value_type: u8 = bincode::Decode::decode(decoder)?;
222                    let value_type = crate::ValueType::try_from(value_type).map_err(|_| ::bincode::error::DecodeError::Other("An unknown combination of type ID and value type was detected"))?;
223                    match (type_id, value_type) {
224                        #( #decode_match_arms )*,
225                        _ => Err(::bincode::error::DecodeError::Other("An unknown combination of type ID and value type was detected"))
226                    }
227                }
228            }
229        }
230    };
231
232    TokenStream::from(expanded)
233}
234
235#[derive(Debug, FromDeriveInput)]
236#[darling(attributes(sensor), supports(struct_newtype))]
237struct SensorDataType {
238    ident: syn::Ident,
239    data: darling::ast::Data<darling::util::Ignored, Type>,
240}
241
242#[proc_macro_derive(SensorDataType)]
243pub fn derive_sensor_data_type(input: TokenStream) -> TokenStream {
244    let input = parse_macro_input!(input as DeriveInput);
245    let data = SensorDataType::from_derive_input(&input).expect("Failed to parse input");
246
247    let name = &data.ident;
248    let expanded = if let darling::ast::Data::Struct(fields) = &data.data {
249        let field = &fields.fields[0];
250        quote! {
251            impl #name {
252                /// Constructs a new instance of the [`#name`] type.
253                #[must_use]
254                pub const fn new(value: #field) -> Self {
255                    Self(value)
256                }
257
258                /// Returns a reference to the inner value.
259                #[must_use]
260                pub fn inner(&self) -> &#field {
261                    &self.0
262                }
263
264                /// Consumes self and returns the contained value.
265                #[must_use]
266                pub const fn into_inner(self) -> #field {
267                    self.0
268                }
269            }
270
271            impl core::convert::AsRef<#field> for #name {
272                fn as_ref(&self) -> &#field {
273                    &self.0
274                }
275            }
276
277            impl core::convert::AsMut<#field> for #name {
278                fn as_mut(&mut self) -> &mut #field {
279                    &mut self.0
280                }
281            }
282
283            impl core::ops::Deref for #name {
284                type Target = #field;
285
286                fn deref(&self) -> &Self::Target {
287                    &self.0
288                }
289            }
290
291            impl core::ops::DerefMut for #name {
292                fn deref_mut(&mut self) -> &mut Self::Target {
293                    &mut self.0
294                }
295            }
296
297            impl From<#name> for #field {
298                fn from(value: #name) -> #field {
299                    value.0
300                }
301            }
302
303            impl From<#field> for #name {
304                fn from(value: #field) -> #name {
305                    #name(value)
306                }
307            }
308
309            impl TryFrom<crate::versions::Version1DataFrame> for #name {
310                type Error = ();
311
312                #[inline]
313                fn try_from(value: crate::versions::Version1DataFrame) -> Result<Self, Self::Error> {
314                    value.value.try_into()
315                }
316            }
317
318            impl TryFrom<crate::VersionedDataFrame<crate::versions::Version1, crate::versions::Version1DataFrame>> for #name {
319                type Error = ();
320
321                #[inline]
322                fn try_from(value: crate::VersionedDataFrame<crate::versions::Version1, crate::versions::Version1DataFrame>) -> Result<Self, Self::Error> {
323                    value.data.value.try_into()
324                }
325            }
326        }
327    } else {
328        quote! {}
329    };
330
331    TokenStream::from(expanded)
332}