Skip to content

Commit 9fadf88

Browse files
feat: improve type heuristics by adding generics and more built-in types (#44)
1 parent 0539c9f commit 9fadf88

File tree

11 files changed

+421
-62
lines changed

11 files changed

+421
-62
lines changed

packages/fortifier-macros/src/validate/enum.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use proc_macro2::TokenStream;
22
use quote::{format_ident, quote};
3-
use syn::{DataEnum, DeriveInput, Ident, Result, Variant, Visibility};
3+
use syn::{DataEnum, DeriveInput, Generics, Ident, Result, Variant, Visibility};
44

55
use crate::{
66
validate::{
@@ -30,6 +30,7 @@ impl<'a> ValidateEnum<'a> {
3030
for variant in &data.variants {
3131
result.variants.push(ValidateEnumVariant::parse(
3232
&input.vis,
33+
&input.generics,
3334
result.ident,
3435
result.error_ident.clone(),
3536
variant,
@@ -109,6 +110,7 @@ pub struct ValidateEnumVariant<'a> {
109110
impl<'a> ValidateEnumVariant<'a> {
110111
pub fn parse(
111112
visibility: &'a Visibility,
113+
generics: &'a Generics,
112114
enum_ident: &'a Ident,
113115
enum_error_ident: Ident,
114116
variant: &'a Variant,
@@ -119,6 +121,7 @@ impl<'a> ValidateEnumVariant<'a> {
119121
ident: &variant.ident,
120122
fields: ValidateFields::parse(
121123
visibility,
124+
generics,
122125
format_ident!("{}{}", enum_ident, variant.ident),
123126
&variant.fields,
124127
)?,

packages/fortifier-macros/src/validate/field.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use convert_case::{Case, Casing};
22
use proc_macro2::{Literal, TokenStream};
33
use quote::{ToTokens, format_ident, quote};
4-
use syn::{Error, Field, Ident, Result, Visibility};
4+
use syn::{Error, Field, Generics, Ident, Result, Visibility};
55

66
use crate::{
77
validate::{
@@ -46,6 +46,7 @@ pub struct ValidateField<'a> {
4646
impl<'a> ValidateField<'a> {
4747
pub fn parse(
4848
visibility: &'a Visibility,
49+
generics: &'a Generics,
4950
type_prefix: &Ident,
5051
ident: LiteralOrIdent,
5152
field: &Field,
@@ -128,10 +129,9 @@ impl<'a> ValidateField<'a> {
128129
}
129130
}
130131

131-
// TODO: Use enum/struct generics to determine if a generic field type supports nested validation.
132132
if !skip_nested
133133
&& result.validations.is_empty()
134-
&& let Some(nested_type) = should_validate_type(&field.ty)
134+
&& let Some(nested_type) = should_validate_type(generics, &field.ty)
135135
{
136136
if let KnownOrUnknown::Known(nested_type) = nested_type {
137137
result.validations.push(Box::new(Nested::new(nested_type)));

packages/fortifier-macros/src/validate/fields.rs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::iter::empty;
22

33
use proc_macro2::{Literal, TokenStream};
44
use quote::quote;
5-
use syn::{Fields, FieldsNamed, FieldsUnnamed, Ident, Result, Visibility};
5+
use syn::{Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Result, Visibility};
66

77
use crate::{
88
validate::{
@@ -22,14 +22,19 @@ pub enum ValidateFields<'a> {
2222
}
2323

2424
impl<'a> ValidateFields<'a> {
25-
pub fn parse(visibility: &'a Visibility, ident: Ident, fields: &'a Fields) -> Result<Self> {
25+
pub fn parse(
26+
visibility: &'a Visibility,
27+
generics: &'a Generics,
28+
ident: Ident,
29+
fields: &'a Fields,
30+
) -> Result<Self> {
2631
Ok(match fields {
27-
Fields::Named(fields) => {
28-
Self::Named(ValidateNamedFields::parse(visibility, ident, fields)?)
29-
}
30-
Fields::Unnamed(fields) => {
31-
Self::Unnamed(ValidateUnnamedFields::parse(visibility, ident, fields)?)
32-
}
32+
Fields::Named(fields) => Self::Named(ValidateNamedFields::parse(
33+
visibility, generics, ident, fields,
34+
)?),
35+
Fields::Unnamed(fields) => Self::Unnamed(ValidateUnnamedFields::parse(
36+
visibility, generics, ident, fields,
37+
)?),
3338
Fields::Unit => Self::Unit(ValidateUnitFields::parse(visibility, ident)?),
3439
})
3540
}
@@ -94,7 +99,12 @@ pub struct ValidateNamedFields<'a> {
9499
}
95100

96101
impl<'a> ValidateNamedFields<'a> {
97-
fn parse(visibility: &'a Visibility, ident: Ident, fields: &'a FieldsNamed) -> Result<Self> {
102+
fn parse(
103+
visibility: &'a Visibility,
104+
generics: &'a Generics,
105+
ident: Ident,
106+
fields: &'a FieldsNamed,
107+
) -> Result<Self> {
98108
let error_ident = format_error_ident(&ident);
99109

100110
let mut result = Self {
@@ -111,6 +121,7 @@ impl<'a> ValidateNamedFields<'a> {
111121

112122
result.fields.push(ValidateField::parse(
113123
visibility,
124+
generics,
114125
&result.ident,
115126
LiteralOrIdent::Ident(field_ident.clone()),
116127
field,
@@ -173,7 +184,12 @@ pub struct ValidateUnnamedFields<'a> {
173184
}
174185

175186
impl<'a> ValidateUnnamedFields<'a> {
176-
fn parse(visibility: &'a Visibility, ident: Ident, fields: &'a FieldsUnnamed) -> Result<Self> {
187+
fn parse(
188+
visibility: &'a Visibility,
189+
generics: &'a Generics,
190+
ident: Ident,
191+
fields: &'a FieldsUnnamed,
192+
) -> Result<Self> {
177193
let error_ident = format_error_ident(&ident);
178194

179195
let mut result = Self {
@@ -186,6 +202,7 @@ impl<'a> ValidateUnnamedFields<'a> {
186202
for (index, field) in fields.unnamed.iter().enumerate() {
187203
result.fields.push(ValidateField::parse(
188204
visibility,
205+
generics,
189206
&result.ident,
190207
LiteralOrIdent::Literal(Literal::usize_unsuffixed(index)),
191208
field,

packages/fortifier-macros/src/validate/struct.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ pub struct ValidateStruct<'a> {
1313
impl<'a> ValidateStruct<'a> {
1414
pub fn parse(input: &'a DeriveInput, data: &'a DataStruct) -> Result<Self> {
1515
Ok(ValidateStruct {
16-
fields: ValidateFields::parse(&input.vis, input.ident.clone(), &data.fields)?,
16+
fields: ValidateFields::parse(
17+
&input.vis,
18+
&input.generics,
19+
input.ident.clone(),
20+
&data.fields,
21+
)?,
1722
})
1823
}
1924

0 commit comments

Comments
 (0)