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}