diff --git a/packages/fortifier-macros/src/validate/enum.rs b/packages/fortifier-macros/src/validate/enum.rs index aeb6731..77cfac6 100644 --- a/packages/fortifier-macros/src/validate/enum.rs +++ b/packages/fortifier-macros/src/validate/enum.rs @@ -1,12 +1,13 @@ -use std::{collections::HashSet, str::FromStr}; - use proc_macro2::TokenStream; use quote::{ToTokens, TokenStreamExt, format_ident, quote}; use syn::{DataEnum, DeriveInput, Generics, Ident, Result, Variant, Visibility}; -use crate::validate::{ - field::{LiteralOrIdent, ValidateFieldPrefix}, - fields::ValidateFields, +use crate::{ + validate::{ + field::{LiteralOrIdent, ValidateFieldPrefix}, + fields::ValidateFields, + }, + validation::Execution, }; pub struct ValidateEnum { @@ -39,13 +40,6 @@ impl ValidateEnum { Ok(result) } - fn uses(&self) -> HashSet { - self.variants - .iter() - .flat_map(|variant| variant.uses()) - .collect() - } - fn error_type(&self) -> (Ident, TokenStream) { let visibility = &self.visibility; let error_ident = &self.error_ident; @@ -89,42 +83,33 @@ impl ToTokens for ValidateEnum { let ident = &self.ident; let (impl_generics, type_generics, where_clause) = &self.generics.split_for_impl(); - let uses = self.uses().into_iter().map(|r#use| { - let tokens = TokenStream::from_str(&r#use).expect("Tokens should be valid."); - quote!(use #tokens;) - }); let (error_ident, error_type) = self.error_type(); let variant_error_types = self.variants.iter().map(|variant| variant.error_type().1); let sync_variant_match_arms = self .variants .iter() - .map(|variant| variant.sync_match_arm_tokens()); + .map(|variant| variant.match_arm(Execution::Sync)); let async_variant_match_arms = self .variants .iter() - .map(|variant| variant.async_match_arm_tokens()); + .map(|variant| variant.match_arm(Execution::Async)); tokens.append_all(quote! { - #( #uses )* - - // TODO: Replace with granular uses. - use fortifier::*; - #error_type #( #variant_error_types )* #[automatically_derived] - impl #impl_generics Validate for #ident #type_generics #where_clause { + impl #impl_generics ::fortifier::Validate for #ident #type_generics #where_clause { type Error = #error_ident; - fn validate_sync(&self) -> Result<(), ValidationErrors> { + fn validate_sync(&self) -> Result<(), ::fortifier::ValidationErrors> { match &self { #( #sync_variant_match_arms ),* } } - fn validate_async(&self) -> ::std::pin::Pin>>>> { + fn validate_async(&self) -> ::std::pin::Pin>>>> { Box::pin(async move { match &self { #( #async_variant_match_arms ),* @@ -164,66 +149,11 @@ impl ValidateEnumVariant { Ok(result) } - fn uses(&self) -> HashSet { - self.fields.uses() - } - - fn error_type(&self) -> (Ident, TokenStream) { + fn error_type(&self) -> (TokenStream, TokenStream) { self.fields.error_type() } - fn sync_match_arm_tokens(&self) -> TokenStream { - let enum_ident = &self.enum_ident; - let enum_error_ident = &self.enum_error_ident; - let ident = &self.ident; - - let error_wrapper = |tokens| quote!(#enum_error_ident::#ident(#tokens)); - - match &self.fields { - ValidateFields::Named(fields) => { - let field_idents = fields.idents(); - let sync_validations = - fields.sync_validations(ValidateFieldPrefix::None, &error_wrapper); - - // TODO: Only destructure fields required for validation. - quote! { - #[allow(unused_variables)] - #enum_ident::#ident { - #( #field_idents ),* - } => { - #sync_validations - } - } - } - ValidateFields::Unnamed(fields) => { - let field_idents = fields.idents().map(|ident| match ident { - LiteralOrIdent::Literal(literal) => format_ident!("f{literal}"), - LiteralOrIdent::Ident(ident) => ident.clone(), - }); - let sync_validations = - fields.sync_validations(ValidateFieldPrefix::F, &error_wrapper); - - quote! { - #enum_ident::#ident( - #( #field_idents ),* - ) => { - #sync_validations - } - } - } - ValidateFields::Unit(fields) => { - let sync_validations = fields.sync_validations(); - - quote! { - #enum_ident::#ident => { - #sync_validations - } - } - } - } - } - - fn async_match_arm_tokens(&self) -> TokenStream { + fn match_arm(&self, exeuction: Execution) -> TokenStream { let enum_ident = &self.enum_ident; let enum_error_ident = &self.enum_error_ident; let ident = &self.ident; @@ -233,8 +163,8 @@ impl ValidateEnumVariant { match &self.fields { ValidateFields::Named(fields) => { let field_idents = fields.idents(); - let async_validations = - fields.async_validations(ValidateFieldPrefix::None, &error_wrapper); + let validations = + fields.validations(exeuction, ValidateFieldPrefix::None, &error_wrapper); // TODO: Only destructure fields required for validation. quote! { @@ -242,7 +172,7 @@ impl ValidateEnumVariant { #enum_ident::#ident { #( #field_idents ),* } => { - #async_validations + #validations } } } @@ -251,23 +181,23 @@ impl ValidateEnumVariant { LiteralOrIdent::Literal(literal) => format_ident!("f{literal}"), LiteralOrIdent::Ident(ident) => ident.clone(), }); - let async_validations = - fields.async_validations(ValidateFieldPrefix::F, &error_wrapper); + let validations = + fields.validations(exeuction, ValidateFieldPrefix::F, &error_wrapper); quote! { #enum_ident::#ident( #( #field_idents ),* ) => { - #async_validations + #validations } } } ValidateFields::Unit(fields) => { - let async_validations = fields.async_validations(); + let validations = fields.validations(); quote! { #enum_ident::#ident => { - #async_validations + #validations } } } diff --git a/packages/fortifier-macros/src/validate/field.rs b/packages/fortifier-macros/src/validate/field.rs index a4ec772..0cff6d0 100644 --- a/packages/fortifier-macros/src/validate/field.rs +++ b/packages/fortifier-macros/src/validate/field.rs @@ -4,7 +4,7 @@ use quote::{ToTokens, format_ident, quote}; use syn::{Field, Ident, Result, Visibility}; use crate::{ - validation::Validation, + validation::{Execution, Validation}, validations::{Custom, Email, Length, Regex, Url}, }; @@ -127,64 +127,38 @@ impl ValidateField { } } - pub fn sync_validations(&self, field_prefix: ValidateFieldPrefix) -> Vec { + pub fn validations( + &self, + execution: Execution, + field_prefix: ValidateFieldPrefix, + ) -> Vec { let error_type_ident = &self.error_type_ident; let ident = &self.ident; - self.validations - .iter() - .filter(|validation| !validation.is_async()) - .map(|validation| { - let validation_ident = validation.ident(); - let tokens = validation.tokens(&match field_prefix { - ValidateFieldPrefix::None => self.ident.to_token_stream(), - ValidateFieldPrefix::SelfKeyword => quote!(self.#ident), - ValidateFieldPrefix::F => match &self.ident { - LiteralOrIdent::Literal(literal) => { - format_ident!("f{literal}").to_token_stream() - } - LiteralOrIdent::Ident(ident) => ident.to_token_stream(), - }, - }); - - if self.validations.len() > 1 { - quote! { - #tokens.map_err(#error_type_ident::#validation_ident) - } - } else { - tokens - } - }) - .collect() - } - - pub fn async_validations(&self, field_prefix: ValidateFieldPrefix) -> Vec { - let ident = &self.ident; - let error_type_ident = &self.error_type_ident; + let field_expr = match field_prefix { + ValidateFieldPrefix::None => self.ident.to_token_stream(), + ValidateFieldPrefix::SelfKeyword => quote!(self.#ident), + ValidateFieldPrefix::F => match &self.ident { + LiteralOrIdent::Literal(literal) => format_ident!("f{literal}").to_token_stream(), + LiteralOrIdent::Ident(ident) => ident.to_token_stream(), + }, + }; self.validations .iter() - .filter(|validation| validation.is_async()) - .map(|validation| { + .flat_map(|validation| { let validation_ident = validation.ident(); - let tokens = validation.tokens(&match field_prefix { - ValidateFieldPrefix::None => self.ident.to_token_stream(), - ValidateFieldPrefix::SelfKeyword => quote!(self.#ident), - ValidateFieldPrefix::F => match &self.ident { - LiteralOrIdent::Literal(literal) => { - format_ident!("f{literal}").to_token_stream() - } - LiteralOrIdent::Ident(ident) => ident.to_token_stream(), - }, - }); + let expr = validation.expr(execution, &field_expr); - if self.validations.len() > 1 { - quote! { - #tokens.map_err(#error_type_ident::#validation_ident) + expr.map(|expr| { + if self.validations.len() > 1 { + quote! { + #expr.map_err(#error_type_ident::#validation_ident) + } + } else { + expr } - } else { - tokens - } + }) }) .collect() } diff --git a/packages/fortifier-macros/src/validate/fields.rs b/packages/fortifier-macros/src/validate/fields.rs index 217eb43..7bc9e40 100644 --- a/packages/fortifier-macros/src/validate/fields.rs +++ b/packages/fortifier-macros/src/validate/fields.rs @@ -1,10 +1,11 @@ -use std::collections::HashSet; - use proc_macro2::{Literal, TokenStream}; -use quote::{format_ident, quote}; +use quote::{ToTokens, format_ident, quote}; use syn::{Fields, FieldsNamed, FieldsUnnamed, Ident, Result, Visibility}; -use crate::validate::field::{LiteralOrIdent, ValidateField, ValidateFieldPrefix}; +use crate::{ + validate::field::{LiteralOrIdent, ValidateField, ValidateFieldPrefix}, + validation::Execution, +}; pub enum ValidateFields { Named(ValidateNamedFields), @@ -25,15 +26,7 @@ impl ValidateFields { }) } - pub fn uses(&self) -> HashSet { - match self { - ValidateFields::Named(named) => named.uses(), - ValidateFields::Unnamed(unnamed) => unnamed.uses(), - ValidateFields::Unit(unit) => unit.uses(), - } - } - - pub fn error_type(&self) -> (Ident, TokenStream) { + pub fn error_type(&self) -> (TokenStream, TokenStream) { match self { ValidateFields::Named(named) => named.error_type(), ValidateFields::Unnamed(unnamed) => unnamed.error_type(), @@ -41,31 +34,20 @@ impl ValidateFields { } } - pub fn sync_validations( + pub fn validations( &self, + execution: Execution, field_prefix: ValidateFieldPrefix, error_wrapper: &impl Fn(TokenStream) -> TokenStream, ) -> TokenStream { match self { - ValidateFields::Named(named) => named.sync_validations(field_prefix, error_wrapper), - ValidateFields::Unnamed(unnamed) => { - unnamed.sync_validations(field_prefix, error_wrapper) + ValidateFields::Named(named) => { + named.validations(execution, field_prefix, error_wrapper) } - ValidateFields::Unit(unit) => unit.sync_validations(), - } - } - - pub fn async_validations( - &self, - field_prefix: ValidateFieldPrefix, - error_wrapper: &impl Fn(TokenStream) -> TokenStream, - ) -> TokenStream { - match self { - ValidateFields::Named(named) => named.async_validations(field_prefix, error_wrapper), ValidateFields::Unnamed(unnamed) => { - unnamed.async_validations(field_prefix, error_wrapper) + unnamed.validations(execution, field_prefix, error_wrapper) } - ValidateFields::Unit(unit) => unit.async_validations(), + ValidateFields::Unit(unit) => unit.validations(), } } } @@ -106,11 +88,7 @@ impl ValidateNamedFields { self.fields.iter().map(|field| field.ident()) } - fn uses(&self) -> HashSet { - HashSet::default() - } - - fn error_type(&self) -> (Ident, TokenStream) { + fn error_type(&self) -> (TokenStream, TokenStream) { let visibility = &self.visibility; let ident = &self.ident; let error_ident = &self.error_ident; @@ -131,7 +109,7 @@ impl ValidateNamedFields { } ( - error_ident.clone(), + error_ident.to_token_stream(), quote! { #[allow(dead_code)] #[derive(Debug)] @@ -154,31 +132,18 @@ impl ValidateNamedFields { ) } - pub fn sync_validations( - &self, - field_prefix: ValidateFieldPrefix, - error_wrapper: &impl Fn(TokenStream) -> TokenStream, - ) -> TokenStream { - validations( - &self.error_ident, - error_wrapper, - self.fields - .iter() - .map(|field| (field, field.sync_validations(field_prefix))), - ) - } - - pub fn async_validations( + pub fn validations( &self, + execution: Execution, field_prefix: ValidateFieldPrefix, error_wrapper: &impl Fn(TokenStream) -> TokenStream, ) -> TokenStream { validations( + execution, + field_prefix, &self.error_ident, error_wrapper, - self.fields - .iter() - .map(|field| (field, field.async_validations(field_prefix))), + self.fields.iter(), ) } } @@ -215,11 +180,7 @@ impl ValidateUnnamedFields { self.fields.iter().map(|field| field.ident()) } - fn uses(&self) -> HashSet { - HashSet::default() - } - - fn error_type(&self) -> (Ident, TokenStream) { + fn error_type(&self) -> (TokenStream, TokenStream) { let visibility = &self.visibility; let ident = &self.ident; let error_ident = &self.error_ident; @@ -240,7 +201,7 @@ impl ValidateUnnamedFields { } ( - error_ident.clone(), + error_ident.to_token_stream(), quote! { #[allow(dead_code)] #[derive(Debug)] @@ -263,31 +224,18 @@ impl ValidateUnnamedFields { ) } - pub fn sync_validations( + pub fn validations( &self, + execution: Execution, field_prefix: ValidateFieldPrefix, error_wrapper: &impl Fn(TokenStream) -> TokenStream, ) -> TokenStream { validations( + execution, + field_prefix, &self.error_ident, error_wrapper, - self.fields - .iter() - .map(|field| (field, field.sync_validations(field_prefix))), - ) - } - - pub fn async_validations( - &self, - field_prefix: ValidateFieldPrefix, - error_wrapper: &impl Fn(TokenStream) -> TokenStream, - ) -> TokenStream { - validations( - &self.error_ident, - error_wrapper, - self.fields - .iter() - .map(|field| (field, field.async_validations(field_prefix))), + self.fields.iter(), ) } } @@ -299,21 +247,11 @@ impl ValidateUnitFields { Ok(Self {}) } - fn uses(&self) -> HashSet { - HashSet::from(["std::convert::Infallible".to_owned()]) - } - - fn error_type(&self) -> (Ident, TokenStream) { - (format_ident!("Infallible"), TokenStream::new()) + fn error_type(&self) -> (TokenStream, TokenStream) { + (quote!(::std::convert::Infallible), TokenStream::new()) } - pub fn sync_validations(&self) -> TokenStream { - quote! { - Ok(()) - } - } - - pub fn async_validations(&self) -> TokenStream { + pub fn validations(&self) -> TokenStream { quote! { Ok(()) } @@ -321,13 +259,18 @@ impl ValidateUnitFields { } fn validations<'a>( + execution: Execution, + field_prefix: ValidateFieldPrefix, error_ident: &Ident, error_wrapper: &impl Fn(TokenStream) -> TokenStream, - iterator: impl Iterator)>, + fields: impl Iterator, ) -> TokenStream { - let validations = iterator - .flat_map(|(field, validations)| { + let error_ident = &error_ident; + + let validations = fields + .flat_map(|field| { let field_error_ident = field.error_ident(); + let validations = field.validations(execution, field_prefix); validations .iter() diff --git a/packages/fortifier-macros/src/validate/struct.rs b/packages/fortifier-macros/src/validate/struct.rs index 5c7c58e..d105240 100644 --- a/packages/fortifier-macros/src/validate/struct.rs +++ b/packages/fortifier-macros/src/validate/struct.rs @@ -1,10 +1,11 @@ -use std::str::FromStr; - use proc_macro2::TokenStream; use quote::{ToTokens, TokenStreamExt, quote}; use syn::{DataStruct, DeriveInput, Generics, Ident, Result}; -use crate::validate::{field::ValidateFieldPrefix, fields::ValidateFields}; +use crate::{ + validate::{field::ValidateFieldPrefix, fields::ValidateFields}, + validation::Execution, +}; pub struct ValidateStruct { ident: Ident, @@ -29,35 +30,30 @@ impl ToTokens for ValidateStruct { let error_wrapper = |tokens| tokens; - let uses = self.fields.uses().into_iter().map(|r#use| { - let tokens = TokenStream::from_str(&r#use).expect("Tokens should be valid."); - quote!(use #tokens;) - }); let (error_ident, error_type) = self.fields.error_type(); - let sync_validations = self - .fields - .sync_validations(ValidateFieldPrefix::SelfKeyword, &error_wrapper); - let async_validations = self - .fields - .async_validations(ValidateFieldPrefix::SelfKeyword, &error_wrapper); + let sync_validations = self.fields.validations( + Execution::Sync, + ValidateFieldPrefix::SelfKeyword, + &error_wrapper, + ); + let async_validations = self.fields.validations( + Execution::Async, + ValidateFieldPrefix::SelfKeyword, + &error_wrapper, + ); tokens.append_all(quote! { - #( #uses )* - - // TODO: Replace with granular uses. - use fortifier::*; - #error_type #[automatically_derived] - impl #impl_generics Validate for #ident #type_generics #where_clause { + impl #impl_generics ::fortifier::Validate for #ident #type_generics #where_clause { type Error = #error_ident; - fn validate_sync(&self) -> Result<(), ValidationErrors> { + fn validate_sync(&self) -> Result<(), ::fortifier::ValidationErrors> { #sync_validations } - fn validate_async(&self) -> ::std::pin::Pin>>>> { + fn validate_async(&self) -> ::std::pin::Pin>>>> { Box::pin(async { #async_validations }) diff --git a/packages/fortifier-macros/src/validation.rs b/packages/fortifier-macros/src/validation.rs index 182b598..0236fa1 100644 --- a/packages/fortifier-macros/src/validation.rs +++ b/packages/fortifier-macros/src/validation.rs @@ -1,16 +1,20 @@ use proc_macro2::TokenStream; use syn::{Ident, Result, meta::ParseNestedMeta}; +#[derive(Clone, Copy)] +pub enum Execution { + Sync, + Async, +} + pub trait Validation { fn parse(_meta: &ParseNestedMeta<'_>) -> Result where Self: Sized; - fn is_async(&self) -> bool; - fn ident(&self) -> Ident; fn error_type(&self) -> TokenStream; - fn tokens(&self, expr: &TokenStream) -> TokenStream; + fn expr(&self, execution: Execution, expr: &TokenStream) -> Option; } diff --git a/packages/fortifier-macros/src/validations/custom.rs b/packages/fortifier-macros/src/validations/custom.rs index e939d86..e459567 100644 --- a/packages/fortifier-macros/src/validations/custom.rs +++ b/packages/fortifier-macros/src/validations/custom.rs @@ -2,17 +2,17 @@ use proc_macro2::TokenStream; use quote::{ToTokens, format_ident, quote}; use syn::{Ident, LitBool, Path, Result, Type, meta::ParseNestedMeta}; -use crate::validation::Validation; +use crate::validation::{Execution, Validation}; pub struct Custom { - is_async: bool, + execution: Execution, error_type: Type, function_path: Path, } impl Validation for Custom { fn parse(meta: &ParseNestedMeta<'_>) -> Result { - let mut is_async = false; + let mut execution = Execution::Sync; let mut error_type: Option = None; let mut function_path: Option = None; @@ -20,9 +20,13 @@ impl Validation for Custom { if meta.path.is_ident("async") { if let Ok(value) = meta.value() { let lit: LitBool = value.parse()?; - is_async = lit.value; + execution = if lit.value { + Execution::Async + } else { + Execution::Sync + }; } else { - is_async = true; + execution = Execution::Async; } Ok(()) @@ -47,16 +51,12 @@ impl Validation for Custom { }; Ok(Custom { - is_async, + execution, error_type, function_path, }) } - fn is_async(&self) -> bool { - self.is_async - } - fn ident(&self) -> Ident { // TODO: Determine ident from function or error type. format_ident!("Custom") @@ -66,17 +66,23 @@ impl Validation for Custom { self.error_type.to_token_stream() } - fn tokens(&self, expr: &TokenStream) -> TokenStream { - let function_path = &self.function_path; + fn expr(&self, execution: Execution, expr: &TokenStream) -> Option { + match (execution, self.execution) { + (Execution::Sync, Execution::Sync) => { + let function_path = &self.function_path; - if self.is_async { - quote! { - #function_path(&#expr).await + Some(quote! { + #function_path(&#expr) + }) } - } else { - quote! { - #function_path(&#expr) + (Execution::Async, Execution::Async) => { + let function_path = &self.function_path; + + Some(quote! { + #function_path(&#expr).await + }) } + _ => None, } } } diff --git a/packages/fortifier-macros/src/validations/email.rs b/packages/fortifier-macros/src/validations/email.rs index f2f1f74..66255e8 100644 --- a/packages/fortifier-macros/src/validations/email.rs +++ b/packages/fortifier-macros/src/validations/email.rs @@ -2,7 +2,7 @@ use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::{Ident, LitBool, LitInt, Result, meta::ParseNestedMeta}; -use crate::validation::Validation; +use crate::validation::{Execution, Validation}; pub struct Email { allow_display_text: bool, @@ -50,33 +50,33 @@ impl Validation for Email { Ok(result) } - fn is_async(&self) -> bool { - false - } - fn ident(&self) -> Ident { format_ident!("Email") } - fn error_type(&self) -> TokenStream { - quote!(EmailError) + quote!(::fortifier::EmailError) } - fn tokens(&self, expr: &TokenStream) -> TokenStream { - let allow_display_text = self.allow_display_text; - let allow_domain_literal = self.allow_domain_literal; - let minimum_sub_domains = self.minimum_sub_domains; + fn expr(&self, execution: Execution, expr: &TokenStream) -> Option { + match execution { + Execution::Sync => { + let allow_display_text = self.allow_display_text; + let allow_domain_literal = self.allow_domain_literal; + let minimum_sub_domains = self.minimum_sub_domains; - quote! { - { - const EMAIL_ADDRESS_OPTIONS: EmailOptions = EmailOptions { - allow_display_text: #allow_display_text, - allow_domain_literal: #allow_domain_literal, - minimum_sub_domains: #minimum_sub_domains, - }; + Some(quote! { + { + const EMAIL_ADDRESS_OPTIONS: ::fortifier::EmailOptions = ::fortifier::EmailOptions { + allow_display_text: #allow_display_text, + allow_domain_literal: #allow_domain_literal, + minimum_sub_domains: #minimum_sub_domains, + }; - #expr.validate_email(EMAIL_ADDRESS_OPTIONS) + ::fortifier::ValidateEmail::validate_email(&#expr, EMAIL_ADDRESS_OPTIONS) + } + }) } + Execution::Async => None, } } } diff --git a/packages/fortifier-macros/src/validations/length.rs b/packages/fortifier-macros/src/validations/length.rs index 2e03c88..ec32494 100644 --- a/packages/fortifier-macros/src/validations/length.rs +++ b/packages/fortifier-macros/src/validations/length.rs @@ -2,7 +2,7 @@ use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::{Expr, Ident, Result, meta::ParseNestedMeta}; -use crate::validation::Validation; +use crate::validation::{Execution, Validation}; #[derive(Default)] pub struct Length { @@ -39,37 +39,38 @@ impl Validation for Length { Ok(result) } - fn is_async(&self) -> bool { - false - } - fn ident(&self) -> Ident { format_ident!("Length") } fn error_type(&self) -> TokenStream { - quote!(LengthError) + quote!(::fortifier::LengthError) } - fn tokens(&self, expr: &TokenStream) -> TokenStream { - let equal = if let Some(equal) = &self.equal { - quote!(Some(#equal)) - } else { - quote!(None) - }; - let min = if let Some(min) = &self.min { - quote!(Some(#min)) - } else { - quote!(None) - }; - let max = if let Some(max) = &self.max { - quote!(Some(#max)) - } else { - quote!(None) - }; + fn expr(&self, exeuction: Execution, expr: &TokenStream) -> Option { + match exeuction { + Execution::Sync => { + let equal = if let Some(equal) = &self.equal { + quote!(Some(#equal)) + } else { + quote!(None) + }; + let min = if let Some(min) = &self.min { + quote!(Some(#min)) + } else { + quote!(None) + }; + let max = if let Some(max) = &self.max { + quote!(Some(#max)) + } else { + quote!(None) + }; - quote! { - #expr.validate_length(#equal, #min, #max) + Some(quote! { + ::fortifier::ValidateLength::validate_length(&#expr, #equal, #min, #max) + }) + } + Execution::Async => None, } } } diff --git a/packages/fortifier-macros/src/validations/regex.rs b/packages/fortifier-macros/src/validations/regex.rs index da9d642..ad4eec4 100644 --- a/packages/fortifier-macros/src/validations/regex.rs +++ b/packages/fortifier-macros/src/validations/regex.rs @@ -2,7 +2,7 @@ use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::{Expr, Ident, Result, meta::ParseNestedMeta}; -use crate::validation::Validation; +use crate::validation::{Execution, Validation}; pub struct Regex { expression: Expr, @@ -33,23 +33,24 @@ impl Validation for Regex { Ok(Regex { expression }) } - fn is_async(&self) -> bool { - false - } - fn ident(&self) -> Ident { format_ident!("Regex") } fn error_type(&self) -> TokenStream { - quote!(RegexError) + quote!(::fortifier::RegexError) } - fn tokens(&self, expr: &TokenStream) -> TokenStream { - let expression = &self.expression; + fn expr(&self, execution: Execution, expr: &TokenStream) -> Option { + match execution { + Execution::Sync => { + let expression = &self.expression; - quote! { - #expr.validate_regex(#expression) + Some(quote! { + ::fortifier::ValidateRegex::validate_regex(&#expr, #expression) + }) + } + Execution::Async => None, } } } diff --git a/packages/fortifier-macros/src/validations/url.rs b/packages/fortifier-macros/src/validations/url.rs index d88875b..547bb6e 100644 --- a/packages/fortifier-macros/src/validations/url.rs +++ b/packages/fortifier-macros/src/validations/url.rs @@ -2,7 +2,7 @@ use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::{Ident, Result, meta::ParseNestedMeta}; -use crate::validation::Validation; +use crate::validation::{Execution, Validation}; #[derive(Default)] pub struct Url {} @@ -12,21 +12,20 @@ impl Validation for Url { Ok(Url::default()) } - fn is_async(&self) -> bool { - false - } - fn ident(&self) -> Ident { format_ident!("Url") } fn error_type(&self) -> TokenStream { - quote!(UrlError) + quote!(::fortifier::UrlError) } - fn tokens(&self, expr: &TokenStream) -> TokenStream { - quote! { - #expr.validate_url() + fn expr(&self, execution: Execution, expr: &TokenStream) -> Option { + match execution { + Execution::Sync => Some(quote! { + ::fortifier::ValidateUrl::validate_url(&#expr) + }), + Execution::Async => None, } } } diff --git a/packages/fortifier-macros/tests/derive/struct_named_generics_pass.rs b/packages/fortifier-macros/tests/derive/struct_named_generics_pass.rs index 13df7e2..2002eee 100644 --- a/packages/fortifier-macros/tests/derive/struct_named_generics_pass.rs +++ b/packages/fortifier-macros/tests/derive/struct_named_generics_pass.rs @@ -1,6 +1,6 @@ use std::error::Error; -use fortifier::Validate; +use fortifier::{Validate, ValidateEmail, ValidateLength}; #[derive(Validate)] struct CreateUser> { diff --git a/packages/fortifier-macros/tests/derive/struct_unnamed_generics_pass.rs b/packages/fortifier-macros/tests/derive/struct_unnamed_generics_pass.rs index ce5e95e..eee76c5 100644 --- a/packages/fortifier-macros/tests/derive/struct_unnamed_generics_pass.rs +++ b/packages/fortifier-macros/tests/derive/struct_unnamed_generics_pass.rs @@ -1,6 +1,6 @@ use std::error::Error; -use fortifier::Validate; +use fortifier::{Validate, ValidateLength}; #[derive(Validate)] struct CreateUser>(#[validate(length(min = 1, max = 256))] N);