1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use quote::ToTokens;
use syn::{Attribute, Meta, NestedMeta};

use crate::{panic, Trait};

#[derive(Clone)]
pub struct FieldAttribute {
    pub flag: bool,
}

#[derive(Debug, Clone)]
pub struct FieldAttributeBuilder {
    pub enable_flag: bool,
}

impl FieldAttributeBuilder {
    #[allow(clippy::wrong_self_convention)]
    pub fn from_deref_mut_meta(&self, meta: &Meta) -> FieldAttribute {
        let correct_usage_for_deref_mut_attribute = {
            let mut usage = vec![];

            if self.enable_flag {
                usage.push(stringify!(#[educe(DerefMut)]));
            }

            usage
        };

        match meta {
            Meta::List(_) => panic::attribute_incorrect_format(
                "DerefMut",
                &correct_usage_for_deref_mut_attribute,
            ),
            Meta::NameValue(_) => panic::attribute_incorrect_format(
                "DerefMut",
                &correct_usage_for_deref_mut_attribute,
            ),
            Meta::Path(_) => {
                if !self.enable_flag {
                    panic::attribute_incorrect_format(
                        "DerefMut",
                        &correct_usage_for_deref_mut_attribute,
                    );
                }

                true
            },
        };

        FieldAttribute {
            flag: true
        }
    }

    #[allow(clippy::wrong_self_convention)]
    pub fn from_attributes(self, attributes: &[Attribute], traits: &[Trait]) -> FieldAttribute {
        let mut result = None;

        for attribute in attributes.iter() {
            let meta = attribute.parse_meta().unwrap();

            let meta_name = meta.path().into_token_stream().to_string();

            if meta_name.as_str() == "educe" {
                match meta {
                    Meta::List(list) => {
                        for p in list.nested.iter() {
                            match p {
                                NestedMeta::Meta(meta) => {
                                    let meta_name = meta.path().into_token_stream().to_string();

                                    let t = Trait::from_str(meta_name);

                                    if traits.binary_search(&t).is_err() {
                                        panic::trait_not_used(t);
                                    }

                                    if t == Trait::DerefMut {
                                        if result.is_some() {
                                            panic::reuse_a_trait(t);
                                        }

                                        result = Some(self.from_deref_mut_meta(meta));
                                    }
                                },
                                _ => panic::educe_format_incorrect(),
                            }
                        }
                    },
                    _ => panic::educe_format_incorrect(),
                }
            }
        }

        result.unwrap_or(FieldAttribute {
            flag: false
        })
    }
}