226 lines
6.6 KiB
Rust
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),
|
|
}
|
|
}
|
|
}
|
|
}
|