serial_sensors_proto_derive/
lib.rs1extern 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 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 #[doc = #name ]
130 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 pub const fn sensor_type_id(&self) -> u8 {
143 match self {
144 #( #sensor_match_arms )*
145 }
146 }
147
148 pub const fn value_type(&self) -> crate::ValueType {
150 match self {
151 #( #field_match_arms )*
152 }
153 }
154
155 pub const fn num_components(&self) -> u8 {
157 match self {
158 #( #num_components_match_arms )*
159 }
160 }
161
162 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 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 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 #[must_use]
254 pub const fn new(value: #field) -> Self {
255 Self(value)
256 }
257
258 #[must_use]
260 pub fn inner(&self) -> &#field {
261 &self.0
262 }
263
264 #[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}