educe/trait_handlers/eq/models/
type_attribute.rs

1use quote::{quote, ToTokens};
2use syn::{
3    punctuated::Punctuated, token::Comma, GenericParam, Lit, Meta, NestedMeta, WherePredicate,
4};
5
6use super::super::super::{
7    create_where_predicates_from_generic_parameters, create_where_predicates_from_lit_str,
8};
9use crate::panic;
10
11#[derive(Clone)]
12pub enum TypeAttributeBound {
13    None,
14    Auto,
15    Custom(Punctuated<WherePredicate, Comma>),
16}
17
18impl TypeAttributeBound {
19    pub fn into_punctuated_where_predicates_by_generic_parameters(
20        self,
21        params: &Punctuated<GenericParam, Comma>,
22    ) -> Punctuated<WherePredicate, Comma> {
23        match self {
24            TypeAttributeBound::None => Punctuated::new(),
25            TypeAttributeBound::Auto => create_where_predicates_from_generic_parameters(
26                params,
27                &syn::parse2(quote!(core::cmp::Eq)).unwrap(),
28            ),
29            TypeAttributeBound::Custom(where_predicates) => where_predicates,
30        }
31    }
32}
33
34#[derive(Clone)]
35pub struct TypeAttribute {
36    pub bound: TypeAttributeBound,
37}
38
39#[derive(Debug, Clone)]
40pub struct TypeAttributeBuilder {
41    pub enable_bound: bool,
42}
43
44impl TypeAttributeBuilder {
45    #[allow(clippy::wrong_self_convention)]
46    pub fn from_eq_meta(&self, meta: &Meta) -> TypeAttribute {
47        let mut bound = TypeAttributeBound::None;
48
49        let correct_usage_for_eq_attribute = {
50            let usage = vec![stringify!(#[educe(Eq)])];
51
52            usage
53        };
54
55        let correct_usage_for_bound = {
56            let usage = vec![
57                stringify!(#[educe(Eq(bound))]),
58                stringify!(#[educe(Eq(bound = "where_predicates"))]),
59                stringify!(#[educe(Eq(bound("where_predicates")))]),
60            ];
61
62            usage
63        };
64
65        match meta {
66            Meta::List(list) => {
67                let mut bound_is_set = false;
68
69                for p in list.nested.iter() {
70                    match p {
71                        NestedMeta::Meta(meta) => {
72                            let meta_name = meta.path().into_token_stream().to_string();
73
74                            match meta_name.as_str() {
75                                "bound" => {
76                                    if !self.enable_bound {
77                                        panic::unknown_parameter("Eq", meta_name.as_str());
78                                    }
79
80                                    match meta {
81                                        Meta::List(list) => {
82                                            for p in list.nested.iter() {
83                                                match p {
84                                                    NestedMeta::Lit(Lit::Str(s)) => {
85                                                        if bound_is_set {
86                                                            panic::reset_parameter(
87                                                                meta_name.as_str(),
88                                                            );
89                                                        }
90
91                                                        bound_is_set = true;
92
93                                                        let where_predicates =
94                                                            create_where_predicates_from_lit_str(s);
95
96                                                        bound = match where_predicates {
97                                                            Some(where_predicates) => {
98                                                                TypeAttributeBound::Custom(
99                                                                    where_predicates,
100                                                                )
101                                                            },
102                                                            None => panic::empty_parameter(
103                                                                meta_name.as_str(),
104                                                            ),
105                                                        };
106                                                    },
107                                                    _ => panic::parameter_incorrect_format(
108                                                        meta_name.as_str(),
109                                                        &correct_usage_for_bound,
110                                                    ),
111                                                }
112                                            }
113                                        },
114                                        Meta::NameValue(named_value) => {
115                                            let lit = &named_value.lit;
116
117                                            match lit {
118                                                Lit::Str(s) => {
119                                                    if bound_is_set {
120                                                        panic::reset_parameter(meta_name.as_str());
121                                                    }
122
123                                                    bound_is_set = true;
124
125                                                    let where_predicates =
126                                                        create_where_predicates_from_lit_str(s);
127
128                                                    bound = match where_predicates {
129                                                        Some(where_predicates) => {
130                                                            TypeAttributeBound::Custom(
131                                                                where_predicates,
132                                                            )
133                                                        },
134                                                        None => panic::empty_parameter(
135                                                            meta_name.as_str(),
136                                                        ),
137                                                    };
138                                                },
139                                                _ => panic::parameter_incorrect_format(
140                                                    meta_name.as_str(),
141                                                    &correct_usage_for_bound,
142                                                ),
143                                            }
144                                        },
145                                        Meta::Path(_) => {
146                                            if bound_is_set {
147                                                panic::reset_parameter(meta_name.as_str());
148                                            }
149
150                                            bound_is_set = true;
151
152                                            bound = TypeAttributeBound::Auto;
153                                        },
154                                    }
155                                },
156                                _ => panic::unknown_parameter("Eq", meta_name.as_str()),
157                            }
158                        },
159                        _ => {
160                            panic::attribute_incorrect_format("Eq", &correct_usage_for_eq_attribute)
161                        },
162                    }
163                }
164            },
165            Meta::NameValue(_) => {
166                panic::attribute_incorrect_format("Eq", &correct_usage_for_eq_attribute)
167            },
168            Meta::Path(_) => (),
169        }
170
171        TypeAttribute {
172            bound,
173        }
174    }
175}