11use std:: collections:: HashMap ;
22
33use convert_case:: { Case , Casing } ;
4- use proc_macro2:: TokenStream ;
4+ use proc_macro2:: { Literal , TokenStream } ;
55use quote:: { ToTokens , TokenStreamExt , format_ident, quote} ;
66use syn:: { DataStruct , DeriveInput , Fields , FieldsNamed , FieldsUnnamed , Ident , Result } ;
77
@@ -54,10 +54,11 @@ impl ValidateNamedStruct {
5454 continue ;
5555 } ;
5656
57- result. fields . insert (
58- field_ident. clone ( ) ,
59- ValidateField :: parse ( field_ident. clone ( ) , field) ?,
60- ) ;
57+ let expr = quote ! ( self . #field_ident) ;
58+
59+ result
60+ . fields
61+ . insert ( field_ident. clone ( ) , ValidateField :: parse ( expr, field) ?) ;
6162 }
6263
6364 Ok ( result)
@@ -147,26 +148,108 @@ impl ToTokens for ValidateNamedStruct {
147148}
148149
149150pub struct ValidateUnnamedStruct {
150- #[ allow( unused) ]
151151 ident : Ident ,
152- # [ allow ( unused ) ]
152+ error_ident : Ident ,
153153 fields : Vec < ValidateField > ,
154154}
155155
156156impl ValidateUnnamedStruct {
157- fn parse ( input : & DeriveInput , _data : & DataStruct , _fields : & FieldsUnnamed ) -> Result < Self > {
158- let result = Self {
157+ fn parse ( input : & DeriveInput , _data : & DataStruct , fields : & FieldsUnnamed ) -> Result < Self > {
158+ let mut result = Self {
159159 ident : input. ident . clone ( ) ,
160+ error_ident : format_ident ! ( "{}ValidationError" , input. ident) ,
160161 fields : Vec :: default ( ) ,
161162 } ;
162163
164+ for ( index, field) in fields. unnamed . iter ( ) . enumerate ( ) {
165+ let index = Literal :: usize_unsuffixed ( index) ;
166+ let expr = quote ! ( self . #index) ;
167+
168+ result. fields . push ( ValidateField :: parse ( expr, field) ?) ;
169+ }
170+
163171 Ok ( result)
164172 }
165173}
166174
167175impl ToTokens for ValidateUnnamedStruct {
168- fn to_tokens ( & self , _tokens : & mut TokenStream ) {
169- // TODO
176+ fn to_tokens ( & self , tokens : & mut TokenStream ) {
177+ let ident = & self . ident ;
178+ let error_ident = & self . error_ident ;
179+ let mut error_field_idents = vec ! [ ] ;
180+ let mut error_field_types = vec ! [ ] ;
181+ let mut sync_validations = vec ! [ ] ;
182+ let mut async_validations = vec ! [ ] ;
183+
184+ for ( index, field) in self . fields . iter ( ) . enumerate ( ) {
185+ let field_error_ident = format_ident ! ( "F{index}" ) ;
186+
187+ error_field_idents. push ( field_error_ident. clone ( ) ) ;
188+ error_field_types. push ( field. error_type ( ) ) ;
189+
190+ for validation in field. sync_validations ( ) {
191+ sync_validations. push ( quote ! {
192+ if let Err ( err) = #validation {
193+ errors. push( #error_ident:: #field_error_ident( err) ) ;
194+ }
195+ } ) ;
196+ }
197+
198+ for validation in field. async_validations ( ) {
199+ async_validations. push ( quote ! {
200+ if let Err ( err) = #validation {
201+ errors. push( #error_ident:: #field_error_ident( err) ) ;
202+ }
203+ } ) ;
204+ }
205+ }
206+
207+ tokens. append_all ( quote ! {
208+ use fortifier:: * ;
209+
210+ #[ derive( Debug ) ]
211+ enum #error_ident {
212+ #( #error_field_idents( #error_field_types) ) , *
213+ }
214+
215+ impl :: std:: fmt:: Display for #error_ident {
216+ fn fmt( & self , f: & mut :: std:: fmt:: Formatter <' _>) -> :: std:: fmt:: Result {
217+ write!( f, "{self:#?}" )
218+ }
219+ }
220+
221+ impl :: std:: error:: Error for #error_ident { }
222+
223+ impl Validate for #ident {
224+ type Error = #error_ident;
225+
226+ fn validate_sync( & self ) -> Result <( ) , ValidationErrors <Self :: Error >> {
227+ let mut errors = vec![ ] ;
228+
229+ #( #sync_validations) *
230+
231+ if !errors. is_empty( ) {
232+ Err ( errors. into( ) )
233+ } else {
234+ Ok ( ( ) )
235+ }
236+ }
237+
238+ fn validate_async( & self ) -> :: std:: pin:: Pin <Box <impl Future <Output = Result <( ) , ValidationErrors <Self :: Error >>>>> {
239+ Box :: pin( async {
240+ let mut errors = vec![ ] ;
241+
242+ #( #async_validations) *
243+
244+ if !errors. is_empty( ) {
245+ Err ( errors. into( ) )
246+ } else {
247+ Ok ( ( ) )
248+ }
249+ } )
250+ }
251+ }
252+ } )
170253 }
171254}
172255
@@ -187,8 +270,10 @@ impl ToTokens for ValidateUnitStruct {
187270 let ident = & self . ident ;
188271
189272 tokens. append_all ( quote ! {
273+ use fortifier:: ValidationErrors ;
274+
190275 impl Validate for #ident {
191- type Error = Infallible ;
276+ type Error = :: std :: convert :: Infallible ;
192277
193278 fn validate_sync( & self ) -> Result <( ) , ValidationErrors <Self :: Error >> {
194279 Ok ( ( ) )
0 commit comments