educe/trait_handlers/deref/models/
type_attribute.rs
1use syn::{punctuated::Punctuated, Attribute, Meta, Token};
2
3use crate::{panic, Trait};
4
5pub(crate) struct TypeAttribute;
6
7#[derive(Debug)]
8pub(crate) struct TypeAttributeBuilder {
9 pub(crate) enable_flag: bool,
10}
11
12impl TypeAttributeBuilder {
13 pub(crate) fn build_from_deref_meta(&self, meta: &Meta) -> syn::Result<TypeAttribute> {
14 debug_assert!(meta.path().is_ident("Deref"));
15
16 let correct_usage_for_deref_attribute = {
17 let mut usage = vec![];
18
19 if self.enable_flag {
20 usage.push(stringify!(#[educe(Deref)]));
21 }
22
23 usage
24 };
25
26 match meta {
27 Meta::Path(_) => {
28 if !self.enable_flag {
29 return Err(panic::attribute_incorrect_format(
30 meta.path().get_ident().unwrap(),
31 &correct_usage_for_deref_attribute,
32 ));
33 }
34 },
35 Meta::NameValue(_) | Meta::List(_) => {
36 return Err(panic::attribute_incorrect_format(
37 meta.path().get_ident().unwrap(),
38 &correct_usage_for_deref_attribute,
39 ));
40 },
41 }
42
43 Ok(TypeAttribute)
44 }
45
46 pub(crate) fn build_from_attributes(
47 &self,
48 attributes: &[Attribute],
49 traits: &[Trait],
50 ) -> syn::Result<TypeAttribute> {
51 let mut output = None;
52
53 for attribute in attributes.iter() {
54 let path = attribute.path();
55
56 if path.is_ident("educe") {
57 if let Meta::List(list) = &attribute.meta {
58 let result =
59 list.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
60
61 for meta in result {
62 let path = meta.path();
63
64 let t = match Trait::from_path(path) {
65 Some(t) => t,
66 None => return Err(panic::unsupported_trait(meta.path())),
67 };
68
69 if !traits.contains(&t) {
70 return Err(panic::trait_not_used(path.get_ident().unwrap()));
71 }
72
73 if t == Trait::Deref {
74 if output.is_some() {
75 return Err(panic::reuse_a_trait(path.get_ident().unwrap()));
76 }
77
78 output = Some(self.build_from_deref_meta(&meta)?);
79 }
80 }
81 }
82 }
83 }
84
85 Ok(output.unwrap_or(TypeAttribute))
86 }
87}