use quote::{format_ident, quote, ToTokens}; use syn::Ident; use crate::attribute_info::*; use crate::data_type::*; use crate::transaction_field::*; pub struct TrackerField<'a> { pub variable_name: &'a Ident, pub data_type: &'a DataType, pub convert_type: Option<&'a proc_macro2::TokenStream>, pub attribute_infos: &'a Vec, } impl<'a> From<&'a TransactionField> for TrackerField<'a> { fn from(transaction_field: &'a TransactionField) -> Self { let convert_type = AttributeInfo::find_convert_type(&transaction_field.attribute_infos); Self { variable_name: &transaction_field.variable_name, data_type: &transaction_field.data_type, convert_type, attribute_infos: &transaction_field.attribute_infos, } } } pub struct TrackerDataType<'a> { pub variable_name: &'a Ident, pub data_type: &'a DataType, pub convert_type: &'a Option<&'a proc_macro2::TokenStream>, pub attribute_infos: &'a Vec, } impl<'a> From<&'a TrackerField<'a>> for TrackerDataType<'a> { fn from(tracker_field: &'a TrackerField) -> Self { Self { variable_name: &tracker_field.variable_name, data_type: &tracker_field.data_type, convert_type: &tracker_field.convert_type, attribute_infos: &tracker_field.attribute_infos, } } } impl<'a> ToTokens for TrackerDataType<'a> { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { let variable_name = &self.variable_name; let track = format_ident!("track_{}", variable_name); let last_change = format_ident!("{}_last_change", variable_name); // figure out the type of the variable let quote = match self.data_type { DataType::Array(array) => { let length = &array.length; match self.convert_type { Some(convert_type) => { quote! { #variable_name: [Option<#convert_type>; #length], } } None => { let inner = &array.inner_type; quote! { #variable_name: [Option<#inner>; #length], } } } } DataType::Vector(vector) => match self.convert_type { Some(convert_type) => { quote! { #variable_name: Vec>, } } None => { let inner = &vector.inner_type; quote! { #variable_name: Vec>, } } }, DataType::Other(ts) => match self.convert_type { Some(convert_type) => { quote! { #variable_name: Option<#convert_type>, } } None => { quote! { #variable_name: Option<#ts>, } } }, }; // check features AttributeInfo::set_features(&self.attribute_infos, tokens); // set variable type proc_macro2::TokenStream::from(quote).to_tokens(tokens); // check features AttributeInfo::set_features(&self.attribute_infos, tokens); // flag, if variable gets tracked proc_macro2::TokenStream::from(quote! { #track: bool, }) .to_tokens(tokens); // check features AttributeInfo::set_features(&self.attribute_infos, tokens); // track the time the variable got changed last time proc_macro2::TokenStream::from(match self.data_type { DataType::Array(array) => { let length = &array.length; quote! {#last_change: [std::time::Duration; #length],} } DataType::Vector(_) => { quote! {#last_change: Vec,} } DataType::Other(_) => { quote! {#last_change: std::time::Duration,} } }) .to_tokens(tokens); } } pub struct TrackerDefault<'a> { pub variable_name: &'a Ident, pub attribute_infos: &'a Vec, } impl<'a> From<&'a TrackerDataType<'a>> for TrackerDefault<'a> { fn from(tracker_field: &'a TrackerDataType) -> Self { Self { variable_name: &tracker_field.variable_name, attribute_infos: &tracker_field.attribute_infos, } } } impl<'a> ToTokens for TrackerDefault<'a> { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { let variable_name = &self.variable_name; let track = format_ident!("track_{}", variable_name); let last_change = format_ident!("{}_last_change", variable_name); // check features AttributeInfo::set_features(&self.attribute_infos, tokens); proc_macro2::TokenStream::from(quote! { #variable_name: Default::default(), }) .to_tokens(tokens); // check features AttributeInfo::set_features(&self.attribute_infos, tokens); proc_macro2::TokenStream::from(quote! { #track: true, }) .to_tokens(tokens); // check features AttributeInfo::set_features(&self.attribute_infos, tokens); proc_macro2::TokenStream::from(quote! { #last_change: Default::default(), }) .to_tokens(tokens); } }