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 mut display_name = String::new();
53 let parsed_attrs = PAttrs::parse(attrs, &mut display_name);
54 parsed_attrs.facet_crate()
55 };
56
57 if let Some(chain) = generate_plugin_chain(&input, &plugins, &facet_crate) {
59 return chain;
60 }
61 }
62
63 match it.first {
65 AdtDecl::Struct(parsed) => process_struct::process_struct(parsed),
66 AdtDecl::Enum(parsed) => process_enum::process_enum(parsed),
67 }
68 }
69 Err(err) => {
70 panic!("Could not parse type declaration: {input}\nError: {err}");
71 }
72 }
73}
74
75pub(crate) fn build_where_clauses(
76 where_clauses: Option<&WhereClauses>,
77 generics: Option<&GenericParams>,
78 opaque: bool,
79 facet_crate: &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 if !has_clauses {
128 quote! {}
129 } else {
130 quote! { where #where_clause_tokens }
131 }
132}
133
134pub(crate) fn build_type_params_call(
136 generics: Option<&GenericParams>,
137 opaque: bool,
138 facet_crate: &TokenStream,
139) -> TokenStream {
140 if opaque {
141 return quote! {};
142 }
143
144 let mut type_params = Vec::new();
145 if let Some(generics) = generics {
146 for p in generics.params.iter() {
147 match &p.value {
148 GenericParam::Lifetime { .. } => {
149 }
151 GenericParam::Const { .. } => {
152 }
154 GenericParam::Type { name, .. } => {
155 let name_str = name.to_string();
156 type_params.push(quote! {
157 #facet_crate::TypeParam {
158 name: #name_str,
159 shape: <#name as #facet_crate::Facet>::SHAPE
160 }
161 });
162 }
163 }
164 }
165 }
166
167 if type_params.is_empty() {
168 quote! {}
169 } else {
170 quote! { .type_params(&[#(#type_params),*]) }
171 }
172}
173
174pub(crate) fn generate_type_name_fn(
177 type_name: &Ident,
178 generics: Option<&GenericParams>,
179 opaque: bool,
180 facet_crate: &TokenStream,
181) -> TokenStream {
182 let type_name_str = type_name.to_string();
183
184 let write_generics = (!opaque)
185 .then_some(generics)
186 .flatten()
187 .and_then(|generics| {
188 let params = generics.params.iter();
189 let write_each = params.filter_map(|param| match ¶m.value {
190 GenericParam::Lifetime { .. } => None,
192 GenericParam::Const { name, .. } => Some(quote! {
193 write!(f, "{:?}", #name)?;
194 }),
195 GenericParam::Type { name, .. } => Some(quote! {
196 <#name as #facet_crate::Facet>::SHAPE.write_type_name(f, opts)?;
197 }),
198 });
199 let mut tokens = TokenStream::new();
201 tokens.append_separated(write_each, quote! { write!(f, ", ")?; });
202 if tokens.is_empty() {
203 None
204 } else {
205 Some(tokens)
206 }
207 });
208
209 match write_generics {
210 Some(write_generics) => {
211 quote! {
212 |_shape, f, opts| {
213 write!(f, #type_name_str)?;
214 if let Some(opts) = opts.for_children() {
215 write!(f, "<")?;
216 #write_generics
217 write!(f, ">")?;
218 } else {
219 write!(f, "<…>")?;
220 }
221 Ok(())
222 }
223 }
224 }
225 None => quote! { |_shape, f, _opts| ::core::fmt::Write::write_str(f, #type_name_str) },
226 }
227}