derive_attribute_macros/
lib.rs

1use convert_case::{Casing, Case};
2use proc_macro2::{Span, Ident, TokenStream};
3use quote::{quote, TokenStreamExt, format_ident};
4use syn_v2::{DeriveInput, Data, spanned::Spanned, Field, parse_macro_input};
5
6use derive_attribute_utils::{TryFromMeta, Syn2, ArgResult, Error, ErrorMsg::{*, self}, SynVersion, Concat, GetSpan, AttributeName, Attribute, CustomArgFromMeta, CustomArg};
7
8#[proc_macro_derive(Attribute, attributes(attr))]
9pub fn derive_attribute(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
10
11    let ast = parse_macro_input!(input as DeriveInput);
12
13    let maybe_output = attempt_derive_attr(ast);
14    let output = 
15        match maybe_output {
16            Ok(output) => output,
17            Err(errors) => {
18                let compile_errors = errors.into_iter().map(|e| e.to_compile_error());
19                quote!(#(#compile_errors)*)
20            }
21        };
22
23    output.into()
24}
25fn attempt_derive_attr(ast: DeriveInput) -> Result<TokenStream, Vec<syn_v2::Error>> {
26    let mut all_errors = vec![];
27
28    let maybe_container_attr = AttributeAttribute::from_attrs(ast.ident.span(), ast.attrs)?;
29
30    let struct_data =
31        match ast.data {
32            Data::Struct(struct_date) => struct_date,
33            _ => {
34                all_errors.push(syn_v2::Error::new(ast.ident.span(), "Invalid body expected struct"));
35                return Err(all_errors)
36            }
37        };
38
39    let mut builder = AttributeTraitBuilder::new(ast.ident, maybe_container_attr);
40    
41
42
43    for field in struct_data.fields {
44        let field_attr = 
45            match AttributeAttribute::from_attrs(field.ident.span(), field.attrs.clone()) {
46                Ok(attr) => attr,
47                Err(ref mut errors) => {
48                    all_errors.append(errors);
49                    continue;
50                }
51            };
52
53        builder.check_field(field, field_attr);
54        
55    }
56
57    let output = builder.build();
58
59    match all_errors.len() {
60        0 => Ok(output),
61        _ => Err(all_errors)
62    }
63}
64
65
66
67#[proc_macro_derive(List, attributes(attr))]
68pub fn derive_list(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
69
70    let ast = parse_macro_input!(input as DeriveInput);
71
72    let maybe_output = attempt_derive_list(ast);
73    let output = 
74        match maybe_output {
75            Ok(output) => output,
76            Err(errors) => {
77                let compile_errors = errors.into_iter().map(|e| e.to_compile_error());
78                quote!(#(#compile_errors)*)
79            }
80        };
81
82    output.into()
83}
84fn attempt_derive_list(ast: DeriveInput) -> Result<TokenStream, Vec<syn_v2::Error>> {
85    let mut all_errors = vec![];
86
87    let struct_data =
88        match ast.data {
89            Data::Struct(struct_date) => struct_date,
90            _ => {
91                all_errors.push(syn_v2::Error::new(ast.ident.span(), "Invalid body expected struct"));
92                return Err(all_errors)
93            }
94        };
95
96    let mut builder = ListTraitBuilder::new(ast.ident);
97    
98
99
100    for field in struct_data.fields {
101        let field_attr = 
102            match AttributeAttribute::from_attrs(field.ident.span(), field.attrs.clone()) {
103                Ok(attr) => attr,
104                Err(ref mut errors) => {
105                    all_errors.append(errors);
106                    continue;
107                }
108            };
109
110        builder.check_field(field, field_attr);
111        
112    }
113
114    let output = builder.build();
115
116    match all_errors.len() {
117        0 => Ok(output),
118        _ => Err(all_errors)
119    }
120}
121
122
123
124
125
126
127
128
129
130struct BuilderParts {
131    builder_name: Ident,
132    field_declaration: TokenStream,
133    field_expansion: TokenStream,
134    concat_parts: TokenStream
135}
136impl BuilderParts {
137    fn new(struct_name: &Ident) -> Self {
138        Self {
139            builder_name: format_ident!("{struct_name}Builder"),
140            field_declaration: TokenStream::new(),
141            field_expansion: TokenStream::new(),
142            concat_parts: TokenStream::new()
143        }
144    }
145    fn generate_builder(self) -> (TokenStream, Ident) {
146        let Self { builder_name, field_declaration, field_expansion, concat_parts } = self;
147
148        let declaration = 
149            quote!{
150                struct #builder_name<V: SynVersion> {
151                    #field_declaration
152                }
153                impl<V: SynVersion> #builder_name<V> {
154                    fn new(location: Span) -> Self {
155                        Self {
156                            #field_expansion
157                        }
158                    } 
159                }
160                impl<V: SynVersion> Concat for #builder_name<V> {
161                    const NO_DUPLICATES: bool = false;
162
163                    fn concat(&mut self, other: Self) {
164                        #concat_parts
165                    }
166                }
167            };
168
169        (declaration, builder_name)
170    }
171}
172
173
174struct Validation {
175    validate_arguments: TokenStream,
176    expansion: TokenStream
177}
178impl Validation {
179    fn new() -> Self {
180        Self {
181            validate_arguments: TokenStream::new(),
182            expansion: TokenStream::new()
183        }
184    }
185}
186
187struct TryFrom {
188    match_branches: TokenStream
189}
190impl TryFrom {
191    fn new() -> Self {
192        Self {
193            match_branches: TokenStream::new()
194        }
195    }
196}
197
198struct MacroBase {
199    struct_name: Ident,
200    builder_parts: BuilderParts,
201    try_from: TryFrom,
202    validation: Validation,
203}
204impl MacroBase {
205    fn new(struct_name: Ident) -> Self {
206        Self {
207            struct_name: struct_name.clone(),
208            builder_parts: BuilderParts::new(&struct_name),
209            try_from: TryFrom::new(),
210            validation: Validation::new()
211        }
212    }
213
214    fn check_field(&mut self, field: Field, attribute: AttributeAttribute) {
215        let Self { builder_parts, try_from, validation, ..} = self;
216
217        let field_name = field.ident.unwrap();
218        let field_type = field.ty;
219        
220        {
221            let field_decl = quote!{ #field_name: ArgResult<<#field_type as TryFromMeta<V>>::InitialType>, };
222            builder_parts.field_declaration.append_all(field_decl);
223        }
224
225        {
226            let field_expansion = quote!{ #field_name: ArgResult::new(location), };
227            builder_parts.field_expansion.append_all(field_expansion);
228        }
229        
230        {
231            let concat_part = quote!{self.#field_name.concat(other.#field_name);};
232            builder_parts.concat_parts.append_all(concat_part);
233        }
234
235        let field_name_str = 
236            match attribute.name {
237                Some(name) => name,
238                None => field_name.to_string()
239            };
240        {
241            let branch = 
242                quote!{
243                    #field_name_str => {
244                        let value = <#field_type as TryFromMeta<V>>::try_from_meta(arg);
245                        builder.#field_name.concat(value);
246                    }
247                };
248            try_from.match_branches.append_all(branch);
249        }
250   
251        let field_type_str = field_name.to_string();
252        {
253            let normal_validation = 
254                quote!{
255                    let mut #field_name = <#field_type as TryFromMeta<V>>::validate(builder.#field_name, #field_type_str);
256                    if let Err(ref mut errors) = #field_name {
257                        state.errors.append(errors);
258                    }
259                };
260
261            let validate_field = 
262                match attribute.default {
263                    Some(arg) => {
264                        let x = 
265                            match arg.0 {
266                                Default::UseSelfDefault => quote!{ <#field_type as Default>::default() },
267                                Default::ChooseDefault(path) => quote![ #path() ]
268                            };
269
270                        quote!{
271                            let mut #field_name = 
272                            match builder.#field_name.value.is_none() && builder.#field_name.found_with_errors() == false {
273                                true => Ok(#x),
274                                false => {
275                                    #normal_validation
276
277                                    #field_name
278                                }
279                            };
280                        }
281                    }
282                    None => normal_validation
283                };
284            validation.validate_arguments.append_all(validate_field);
285        }
286        
287        {
288            let field_error = format!("failed to deserialize '{field_name_str}'");
289            let field_expansion = quote!{ #field_name: #field_name.expect(#field_error), };
290            validation.expansion.append_all(field_expansion);
291        }
292       
293    }
294}
295
296struct AttributeTraitBuilder {
297    container_attr: AttributeAttribute,
298    base: MacroBase
299}
300impl AttributeTraitBuilder {
301    fn new(struct_name: Ident, container_attr: AttributeAttribute) -> Self {
302        Self {
303            container_attr,
304            base: MacroBase::new(struct_name)
305        }
306    }
307    fn check_field(&mut self, field: Field, attribute: AttributeAttribute) {
308        self.base.check_field(field, attribute);
309    }
310
311    fn build(self) -> TokenStream {
312        let Self {
313            container_attr, 
314            base:
315                MacroBase { 
316                    struct_name, 
317                    builder_parts, 
318                    try_from, 
319                    validation
320                } 
321            } = self;
322
323        let set_default = 
324            match container_attr.default {
325                Some(CustomArg(Default::UseSelfDefault)) => quote!{ return Ok(<Self as Default>::default()) },
326                Some(CustomArg(Default::ChooseDefault(path))) => quote!{ return Ok(#path()) },
327                None => quote!()
328            };
329
330        let (builder_decl, builder_name) = builder_parts.generate_builder();
331        
332
333        let mut all_attribute_impls = TokenStream::new();
334        #[cfg(feature = "syn_1")]
335        {
336            let attr_impl =
337                quote!{
338                    use derive_attribute::Syn1;
339                    impl Attribute<Syn1> for #struct_name {} 
340                };
341            all_attribute_impls.append_all(attr_impl);
342        }
343        #[cfg(feature = "syn_2")]
344        {
345            let attr_impl =
346                quote!{
347                    use derive_attribute::Syn2;
348                    impl Attribute<Syn2> for #struct_name {} 
349                };
350            all_attribute_impls.append_all(attr_impl);
351        }
352
353
354        let name = 
355            match container_attr.name {
356                Some(name) => name,
357                None => struct_name.to_string().to_case(Case::Snake)
358            };
359
360        let try_from_fn = generate_try_from_meta(format_ident!("deserialize_attr_args"), &builder_name, try_from);
361        let validation_fn = generate_validate(validation, set_default, format_ident!("MissingAttribute"));
362
363        quote!{
364            const _: () = {
365                use derive_attribute::{AttributeName, TryFromMeta, Attribute, GetSpan, Concat, Error, ErrorMsg::*, SynVersion, ArgResult, reexports::proc_macro2::Span};
366
367                impl AttributeName for #struct_name {
368                    const NAME: &'static str = #name;
369                }
370
371                #all_attribute_impls
372
373                #builder_decl
374
375                impl<V: SynVersion> TryFromMeta<V> for #struct_name {
376                    type InitialType = #builder_name<V>;
377                
378                    type Metadata = V::Attribute;
379                    
380                    #try_from_fn
381                
382                    #validation_fn
383                }
384                
385            };
386        }
387     } 
388
389}
390
391
392struct ListTraitBuilder {
393    base: MacroBase
394}
395impl ListTraitBuilder {
396    fn new(struct_name: Ident) -> Self {
397        Self {
398            base: MacroBase::new(struct_name)
399        }
400    }
401    fn check_field(&mut self, field: Field, attribute: AttributeAttribute) {
402        self.base.check_field(field, attribute);
403    }
404    fn build(self) -> TokenStream {
405        let Self {
406            base: 
407                MacroBase { 
408                    struct_name, 
409                    builder_parts, 
410                    try_from, 
411                    validation
412                } 
413            } = self;
414
415        let (builder_decl, builder_name) = builder_parts.generate_builder();
416        
417        let try_from_fn = generate_try_from_meta(format_ident!("deserialize_list_args"), &builder_name, try_from);
418        let validation_fn = generate_validate(validation, quote!(), format_ident!("MissingArg"));
419
420        quote!{
421            const _: () = {
422                use derive_attribute::{AttributeName, TryFromMeta, Attribute, GetSpan, Concat, Error, ErrorMsg::*, SynVersion, ArgResult, reexports::proc_macro2::Span};
423
424
425                #builder_decl
426
427                impl<V: SynVersion> TryFromMeta<V> for #struct_name {
428                    type InitialType = #builder_name<V>;
429                
430                    type Metadata = V::ArgMeta;
431                    
432                    #try_from_fn
433                
434                    #validation_fn
435                }
436                
437            };
438        }
439        
440    }
441
442}
443
444
445
446fn generate_try_from_meta(deserialize_args: Ident, builder_name: &Ident, try_from: TryFrom) -> TokenStream {
447    let TryFrom { match_branches } = try_from;
448    quote!{
449        fn try_from_meta(arg_meta: Self::Metadata) -> ArgResult<Self::InitialType> {
450            let mut result = ArgResult::new(arg_meta.get_span());
451    
452            let mut builder = #builder_name::new(arg_meta.get_span());
453    
454            let attribute_args = 
455                match V::#deserialize_args(&arg_meta) {
456                    Some(args) => args,
457                    None => {
458                        result.add_error(InvalidType { expected: "list" });
459                        return result
460                    }
461                };
462            
463    
464            for arg in attribute_args {
465                let key = V::deserialize_key(&arg).expect("key failed");
466                match key.as_str() {
467                    #match_branches
468
469                    _ => result.errors.push(Error::new(arg.get_span(), InvalidArg))
470                }
471            }
472            result.add_value(builder);
473            result
474        }
475    }
476}
477
478fn generate_validate(validate: Validation, set_default: TokenStream, error_type: Ident) -> TokenStream {
479    let Validation { validate_arguments, expansion } = validate;
480    quote!{
481        fn validate(state: ArgResult<Self::InitialType>, arg_name: &'static str) -> Result<Self, Vec<Error>> {
482            let mut state = state;
483
484            if state.value.is_none() && state.found_with_errors() == false {
485                #set_default
486            }
487    
488            // let mut builder = 
489            //     match state.value {
490            //         Some(value) => value,
491            //         None => return Err(vec![Error::new(state.location, #error_type(arg_name))])
492            //     };
493
494            let mut builder =
495                match state.found_with_errors() {
496                    true => return Err(state.errors),
497                    false if state.value.is_none() => {
498                        state.add_error(#error_type(arg_name));
499                        return Err(state.errors);
500                    }
501                    false => state.value.unwrap()
502                };
503
504            #validate_arguments
505    
506    
507            match state.errors.len() {
508                0 => Ok(Self { #expansion }),
509                _ => Err(state.errors)
510            }
511        }
512    }
513}
514
515
516
517#[derive(Debug, Default)]
518struct AttributeAttribute {
519    name: Option<String>,
520    default: Option<CustomArg<Default>>,
521}
522
523struct AttributeAttributeBuilder<V: SynVersion> {
524    name: ArgResult<<Option<String> as TryFromMeta<V>>::InitialType>,
525    default: ArgResult<<Option<CustomArg<Default>> as TryFromMeta<V>>::InitialType>,
526}
527impl<V: SynVersion> AttributeAttributeBuilder<V> {
528    fn new(location: Span) -> Self {
529        Self { 
530            name: ArgResult::new(location),
531            default: ArgResult::new(location),
532        }
533    }
534}
535impl<V: SynVersion> Concat for AttributeAttributeBuilder<V> {
536    const NO_DUPLICATES: bool = false;
537    fn concat(&mut self, other: Self) {
538        self.name.concat(other.name);
539        self.default.concat(other.default);
540    }
541}
542
543
544impl Attribute<Syn2> for AttributeAttribute {}
545impl AttributeName for AttributeAttribute {
546    const NAME: &'static str = "attr";
547}
548impl<V: SynVersion> TryFromMeta<V> for AttributeAttribute {
549    type InitialType = AttributeAttributeBuilder<V>;
550
551    type Metadata = V::Attribute;
552    fn try_from_meta(arg_meta: Self::Metadata) -> ArgResult<Self::InitialType> {
553        let mut result = ArgResult::new(arg_meta.get_span());
554
555        let mut builder = AttributeAttributeBuilder::new(arg_meta.get_span());
556
557        let attribute_args = 
558            match V::deserialize_attr_args(&arg_meta) {
559                Some(args) => args,
560                None => {
561                    result.add_error(InvalidType { expected: "list" });
562                    return result
563                }
564            };
565
566
567        for arg in attribute_args {
568            let key = V::deserialize_key(&arg).expect("key failed");
569
570            match key.as_str() {
571                "name" => {
572                    let value = <Option<String> as TryFromMeta<V>>::try_from_meta(arg);
573                    builder.name.concat(value);
574                }
575                "default" => {
576                    let value = <Option<CustomArg<Default>> as TryFromMeta<V>>::try_from_meta(arg);
577                    builder.default.concat(value);
578                }
579
580                _ => result.errors.push(Error::new(arg.get_span(), InvalidArg))
581            };
582
583        }
584        result.add_value(builder);
585        result
586    }
587
588    fn validate(state: ArgResult<Self::InitialType>, arg_name: &'static str) -> Result<Self, Vec<Error>> {
589        let mut state = state;
590
591        if state.value.is_none() && state.found_with_errors() == false {
592            return Ok(Self::default())
593        }
594
595        let builder = 
596            match state.value {
597                Some(value) => value,
598                None => return Err(vec![Error::new(state.location, MissingAttribute(arg_name))])
599            };
600
601        let mut maybe_name = <Option<String> as TryFromMeta<V>>::validate(builder.name, "name");
602        if let Err(ref mut errors) = maybe_name {
603            state.errors.append(errors);
604        }
605
606        let mut maybe_default = <Option<CustomArg<Default>> as TryFromMeta<V>>::validate(builder.default, "default");
607        if let Err(ref mut errors) = maybe_default {
608            state.errors.append(errors);
609        }
610
611        match state.errors.len() {
612            0 => Ok(Self { name: maybe_name.expect("name failed"), default: maybe_default.expect("default failed") }),
613            _ => Err(state.errors)
614        }
615    }
616}
617
618#[derive(Debug)]
619enum Default {
620    UseSelfDefault,
621    ChooseDefault(Ident)
622}
623impl<V: SynVersion> CustomArgFromMeta<V> for Default {
624    fn try_from_meta(meta: V::ArgMeta) -> Result<Self, ErrorMsg> {        
625        let maybe_bool = V::deserialize_bool(&meta);
626        let maybe_path = V::deserialize_string(&meta);
627        
628        match (maybe_bool, maybe_path) {
629            (Some(is_default), _) if is_default => Ok(Self::UseSelfDefault),
630            (_, Some(path)) => Ok(Self::ChooseDefault(format_ident!("{path}"))),
631            _ => Err(InvalidType { expected: "boolean or path string" })
632        }
633    }
634}