Skip to content

Commit

Permalink
wip: support warnings.
Browse files Browse the repository at this point in the history
  • Loading branch information
yassun7010 committed Jun 14, 2024
1 parent c192c36 commit 6f9e486
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 81 deletions.
1 change: 1 addition & 0 deletions serde_valid_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ proc-macro = true
[dependencies]
paste = { workspace = true }
proc-macro-error = "^1.0"
proc-macro-warning = "1.0.2"
proc-macro2 = "^1.0"
quote = "^1.0"
strsim = "0.11.0"
Expand Down
24 changes: 21 additions & 3 deletions serde_valid_derive/src/attribute/rule/named_struct_rule.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
use std::collections::HashSet;

use proc_macro2::TokenStream;
use proc_macro_warning::FormattedWarning;
use quote::{quote, ToTokens};
use syn::spanned::Spanned;

use crate::types::{CommaSeparatedNestedMetas, CommaSeparatedTokenStreams};
use crate::{
output_stream::OutputStream,
types::{CommaSeparatedNestedMetas, CommaSeparatedTokenStreams},
};

pub fn collect_rules_from_named_struct(
attributes: &[syn::Attribute],
) -> Result<(HashSet<syn::Ident>, TokenStream), crate::Errors> {
) -> Result<(HashSet<syn::Ident>, OutputStream), crate::Errors> {
let mut errors = vec![];

let mut rule_fields = HashSet::new();
let mut warnings = vec![];
let rules = attributes
.iter()
.filter(|attribute| attribute.path().is_ident("rule"))
.inspect(|attribute| {
warnings.push(FormattedWarning::new_deprecated(
"rule",
"#[rule(...)] is deprecated, use #[validate(custom(...)))] instead",
attribute.bracket_token.span.span(),
));
})
.filter_map(|attribute| match &attribute.meta {
syn::Meta::List(list) => match collect_rule(list) {
Ok((field_ident, stream)) => {
Expand All @@ -36,7 +48,13 @@ pub fn collect_rules_from_named_struct(
.collect::<Vec<_>>();

if errors.is_empty() {
Ok((rule_fields, TokenStream::from_iter(rules)))
Ok((
rule_fields,
OutputStream {
output: TokenStream::from_iter(rules),
warnings,
},
))
} else {
Err(errors)
}
Expand Down
5 changes: 3 additions & 2 deletions serde_valid_derive/src/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ mod unnamed_struct_derive;

use enum_derive::expand_enum_validate_derive;
use named_struct_derive::expand_named_struct_derive;
use proc_macro2::TokenStream;
use unnamed_struct_derive::expand_unnamed_struct_derive;

pub fn expand_derive(input: &syn::DeriveInput) -> Result<TokenStream, crate::Errors> {
use crate::output_stream::OutputStream;

pub fn expand_derive(input: &syn::DeriveInput) -> Result<OutputStream, crate::Errors> {
match &input.data {
syn::Data::Struct(syn::DataStruct { ref fields, .. }) => match fields {
syn::Fields::Named(fields) => expand_named_struct_derive(input, fields),
Expand Down
109 changes: 69 additions & 40 deletions serde_valid_derive/src/derive/enum_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::named_struct_derive::collect_named_fields_validators_list;
use super::unnamed_struct_derive::collect_unnamed_fields_validators_list;
use crate::attribute::rule::{collect_rules_from_named_struct, collect_rules_from_unnamed_struct};
use crate::error::{array_errors_tokens, new_type_errors_tokens, object_errors_tokens};
use crate::output_stream::OutputStream;
use crate::serde::rename::collect_serde_rename_map;
use crate::types::CommaSeparatedTokenStreams;
use proc_macro2::TokenStream;
Expand All @@ -14,20 +15,21 @@ pub type Variants = syn::punctuated::Punctuated<syn::Variant, syn::token::Comma>
pub fn expand_enum_validate_derive(
input: &syn::DeriveInput,
variants: &Variants,
) -> Result<TokenStream, crate::Errors> {
) -> Result<OutputStream, crate::Errors> {
let ident = &input.ident;
let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();

let mut errors = vec![];

let validations_and_rules =
TokenStream::from_iter(variants.iter().map(|variant| match &variant.fields {
let validations = variants
.into_iter()
.map(|variant| match &variant.fields {
syn::Fields::Named(named_fields) => {
match expand_enum_variant_named_fields(ident, variant, named_fields) {
match expand_enum_variant_named_fields_validation(ident, variant, named_fields) {
Ok(variant_varidates_and_rules) => variant_varidates_and_rules,
Err(variant_errors) => {
errors.extend(variant_errors);
quote!()
OutputStream::new()
}
}
}
Expand All @@ -37,44 +39,65 @@ pub fn expand_enum_validate_derive(
Ok(variant_varidates_and_rules) => variant_varidates_and_rules,
Err(variant_errors) => {
errors.extend(variant_errors);
quote!()
OutputStream::new()
}
}
}
syn::Fields::Unit => quote!(),
}));
syn::Fields::Unit => OutputStream::new(),
})
.collect::<Vec<_>>();

let validations_and_rules = TokenStream::from_iter(
validations
.iter()
.map(|variant| variant.output.clone())
.collect::<Vec<_>>(),
);
let warnings = validations
.into_iter()
.flat_map(|variant| variant.warnings)
.collect::<Vec<_>>();

if errors.is_empty() {
Ok(quote!(
impl #impl_generics ::serde_valid::Validate for #ident #type_generics #where_clause {
fn validate(&self) -> std::result::Result<(), ::serde_valid::validation::Errors> {
#validations_and_rules
Ok(OutputStream {
output: quote!(
impl #impl_generics ::serde_valid::Validate for #ident #type_generics #where_clause {
fn validate(&self) -> std::result::Result<(), ::serde_valid::validation::Errors> {
#validations_and_rules

Ok(())
Ok(())
}
}
}
))
),
warnings,
})
} else {
Err(errors)
}
}

fn expand_enum_variant_named_fields(
fn expand_enum_variant_named_fields_validation(
ident: &syn::Ident,
variant: &syn::Variant,
named_fields: &syn::FieldsNamed,
) -> Result<TokenStream, crate::Errors> {
) -> Result<OutputStream, crate::Errors> {
let mut errors = vec![];

let variant_ident = &variant.ident;
let mut fields_idents = CommaSeparatedTokenStreams::new();
let rename_map = collect_serde_rename_map(named_fields);

let (rule_fields, rules) = match collect_rules_from_named_struct(&variant.attrs) {
let (
rule_fields,
OutputStream {
output: rules,
warnings,
},
) = match collect_rules_from_named_struct(&variant.attrs) {
Ok(field_rules) => field_rules,
Err(variant_errors) => {
errors.extend(variant_errors);
(HashSet::new(), quote!())
(HashSet::new(), OutputStream::new())
}
};

Expand Down Expand Up @@ -105,19 +128,22 @@ fn expand_enum_variant_named_fields(
let variant_errors = object_errors_tokens();

if errors.is_empty() {
Ok(quote!(
if let #ident::#variant_ident{#fields_idents} = &self {
let mut __rule_vec_errors = ::serde_valid::validation::VecErrors::new();
let mut __property_vec_errors_map = ::serde_valid::validation::PropertyVecErrorsMap::new();
Ok(OutputStream {
output: quote!(
if let #ident::#variant_ident{#fields_idents} = &self {
let mut __rule_vec_errors = ::serde_valid::validation::VecErrors::new();
let mut __property_vec_errors_map = ::serde_valid::validation::PropertyVecErrorsMap::new();

#validates
#rules
#validates
#rules

if !(__rule_vec_errors.is_empty() && __property_vec_errors_map.is_empty()) {
Err(#variant_errors)?
if !(__rule_vec_errors.is_empty() && __property_vec_errors_map.is_empty()) {
Err(#variant_errors)?
}
}
}
))
),
warnings,
})
} else {
Err(errors)
}
Expand All @@ -127,7 +153,7 @@ fn expand_enum_variant_unnamed_fields_varidation(
ident: &syn::Ident,
variant: &syn::Variant,
unnamed_fields: &syn::FieldsUnnamed,
) -> Result<TokenStream, crate::Errors> {
) -> Result<OutputStream, crate::Errors> {
let mut errors = vec![];

let variant_ident = &variant.ident;
Expand Down Expand Up @@ -172,19 +198,22 @@ fn expand_enum_variant_unnamed_fields_varidation(
};

if errors.is_empty() {
Ok(quote!(
if let #ident::#variant_ident(#fields_idents) = &self {
let mut __rule_vec_errors = ::serde_valid::validation::VecErrors::new();
let mut __item_vec_errors_map = ::serde_valid::validation::ItemVecErrorsMap::new();
Ok(OutputStream {
output: quote!(
if let #ident::#variant_ident(#fields_idents) = &self {
let mut __rule_vec_errors = ::serde_valid::validation::VecErrors::new();
let mut __item_vec_errors_map = ::serde_valid::validation::ItemVecErrorsMap::new();

#validates
#rules
#validates
#rules

if !(__rule_vec_errors.is_empty() && __item_vec_errors_map.is_empty()) {
Err(#variant_errors)?
if !(__rule_vec_errors.is_empty() && __item_vec_errors_map.is_empty()) {
Err(#variant_errors)?
}
}
}
))
),
warnings: vec![],
})
} else {
Err(errors)
}
Expand Down
46 changes: 28 additions & 18 deletions serde_valid_derive/src/derive/named_struct_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::attribute::field_validate::{extract_field_validator, FieldValidators}
use crate::attribute::rule::collect_rules_from_named_struct;
use crate::attribute::struct_validate::collect_struct_custom_from_named_struct;
use crate::error::object_errors_tokens;
use crate::output_stream::OutputStream;
use crate::serde::rename::{collect_serde_rename_map, RenameMap};
use crate::types::{Field, NamedField};
use proc_macro2::TokenStream;
Expand All @@ -13,18 +14,24 @@ use std::iter::FromIterator;
pub fn expand_named_struct_derive(
input: &syn::DeriveInput,
fields: &syn::FieldsNamed,
) -> Result<TokenStream, crate::Errors> {
) -> Result<OutputStream, crate::Errors> {
let ident = &input.ident;
let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
let rename_map = collect_serde_rename_map(fields);

let mut errors = vec![];

let (rule_fields, rules) = match collect_rules_from_named_struct(&input.attrs) {
Ok((rule_fields, rules)) => (rule_fields, TokenStream::from_iter(rules)),
let (
rule_fields,
OutputStream {
output: rules,
warnings,
},
) = match collect_rules_from_named_struct(&input.attrs) {
Ok((rule_fields, rules)) => (rule_fields, rules),
Err(rule_errors) => {
errors.extend(rule_errors);
(HashSet::new(), quote!())
(HashSet::new(), OutputStream::new())
}
};
let struct_validations = match collect_struct_custom_from_named_struct(&input.attrs) {
Expand Down Expand Up @@ -52,24 +59,27 @@ pub fn expand_named_struct_derive(
let fields_errors = object_errors_tokens();

if errors.is_empty() {
Ok(quote!(
impl #impl_generics ::serde_valid::Validate for #ident #type_generics #where_clause {
fn validate(&self) -> std::result::Result<(), ::serde_valid::validation::Errors> {
let mut __rule_vec_errors = ::serde_valid::validation::VecErrors::new();
let mut __property_vec_errors_map = ::serde_valid::validation::PropertyVecErrorsMap::new();
Ok(OutputStream {
output: quote!(
impl #impl_generics ::serde_valid::Validate for #ident #type_generics #where_clause {
fn validate(&self) -> std::result::Result<(), ::serde_valid::validation::Errors> {
let mut __rule_vec_errors = ::serde_valid::validation::VecErrors::new();
let mut __property_vec_errors_map = ::serde_valid::validation::PropertyVecErrorsMap::new();

#field_validates
#struct_validations
#rules
#field_validates
#struct_validations
#rules

if __rule_vec_errors.is_empty() && __property_vec_errors_map.is_empty() {
Ok(())
} else {
Err(#fields_errors)
if __rule_vec_errors.is_empty() && __property_vec_errors_map.is_empty() {
Ok(())
} else {
Err(#fields_errors)
}
}
}
}
))
),
warnings,
})
} else {
Err(errors)
}
Expand Down
Loading

0 comments on commit 6f9e486

Please sign in to comment.