engine/transaction_derive/src/attribute_info.rs
2024-08-23 13:22:09 +02:00

226 lines
6.6 KiB
Rust

use proc_macro2::Span;
use quote::{quote, ToTokens};
use syn::{Attribute, Ident};
use crate::attribute_token_type::*;
const TRANSACTION_STRING: &'static str = "transaction";
const TRACKER_STRING: &'static str = "tracker";
#[derive(Debug, PartialEq)]
pub struct AttributeInfo {
pub ident: Ident,
pub token_type: Option<AttributeTokenType>,
}
impl AttributeInfo {
pub fn from_attribute(attribute: &Attribute) -> Option<Self> {
let attribute_idents: Vec<Ident> = attribute
.path()
.segments
.iter()
.map(|segment| segment.ident.clone())
.collect();
assert!(
attribute_idents.len() == 1,
"only one ident per attribute is allowed"
);
match attribute_idents[0].to_string().as_str() {
TRANSACTION_STRING => (),
TRACKER_STRING => (),
// filter attributes not affiliated with this crate
_ => return None,
}
let token_type = if let syn::Meta::List(_) = &attribute.meta {
Some(attribute.parse_args().expect("failed parsing attribute"))
} else {
None
};
Some(Self {
ident: attribute_idents[0].clone(),
token_type,
})
}
pub fn is_tracker(infos: &Vec<AttributeInfo>) -> bool {
infos
.iter()
.find(|info| info.ident == Ident::new(TRACKER_STRING, Span::call_site()))
.is_some()
}
pub fn is_transaction(infos: &Vec<AttributeInfo>) -> bool {
infos
.iter()
.find(|info| info.ident == Ident::new(TRANSACTION_STRING, Span::call_site()))
.is_some()
}
pub fn find_pre_setter_exec_function(infos: &Vec<AttributeInfo>) -> Option<&Ident> {
for info in infos.iter() {
if let Some(token_type) = &info.token_type {
match token_type {
AttributeTokenType::PreSetterExec(exec_function) => return Some(exec_function),
_ => (),
}
}
}
None
}
pub fn find_setter_exec_function(infos: &Vec<AttributeInfo>) -> Option<&Ident> {
for info in infos.iter() {
if let Some(token_type) = &info.token_type {
match token_type {
AttributeTokenType::SetterExec(exec_function) => return Some(exec_function),
_ => (),
}
}
}
None
}
pub fn find_apply_exec_function(infos: &Vec<AttributeInfo>) -> Option<&Ident> {
for info in infos.iter() {
if let Some(token_type) = &info.token_type {
match token_type {
AttributeTokenType::ApplyExec(exec_function) => return Some(exec_function),
_ => (),
}
}
}
None
}
pub fn find_convert_type(infos: &Vec<AttributeInfo>) -> Option<&proc_macro2::TokenStream> {
for info in infos.iter() {
if let Some(token_type) = &info.token_type {
match token_type {
AttributeTokenType::ConvertAs(convert_type) => return Some(convert_type),
_ => (),
}
}
}
None
}
pub fn find_skip_getter(infos: &Vec<AttributeInfo>) -> bool {
for info in infos.iter() {
if let Some(token_type) = &info.token_type {
match token_type {
AttributeTokenType::SkipGetter => return true,
_ => (),
}
}
}
false
}
pub fn find_custom_from(infos: &Vec<AttributeInfo>) -> Option<&Ident> {
for info in infos.iter() {
if let Some(token_type) = &info.token_type {
match token_type {
AttributeTokenType::CustomFrom(custom_from) => return Some(custom_from),
_ => (),
}
}
}
None
}
pub fn find_custom_into(infos: &Vec<AttributeInfo>) -> Option<&Ident> {
for info in infos.iter() {
if let Some(token_type) = &info.token_type {
match token_type {
AttributeTokenType::CustomInto(custom_into) => return Some(custom_into),
_ => (),
}
}
}
None
}
pub fn find_compile_feature(infos: &Vec<AttributeInfo>) -> Option<&proc_macro2::TokenStream> {
for info in infos.iter() {
if let Some(token_type) = &info.token_type {
match token_type {
AttributeTokenType::CompileFeature(feature) => return Some(feature),
_ => (),
}
}
}
None
}
pub fn find_private_setter(infos: &Vec<AttributeInfo>) -> bool {
for info in infos.iter() {
if let Some(token_type) = &info.token_type {
match token_type {
AttributeTokenType::PrivateSetter => return true,
_ => (),
}
}
}
false
}
pub fn find_compile_not_feature(
infos: &Vec<AttributeInfo>,
) -> Option<&proc_macro2::TokenStream> {
for info in infos.iter() {
if let Some(token_type) = &info.token_type {
match token_type {
AttributeTokenType::CompileNotFeature(feature) => return Some(feature),
_ => (),
}
}
}
None
}
pub fn set_features(infos: &Vec<AttributeInfo>, tokens: &mut proc_macro2::TokenStream) {
// check features
if let Some(feature) = Self::find_compile_feature(infos) {
proc_macro2::TokenStream::from(quote! {
#[cfg(feature = #feature)]
})
.to_tokens(tokens);
}
if let Some(feature) = Self::find_compile_not_feature(infos) {
proc_macro2::TokenStream::from(quote! {
#[cfg(not(feature = #feature))]
})
.to_tokens(tokens);
}
}
pub fn check_duplicate(attributes: &Vec<AttributeInfo>) {
let mut visited: Vec<&AttributeInfo> = Vec::new();
for attribute in attributes.iter() {
match visited
.iter()
.find(|visited_attribute| ***visited_attribute == *attribute)
{
Some(_) => panic!("Attribute was used multiple times {}", attribute.ident),
None => visited.push(&attribute),
}
}
}
}