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