use quote::{format_ident, quote, ToTokens}; use syn::Ident; use crate::attribute_info::*; use crate::data_type::*; #[derive(Debug)] pub struct TransactionField { pub variable_name: Ident, pub data_type: DataType, pub attribute_infos: Vec, pub tracker: Option, } impl ToTokens for TransactionField { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { let setter = format_ident!("set_{}", self.variable_name); let updater = format_ident!("update_{}", self.variable_name); let var = &self.variable_name; let ty = &self.data_type; let tracker = self.tracker.as_ref().expect("tracker not set"); let track = format_ident!("track_{}", var); let pre_exec_function = AttributeInfo::find_pre_setter_exec_function(&self.attribute_infos); let exec_function = AttributeInfo::find_setter_exec_function(&self.attribute_infos); let convert_type = AttributeInfo::find_convert_type(&self.attribute_infos); let custom_from = AttributeInfo::find_custom_from(&self.attribute_infos); let visibility = if AttributeInfo::find_private_setter(&self.attribute_infos) { quote! {} } else { quote! {pub} }; let setter = match ty { DataType::Vector(vector) => { let vector_type = &vector.inner_type; match (exec_function, pre_exec_function) { (Some(exec_function), Some(pre_exec_function)) => { quote! { fn #setter(&mut self, #var: #vector_type, index: usize) { let v = self.#pre_exec_function(#var); if self.#var[index] != v { let old_value = std::mem::replace(&mut self.#var[index], v); self.#exec_function(old_value, index).unwrap(); self.#updater(index); } } } } (Some(exec_function), None) => { quote! { fn #setter(&mut self, #var: #vector_type, index: usize) { if self.#var[index] != #var { let old_value = std::mem::replace(&mut self.#var[index], #var); self.#exec_function(old_value, index).unwrap(); self.#updater(index); } } } } (None, Some(pre_exec_function)) => { quote! { fn #setter(&mut self, #var: #vector_type, index: usize) { let v = self.#pre_exec_function(#var); if self.#var[index] != v { let old_value = std::mem::replace(&mut self.#var[index], v); self.#updater(index); } } } } (None, None) => { quote! { fn #setter(&mut self, #var: #vector_type, index: usize) { if self.#var[index] != #var { self.#var[index] = #var; self.#updater(index); } } } } } } DataType::Array(array) => { let array_type = &array.inner_type; match (exec_function, pre_exec_function) { (Some(exec_function), Some(pre_exec_function)) => { quote! { fn #setter(&mut self, #var: #array_type, index: usize) { let v = self.#pre_exec_function(#var); if self.#var[index] != v { let old_value = std::mem::replace(&mut self.#var[index], v); self.#exec_function(old_value, index).unwrap(); self.#updater(index); } } } } (Some(exec_function), None) => { quote! { fn #setter(&mut self, #var: #array_type, index: usize) { if self.#var[index] != #var { let old_value = std::mem::replace(&mut self.#var[index], #var); self.#exec_function(old_value, index).unwrap(); self.#updater(index); } } } } (None, Some(pre_exec_function)) => { quote! { fn #setter(&mut self, #var: #array_type, index: usize) { let v = self.#pre_exec_function(#var); if self.#var[index] != v { let old_value = std::mem::replace(&mut self.#var[index], v); self.#updater(index); } } } } (None, None) => { quote! { fn #setter(&mut self, #var: #array_type, index: usize) { if self.#var[index] != #var { self.#var[index] = #var; self.#updater(index); } } } } } } DataType::Other(ts) => match (exec_function, pre_exec_function) { (Some(exec_function), Some(pre_exec_function)) => { quote! { fn #setter(&mut self, #var: #ts) { let v = self.#pre_exec_function(#var); if self.#var != v { let old_value = std::mem::replace(&mut self.#var, v); self.#exec_function(old_value).unwrap(); self.#updater(); } } } } (Some(exec_function), None) => { quote! { fn #setter(&mut self, #var: #ts) { if self.#var != #var { let old_value = std::mem::replace(&mut self.#var, #var); self.#exec_function(old_value).unwrap(); self.#updater(); } } } } (None, Some(pre_exec_function)) => { quote! { fn #setter(&mut self, #var: #ts) { let v = self.#pre_exec_function(#var); if self.#var != v { let old_value = std::mem::replace(&mut self.#var, v); self.#updater(); } } } } (None, None) => { quote! { fn #setter(&mut self, #var: #ts) { if self.#var != #var { self.#var = #var; self.#updater(); } } } } }, }; // check features AttributeInfo::set_features(&self.attribute_infos, tokens); proc_macro2::TokenStream::from(quote! { #visibility #setter }) .to_tokens(tokens); if !AttributeInfo::find_skip_getter(&self.attribute_infos) { let getter = match ty { DataType::Array(array) => { let complete_type = &array.full_type; quote! { pub fn #var(&self) -> &#complete_type { &self.#var } } } DataType::Vector(vector) => { let complete_type = &vector.full_type; quote! { pub fn #var(&self) -> &#complete_type { &self.#var } } } DataType::Other(ts) => { quote! { pub fn #var(&self) -> &#ts { &self.#var } } } }; // check features AttributeInfo::set_features(&self.attribute_infos, tokens); proc_macro2::TokenStream::from(getter).to_tokens(tokens); } // check features AttributeInfo::set_features(&self.attribute_infos, tokens); proc_macro2::TokenStream::from(quote! { pub fn #track(&mut self, track: bool) { self.#tracker.#track = track; } }) .to_tokens(tokens); // check features AttributeInfo::set_features(&self.attribute_infos, tokens); let indexed_type_conversion = match (convert_type, custom_from) { (Some(_convert_type), Some(custom_from)) => quote! { Some(Self::#custom_from(self.#var[index].clone())) }, (Some(convert_type), None) => quote! { Some(#convert_type::from(self.#var[index].clone())) }, (None, _) => quote! { Some(self.#var[index].clone()) }, }; let type_conversion = match (convert_type, custom_from) { (Some(_convert_type), Some(custom_from)) => quote! { Some(Self::#custom_from(self.#var.clone())) }, (Some(convert_type), None) => quote! { Some(#convert_type::from(self.#var.clone())) }, (None, _) => quote! { Some(self.#var.clone()) }, }; let update = match ty { DataType::Vector(_vector) => { let check_vector_length = quote! { if self.#tracker.#var.len() as i32 - 1 < index as i32 { let size_difference = index as i32 - (self.#tracker.#var.len() as i32 - 1); for _ in 0..size_difference { self.#tracker.#var.push(None); } } }; quote! { #[inline] pub fn #updater(&mut self, index: usize) { if self.#tracker.#track { #check_vector_length self.#tracker.#var[index] = #indexed_type_conversion; } } } } DataType::Array(_array) => { quote! { #[inline] pub fn #updater(&mut self, index: usize) { if self.#tracker.#track { self.#tracker.#var[index] = #indexed_type_conversion; } } } } DataType::Other(_ts) => { quote! { #[inline] pub fn #updater(&mut self) { if self.#tracker.#track { self.#tracker.#var = #type_conversion; } } } } }; proc_macro2::TokenStream::from(update).to_tokens(tokens); } }