1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::{format_ident, quote};
5use syn::{
6 parse::Parser, parse_macro_input, spanned::Spanned, Field, ItemStruct, LitBool, LitStr, Result,
7};
8
9#[proc_macro_attribute]
23pub fn parameter_group(_attr: TokenStream, input: TokenStream) -> TokenStream {
24 let item_struct = parse_macro_input!(input as ItemStruct);
25
26 match parameter_pool_impl(item_struct) {
27 Ok(v) => v,
28 Err(err) => err.to_compile_error().into(),
29 }
30}
31
32fn parameter_pool_impl(mut item_struct: ItemStruct) -> Result<TokenStream> {
33 let struct_name = &item_struct.ident;
34
35 let mut meta_fields = Vec::new();
36
37 let meta_name = format_ident!("{}Meta", struct_name);
40
41 let mut setters = Vec::new();
42 let mut idgetters = Vec::new();
43 let mut meta_inits = Vec::new();
44 let mut param_defs = Vec::new();
45 let mut param_mod_values = Vec::new();
46 let mut param_values = Vec::new();
47
48 let mut field_id = 0;
49 let num_fields;
50
51 if let syn::Fields::Named(ref mut fields) = item_struct.fields {
52 num_fields = fields.named.len() as u32;
53 for f in fields.named.iter_mut() {
54 let (extra_meta_fields, init, setter, getid) = get_field_methods(field_id, f)?;
55 meta_fields.extend(extra_meta_fields);
56 meta_inits.push(init);
57 setters.push(setter);
58 idgetters.push(getid);
59
60 param_defs.push(get_para_def(field_id, &f)?);
61 param_mod_values.push(get_para_mod_value(field_id, &f)?);
62 param_values.push(get_para_value(field_id, &f)?);
63
64 f.attrs.clear();
65 field_id += 1;
66 }
67 fields.named.push(
68 syn::Field::parse_named
69 .parse2(quote!( _meta: #meta_name))
70 .unwrap(),
71 );
72 } else {
73 return Err(syn::Error::new_spanned(
74 &item_struct,
75 "parameter_pool cannot be used with tuple or unit structs",
76 ));
77 }
78
79 let struct_name_str = format!("{}", struct_name);
80
81 let r = quote! {
82 #item_struct
83
84
85 impl #struct_name {
86 #(#setters)*
87
88 #(#idgetters)*
89
90 fn get_definitions(&self) -> ygw::protobuf::ygw::ParameterDefinitionList {
91 let mut definitions = Vec::new();
92 #(#param_defs)*
93
94 return ygw::protobuf::ygw::ParameterDefinitionList{ definitions };
95 }
96
97 fn get_modified_values(&mut self) -> ygw::protobuf::ygw::ParameterData {
98 let mut parameters = Vec::new();
99 #(#param_mod_values)*
100
101 ygw::protobuf::ygw::ParameterData {
102 parameters,
103 group: #struct_name_str.to_string(),
104 seq_num: self._meta.next_seq_count(),
105 generation_time: None,
106 acquisition_time: None,
107 }
108 }
109
110 fn get_values(&mut self, gentime: ygw::protobuf::ygw::Timestamp) -> ygw::protobuf::ygw::ParameterData {
111 let mut parameters = Vec::new();
112 #(#param_values)*
113
114 ygw::protobuf::ygw::ParameterData {
115 parameters,
116 group: #struct_name_str.to_string(),
117 seq_num: self._meta.next_seq_count(),
118 generation_time: Some(gentime),
119 acquisition_time: None,
120 }
121 }
122
123 pub async fn send_definitions(&mut self, tx: &Sender<YgwMessage>) -> ygw::Result<()> {
125 tx.send(ygw::msg::YgwMessage::ParameterDefinitions(self._meta.addr, self.get_definitions()))
126 .await.map_err(|_| YgwError::ServerShutdown)
127 }
128
129 pub async fn send_values(&mut self, tx: &Sender<YgwMessage>) -> ygw::Result<()> {
131 tx.send(ygw::msg::YgwMessage::ParameterData(self._meta.addr, self.get_values(ygw::protobuf::now())))
132 .await.map_err(|_| YgwError::ServerShutdown)
133 }
134
135 pub async fn send_modified_values(&mut self, tx: &Sender<YgwMessage>) -> ygw::Result<()> {
137 tx.send(ygw::msg::YgwMessage::ParameterData(self._meta.addr, self.get_modified_values()))
138 .await.map_err(|_| YgwError::ServerShutdown)
139 }
140
141 }
142 struct #meta_name {
143 start_id: u32,
144 seq_count: u32,
145 addr: ygw::msg::Addr,
146 #(#meta_fields,)*
147 }
148
149 impl #meta_name {
150 fn new(addr:ygw::msg::Addr, gentime: ygw::protobuf::ygw::Timestamp) -> Self {
151 Self {
152 addr,
153 start_id: ygw::generate_pids(#num_fields),
154 seq_count: 0,
155 #(#meta_inits)*
156 }
157 }
158 fn next_seq_count(&mut self) -> u32 {
159 let c = self.seq_count;
160 self.seq_count = c + 1;
161 c
162 }
163 }
164 }
165 .into();
166
167 Ok(r)
168}
169
170fn get_para_def(id: u32, field: &Field) -> Result<proc_macro2::TokenStream> {
171 let name_string = format!("{}", field.ident.as_ref().unwrap());
172 let mut relative_name = quote! {#name_string.to_string()};
173 let mut description = quote! { None };
174 let mut unit = quote! { None };
175 let mut writable = quote! { None };
176
177 for attr in &field.attrs {
178 if attr.path().is_ident("mdb") {
179 attr.parse_nested_meta(|meta| {
180 if meta.path.is_ident("relative_name") {
181 let value = meta.value()?;
182 let s: LitStr = value.parse()?;
183 relative_name = quote! {#s.to_string()};
184 } else if meta.path.is_ident("description") {
185 let value = meta.value()?;
186 let s: LitStr = value.parse()?;
187 description = quote! {Some(#s.to_string())};
188 } else if meta.path.is_ident("unit") {
189 let value = meta.value()?;
190 let s: LitStr = value.parse()?;
191 unit = quote! {Some(#s.to_string())};
192 } else if meta.path.is_ident("writable") {
193 let value = meta.value()?;
194 let s: LitBool = value.parse()?;
195 writable = quote! {Some(#s)};
196 }
197 Ok(())
198 })?;
199 };
200 }
201 let types = map_type(&field.ty)?;
202
203 Ok(quote! {
204 definitions.push(ParameterDefinition {
205 relative_name: #relative_name,
206 description: #description,
207 unit: #unit,
208 writable: #writable,
209 ptype: #types.to_string(),
210 id: self._meta.start_id + #id
211 });
212 })
213}
214
215fn get_para_value(id: u32, field: &Field) -> Result<proc_macro2::TokenStream> {
216 let name = field.ident.as_ref().unwrap();
217
218 Ok(quote! {
219 parameters.push(ygw::protobuf::get_pv_eng(self._meta.start_id + #id, None, self.#name));
220 })
221}
222
223fn get_para_mod_value(id: u32, field: &Field) -> Result<proc_macro2::TokenStream> {
224 let name = field.ident.as_ref().unwrap();
225 let gentime_name = format_ident!("{}_gentime", name);
226 let modified_name = format_ident!("{}_modified", name);
227
228 Ok(quote! {
229 if self._meta.#modified_name {
230 parameters.push(ygw::protobuf::get_pv_eng(self._meta.start_id + #id, Some(self._meta.#gentime_name.clone()), self.#name));
231 self._meta.#modified_name = false;
232 }
233 })
234}
235
236fn get_field_methods(
237 id: u32,
238 field: &Field,
239) -> Result<(
240 Vec<Field>,
241 proc_macro2::TokenStream,
242 proc_macro2::TokenStream,
243 proc_macro2::TokenStream,
244)> {
245 let name = field.ident.as_ref().unwrap();
246 let ty = &field.ty;
247 let setter_name = format_ident!("set_{}", name);
248 let id_name = format_ident!("id_{}", name);
249
250 let gentime_name = format_ident!("{}_gentime", name);
251 let modified_name = format_ident!("{}_modified", name);
252
253 let gentime_field = syn::Field::parse_named
254 .parse2(quote! { #gentime_name: ygw::protobuf::ygw::Timestamp })
255 .unwrap();
256 let modified_field = syn::Field::parse_named
257 .parse2(quote! { #modified_name: bool })
258 .unwrap();
259
260 let setter = quote! {
261 pub fn #setter_name(&mut self, #name: #ty, gentime: ygw::protobuf::ygw::Timestamp) {
262 self.#name = #name;
263 self._meta.#gentime_name = gentime;
264 self._meta.#modified_name = true;
265 }};
266
267 let getid = quote! {
268 pub fn #id_name(&self) -> u32{
269 self._meta.start_id + #id
270 }};
271
272 let init = quote! {
273 #gentime_name: gentime.clone(),
274 #modified_name: false,
275 };
276
277 Ok((vec![gentime_field, modified_field], init, setter, getid))
278}
279
280fn map_type(ty: &syn::Type) -> Result<String> {
281 match ty {
282 syn::Type::Path(typepath) if typepath.qself.is_none() => {
283 let type_ident = &typepath.path.segments.first().unwrap().ident;
284
285 match type_ident.to_string().as_ref() {
286 "u32" => Ok("uint32".to_string()),
287 "i32" => Ok("sint32".to_string()),
288 "u64" => Ok("uint64".to_string()),
289 "i64" => Ok("sint64".to_string()),
290 "f32" => Ok("float".to_string()),
291 "f64" => Ok("double".to_string()),
292 "bool" => Ok("boolean".to_string()),
293 "String" => Ok("string".to_string()),
294 _ => Err(syn::Error::new(type_ident.span(), "Invalid Type")),
295 }
296 }
297 _ => Err(syn::Error::new(ty.span(), "Not a simple type")),
298 }
299}