const_format_proc_macros/
format_macro.rs1use crate::{
2 format_args::{ExpandInto, FormatArgs, FormatIfArgs, LocalVariable, WriteArgs},
3 parse_utils::TokenStream2Ext,
4 shared_arg_parsing::{ExprArg, ExprArgs},
5 Error,
6};
7
8use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
9
10use quote::{quote, quote_spanned};
11
12#[cfg(test)]
13mod tests;
14
15pub(crate) fn concatcp_impl(value: ExprArgs) -> Result<TokenStream2, crate::Error> {
18 let fmt_var = Ident::new("fmt", Span::mixed_site());
19
20 let concat_args = value.args.iter().map(|ExprArg { expr, span }| {
21 quote_spanned!(span.start=>
22 __cf_osRcTFl4A::pmr::PConvWrapper(#expr).to_pargument_display(#fmt_var)
23 )
24 });
25
26 Ok(quote!(({
27 #[doc(hidden)]
29 #[allow(unused_mut, non_snake_case)]
30 const CONCATP_NHPMWYD3NJA : &[__cf_osRcTFl4A::pmr::PArgument] = {
31 let #fmt_var = __cf_osRcTFl4A::pmr::FormattingFlags::NEW;
32
33 &[
34 #( #concat_args ),*
35 ]
36 };
37
38 __cf_osRcTFl4A::__concatcp_inner!(CONCATP_NHPMWYD3NJA)
39 })))
40}
41
42pub(crate) fn formatcp_if_macro_impl(value: FormatIfArgs) -> Result<TokenStream2, crate::Error> {
45 formatcp_impl(value.inner)
46}
47
48pub(crate) fn formatcp_impl(fmt_args: FormatArgs) -> Result<TokenStream2, crate::Error> {
49 let locals = fmt_args
50 .local_variables
51 .iter()
52 .map(|LocalVariable { ident, expr }| {
53 let span = ident.span();
54 quote_spanned!(span=> let #ident = #expr;)
55 });
56
57 for ei in fmt_args.expanded_into.iter() {
58 if let ExpandInto::WithFormatter(wf) = ei {
59 return Err(crate::Error::new(
60 wf.fmt_ident.span(),
61 "Can't do custom formatting in the `formatcp` macro",
62 ));
63 }
64 }
65
66 let parg_constructor = fmt_args.expanded_into.iter().map(|ei| match ei {
67 ExpandInto::Str(str, rawness) => {
68 let str_tokens = rawness.tokenize_sub(str);
69 quote!(
70 __cf_osRcTFl4A::pmr::PConvWrapper(#str_tokens)
71 .to_pargument_display(__cf_osRcTFl4A::pmr::FormattingFlags::NEW)
72 )
73 }
74 ExpandInto::Formatted(fmted) => {
75 let to_pargument_m = fmted.format.to_pargument_method_name();
76 let formatting = fmted.format;
77 let local_variable = &fmted.local_variable;
78 let span = local_variable.span();
79 quote!(
82 __cf_osRcTFl4A::pmr::PConvWrapper(#local_variable).#to_pargument_m(#formatting)
83 )
84 .set_span_recursive(span)
85 }
86 ExpandInto::WithFormatter { .. } => unreachable!(),
87 });
88
89 let fmt_if_true = quote!({
90 let mut len = 0usize;
91
92 #( #locals )*
93
94 &[
95 #( #parg_constructor ),*
96 ]
97 });
98
99 if let Some(cond) = fmt_args.condition {
100 Ok(quote!(({
101 enum __Fooosrctfl4a {}
102
103 impl<T> __cf_osRcTFl4A::pmr::ConcatArgsIf<T, true> for __Fooosrctfl4a {
105 #[doc(hidden)]
106 const PARGUMENTS : &'static [__cf_osRcTFl4A::pmr::PArgument] = #fmt_if_true;
107 }
108
109 __cf_osRcTFl4A::__concatcp_inner!(
110 <__Fooosrctfl4a as __cf_osRcTFl4A::pmr::ConcatArgsIf<(), #cond>>::PARGUMENTS
111 )
112 })))
113 } else {
114 Ok(quote!(({
115 #[doc(hidden)]
117 #[allow(unused_mut, non_snake_case)]
118 const CONCATP_NHPMWYD3NJA : &[__cf_osRcTFl4A::pmr::PArgument] = #fmt_if_true;
119
120 __cf_osRcTFl4A::__concatcp_inner!(CONCATP_NHPMWYD3NJA)
121 })))
122 }
123}
124
125pub(crate) fn formatc_if_macro_impl(value: FormatIfArgs) -> Result<TokenStream2, crate::Error> {
128 formatc_macro_impl(value.inner)
129}
130
131pub(crate) fn formatc_macro_impl(fmt_args: FormatArgs) -> Result<TokenStream2, crate::Error> {
134 let locals = fmt_args.local_variables.iter().map(|arg| &arg.ident);
135 let expr = fmt_args.local_variables.iter().map(|arg| &arg.expr);
136
137 let strwriter = Ident::new("strwriter", Span::mixed_site());
138
139 let writing_formatted = fmt_args
140 .expanded_into
141 .iter()
142 .map(|ei| ei.fmt_call(&strwriter));
143
144 let cond_a = fmt_args.condition.iter();
145
146 Ok(quote!(({
147 #[doc(hidden)]
148 #[allow(non_snake_case)]
149 const fn fmt_NHPMWYD3NJA(
150 mut #strwriter: __cf_osRcTFl4A::fmt::Formatter<'_>,
151 ) -> __cf_osRcTFl4A::Result {
152 match (#(&(#expr),)*) {
153 (#(#locals,)*) => {
154 #(
155 __cf_osRcTFl4A::try_!(#writing_formatted);
156 )*
157 },
158 }
159 __cf_osRcTFl4A::pmr::Ok(())
160 }
161
162 __cf_osRcTFl4A::__concatc_inner!(
163 fmt_NHPMWYD3NJA,
164 #((#cond_a) && )* true,
165 ____
166 )
167 })))
168}
169
170pub(crate) fn writec_macro_impl(value: WriteArgs) -> Result<TokenStream2, Error> {
171 let writer_expr = value.writer_expr;
172 let writer_span = value.writer_span;
173 let FormatArgs {
174 condition: _,
175 expanded_into,
176 local_variables,
177 } = value.format_args;
178
179 let locals = local_variables.iter().map(|arg| &arg.ident);
180 let expr = local_variables.iter().map(|arg| &arg.expr);
181
182 let strwriter = Ident::new("strwriter", Span::mixed_site());
183
184 let writing_formatted = expanded_into.iter().map(|ei| ei.fmt_call(&strwriter));
185
186 let borrow_mutably = quote_spanned!(writer_span=> ((#writer_expr).borrow_mutably()));
187
188 let make_formatter = quote_spanned!(writer_span =>
189 let mut marker = __cf_osRcTFl4A::pmr::IsAWriteMarker::NEW;
190 if false {
191 marker = marker.infer_type(&#strwriter);
192 }
193 let mut #strwriter = marker.coerce(#strwriter);
194 let mut #strwriter =
195 #strwriter.make_formatter(__cf_osRcTFl4A::FormattingFlags::NEW);
196 );
197
198 Ok(quote! {({
199
200 #[allow(non_snake_case)]
201 match (#borrow_mutably, #(&(#expr),)*) {
202 (#strwriter, #(#locals,)*) => {
203 #make_formatter
204
205 loop {
206 #(
207 __cf_osRcTFl4A::unwrap_or_else!(
208 #writing_formatted,
209 |e| break __cf_osRcTFl4A::pmr::Err(e)
210 );
211 )*
212 break __cf_osRcTFl4A::pmr::Ok(());
213 }
214 }
215 }
216 })})
217}