engine/transaction_derive/src/transaction_field.rs

337 lines
12 KiB
Rust
Raw Normal View History

2024-08-23 11:22:09 +00:00
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<AttributeInfo>,
pub tracker: Option<Ident>,
}
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);
}
}