facet_macros_impl/
derive.rs1use crate::{ToTokens, *};
2use quote::{TokenStreamExt as _, quote};
3
4use crate::plugin::{extract_derive_plugins, generate_plugin_chain};
5use crate::{LifetimeName, RenameRule, process_enum, process_struct};
6
7pub(crate) fn generate_static_decl(
11 type_name: &Ident,
12 facet_crate: &TokenStream,
13 has_type_or_const_generics: bool,
14) -> TokenStream {
15 if has_type_or_const_generics {
17 return quote! {};
18 }
19
20 let type_name_str = type_name.to_string();
21 let screaming_snake_name = RenameRule::ScreamingSnakeCase.apply(&type_name_str);
22
23 let static_name_ident = quote::format_ident!("{}_SHAPE", screaming_snake_name);
24
25 quote! {
26 #[cfg(not(debug_assertions))]
27 static #static_name_ident: &'static #facet_crate::Shape = <#type_name as #facet_crate::Facet>::SHAPE;
28 }
29}
30
31pub fn facet_macros(input: TokenStream) -> TokenStream {
35 let mut i = input.clone().to_token_iter();
36
37 match i.parse::<Cons<AdtDecl, EndOfStream>>() {
39 Ok(it) => {
40 let attrs = match &it.first {
42 AdtDecl::Struct(s) => &s.attributes,
43 AdtDecl::Enum(e) => &e.attributes,
44 };
45
46 let plugins = extract_derive_plugins(attrs);
48
49 if !plugins.is_empty() {
50 let facet_crate = {
52 let parsed_attrs = PAttrs::parse(attrs);
53 parsed_attrs.facet_crate()
54 };
55
56 if let Some(chain) = generate_plugin_chain(&input, &plugins, &facet_crate) {
58 return chain;
59 }
60 }
61
62 match it.first {
64 AdtDecl::Struct(parsed) => process_struct::process_struct(parsed),
65 AdtDecl::Enum(parsed) => process_enum::process_enum(parsed),
66 }
67 }
68 Err(err) => {
69 panic!("Could not parse type declaration: {input}\nError: {err}");
70 }
71 }
72}
73
74pub(crate) fn build_where_clauses(
75 where_clauses: Option<&WhereClauses>,
76 generics: Option<&GenericParams>,
77 opaque: bool,
78 facet_crate: &TokenStream,
79 custom_bounds: &[TokenStream],
80) -> TokenStream {
81 let mut where_clause_tokens = TokenStream::new();
82 let mut has_clauses = false;
83
84 if let Some(wc) = where_clauses {
85 for c in wc.clauses.iter() {
86 if has_clauses {
87 where_clause_tokens.extend(quote! { , });
88 }
89 where_clause_tokens.extend(c.value.to_token_stream());
90 has_clauses = true;
91 }
92 }
93
94 if let Some(generics) = generics {
95 for p in generics.params.iter() {
96 match &p.value {
97 GenericParam::Lifetime { name, .. } => {
98 let facet_lifetime = LifetimeName(quote::format_ident!("{}", "ʄ"));
99 let lifetime = LifetimeName(name.name.clone());
100 if has_clauses {
101 where_clause_tokens.extend(quote! { , });
102 }
103 where_clause_tokens
104 .extend(quote! { #lifetime: #facet_lifetime, #facet_lifetime: #lifetime });
105
106 has_clauses = true;
107 }
108 GenericParam::Const { .. } => {
109 }
111 GenericParam::Type { name, .. } => {
112 if has_clauses {
113 where_clause_tokens.extend(quote! { , });
114 }
115 if opaque {
117 where_clause_tokens.extend(quote! { #name: 'ʄ });
118 } else {
119 where_clause_tokens.extend(quote! { #name: #facet_crate::Facet<'ʄ> });
120 }
121 has_clauses = true;
122 }
123 }
124 }
125 }
126
127 for bound in custom_bounds {
129 if has_clauses {
130 where_clause_tokens.extend(quote! { , });
131 }
132 where_clause_tokens.extend(bound.clone());
133 has_clauses = true;
134 }
135
136 if !has_clauses {
137 quote! {}
138 } else {
139 quote! { where #where_clause_tokens }
140 }
141}
142
143pub(crate) fn build_type_params_call(
145 generics: Option<&GenericParams>,
146 opaque: bool,
147 facet_crate: &TokenStream,
148) -> TokenStream {
149 if opaque {
150 return quote! {};
151 }
152
153 let mut type_params = Vec::new();
154 if let Some(generics) = generics {
155 for p in generics.params.iter() {
156 match &p.value {
157 GenericParam::Lifetime { .. } => {
158 }
160 GenericParam::Const { .. } => {
161 }
163 GenericParam::Type { name, .. } => {
164 let name_str = name.to_string();
165 type_params.push(quote! {
166 #facet_crate::TypeParam {
167 name: #name_str,
168 shape: <#name as #facet_crate::Facet>::SHAPE
169 }
170 });
171 }
172 }
173 }
174 }
175
176 if type_params.is_empty() {
177 quote! {}
178 } else {
179 quote! { .type_params(&[#(#type_params),*]) }
180 }
181}
182
183pub(crate) fn generate_type_name_fn(
186 type_name: &Ident,
187 generics: Option<&GenericParams>,
188 opaque: bool,
189 facet_crate: &TokenStream,
190) -> TokenStream {
191 let type_name_str = type_name.to_string();
192
193 let write_generics = (!opaque)
194 .then_some(generics)
195 .flatten()
196 .and_then(|generics| {
197 let params = generics.params.iter();
198 let write_each = params.filter_map(|param| match ¶m.value {
199 GenericParam::Lifetime { .. } => None,
201 GenericParam::Const { name, .. } => Some(quote! {
202 write!(f, "{:?}", #name)?;
203 }),
204 GenericParam::Type { name, .. } => Some(quote! {
205 <#name as #facet_crate::Facet>::SHAPE.write_type_name(f, opts)?;
206 }),
207 });
208 let mut tokens = TokenStream::new();
210 tokens.append_separated(write_each, quote! { write!(f, ", ")?; });
211 if tokens.is_empty() {
212 None
213 } else {
214 Some(tokens)
215 }
216 });
217
218 match write_generics {
219 Some(write_generics) => {
220 quote! {
221 |_shape, f, opts| {
222 write!(f, #type_name_str)?;
223 if let Some(opts) = opts.for_children() {
224 write!(f, "<")?;
225 #write_generics
226 write!(f, ">")?;
227 } else {
228 write!(f, "<…>")?;
229 }
230 Ok(())
231 }
232 }
233 }
234 None => quote! { |_shape, f, _opts| ::core::fmt::Write::write_str(f, #type_name_str) },
235 }
236}