xref: /aosp_15_r20/external/pigweed/pw_format/rust/pw_format/macros.rs (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 //! The `macro` module provides helpers that simplify writing proc macros
16 //! that take format strings and arguments.  This is accomplish with three
17 //! main constructs:
18 //! * [`FormatAndArgsFlavor`]: A struct that implements [syn::parse::Parse] to
19 //!   parse a format string and its following arguments.
20 //! * [`FormatMacroGenerator`]: A trait used to implement the macro specific
21 //!   logic to generate code.
22 //! * [`generate`]: A function to handle the execution of the proc macro by
23 //!   calling into a [FormatMacroGenerator].
24 //!
25 //! Additionally [`PrintfFormatMacroGenerator`] trait and [`generate_printf`]
26 //! function are provided to help when implementing generators that need to
27 //! produce `printf` style format strings as part of their code generation.
28 //!
29 //! ## Example
30 //!
31 //! An example of implementing a proc macro is provided in the
32 //! [pw_format_example_macro crate](https://pigweed.googlesource.com/pigweed/pigweed/+/refs/heads/main/pw_format/rust/pw_format_example_macro.rs)
33 //!
34 //!
35 
36 use std::collections::VecDeque;
37 use std::marker::PhantomData;
38 
39 use proc_macro2::Ident;
40 use quote::{format_ident, quote, ToTokens};
41 use syn::{
42     parse::{discouraged::Speculative, Parse, ParseStream},
43     punctuated::Punctuated,
44     spanned::Spanned,
45     Expr, ExprCast, LitStr, Token,
46 };
47 
48 use crate::{
49     ConversionSpec, Flag, FormatFragment, FormatString, Length, MinFieldWidth, Precision,
50     Primitive, Style,
51 };
52 
53 mod keywords {
54     syn::custom_keyword!(PW_FMT_CONCAT);
55 }
56 
57 type TokenStream2 = proc_macro2::TokenStream;
58 
59 /// An error occurring during proc macro evaluation.
60 ///
61 /// In order to stay as flexible as possible to implementors of
62 /// [`FormatMacroGenerator`], the error is simply represent by a
63 /// string.
64 #[derive(Debug)]
65 pub struct Error {
66     text: String,
67 }
68 
69 impl Error {
70     /// Create a new proc macro evaluation error.
new(text: &str) -> Self71     pub fn new(text: &str) -> Self {
72         Self {
73             text: text.to_string(),
74         }
75     }
76 }
77 
78 /// An alias for a Result with an ``Error``
79 pub type Result<T> = core::result::Result<T, Error>;
80 
81 /// Formatting parameters passed to an untyped conversion.
82 #[derive(Clone, Debug, PartialEq)]
83 pub struct FormatParams {
84     /// Style in which to print the corresponding argument.
85     pub style: Style,
86 
87     /// Minimum field width.  (i.e. the `8` in `{:08x}`).
88     pub min_field_width: Option<u32>,
89 
90     /// Zero padding.  (i.e. the existence of `0` in `{:08x}`).
91     pub zero_padding: bool,
92 }
93 
94 impl FormatParams {
printf_format_trait(&self) -> Result<Ident>95     fn printf_format_trait(&self) -> Result<Ident> {
96         match self.style {
97             Style::None => Ok(format_ident!("PrintfFormatter")),
98             Style::Hex => Ok(format_ident!("PrintfHexFormatter")),
99             Style::UpperHex => Ok(format_ident!("PrintfUpperHexFormatter")),
100             _ => Err(Error::new(&format!(
101                 "formatting untyped conversions with {:?} style is unsupported",
102                 self.style
103             ))),
104         }
105     }
106 
field_params(&self) -> String107     fn field_params(&self) -> String {
108         let (zero_pad, min_field_width) = match self.min_field_width {
109             None => ("", "".to_string()),
110             Some(min_field_width) => (
111                 if self.zero_padding { "0" } else { "" },
112                 format!("{min_field_width}"),
113             ),
114         };
115 
116         format!("{zero_pad}{min_field_width}")
117     }
118 
core_fmt_specifier(&self) -> Result<String>119     fn core_fmt_specifier(&self) -> Result<String> {
120         // If no formatting options are needed, omit the `:`.
121         if self.style == Style::None && self.min_field_width.is_none() {
122             return Ok("{}".to_string());
123         }
124 
125         let format = match self.style {
126             Style::None => "",
127             Style::Octal => "o",
128             Style::Hex => "x",
129             Style::UpperHex => "X",
130             _ => {
131                 return Err(Error::new(&format!(
132                     "formatting untyped conversions with {:?} style is unsupported",
133                     self.style
134                 )))
135             }
136         };
137 
138         let field_params = self.field_params();
139 
140         Ok(format!("{{:{field_params}{format}}}"))
141     }
142 }
143 
144 impl TryFrom<&ConversionSpec> for FormatParams {
145     type Error = Error;
try_from(spec: &ConversionSpec) -> core::result::Result<Self, Self::Error>146     fn try_from(spec: &ConversionSpec) -> core::result::Result<Self, Self::Error> {
147         let min_field_width = match spec.min_field_width {
148             MinFieldWidth::None => None,
149             MinFieldWidth::Fixed(len) => Some(len),
150             MinFieldWidth::Variable => {
151                 return Err(Error::new(
152                     "Variable width '*' string formats are not supported.",
153                 ))
154             }
155         };
156 
157         Ok(FormatParams {
158             style: spec.style,
159             min_field_width,
160             zero_padding: spec.flags.contains(&Flag::LeadingZeros),
161         })
162     }
163 }
164 
165 /// Implemented for testing through the pw_format_test_macros crate.
166 impl ToTokens for FormatParams {
to_tokens(&self, tokens: &mut proc_macro2::TokenStream)167     fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
168         let style = self.style;
169         let min_field_width = match self.min_field_width {
170             None => quote! {None},
171             Some(val) => quote! {Some(#val)},
172         };
173         let zero_padding = self.zero_padding;
174 
175         quote! {
176             pw_format::macros::FormatParams {
177                 style: #style,
178                 min_field_width: #min_field_width,
179                 zero_padding: #zero_padding,
180             }
181         }
182         .to_tokens(tokens)
183     }
184 }
185 
186 /// A code generator for implementing a `pw_format` style macro.
187 ///
188 /// This trait serves as the primary interface between `pw_format` and a
189 /// proc macro using it to implement format string and argument parsing.  When
190 /// evaluating the proc macro and generating code, [`generate`] will make
191 /// repeated calls to [`string_fragment`](FormatMacroGenerator::string_fragment)
192 /// and the conversion functions.  These calls will be made in the order they
193 /// appear in the format string.  After all fragments and conversions are
194 /// processed, [`generate`] will call
195 /// [`finalize`](FormatMacroGenerator::finalize).
196 ///
197 /// For an example of implementing a `FormatMacroGenerator` see the
198 /// [pw_format_example_macro crate](https://pigweed.googlesource.com/pigweed/pigweed/+/refs/heads/main/pw_format/rust/pw_format_example_macro.rs).
199 pub trait FormatMacroGenerator {
200     /// Called by [`generate`] at the end of code generation.
201     ///
202     /// Consumes `self` and returns the code to be emitted by the proc macro of
203     /// and [`Error`].
finalize(self) -> Result<TokenStream2>204     fn finalize(self) -> Result<TokenStream2>;
205 
206     /// Process a string fragment.
207     ///
208     /// A string fragment is a string of characters that appear in a format
209     /// string.  This is different than a
210     /// [`string_conversion`](FormatMacroGenerator::string_conversion) which is
211     /// a string provided through a conversion specifier (i.e. `"%s"`).
string_fragment(&mut self, string: &str) -> Result<()>212     fn string_fragment(&mut self, string: &str) -> Result<()>;
213 
214     /// Process an integer conversion.
integer_conversion( &mut self, params: &FormatParams, signed: bool, type_width: u8, expression: Arg, ) -> Result<()>215     fn integer_conversion(
216         &mut self,
217         params: &FormatParams,
218         signed: bool,
219         type_width: u8, // This should probably be an enum
220         expression: Arg,
221     ) -> Result<()>;
222 
223     /// Process a string conversion.
224     ///
225     /// See [`string_fragment`](FormatMacroGenerator::string_fragment) for a
226     /// disambiguation between that function and this one.
string_conversion(&mut self, expression: Arg) -> Result<()>227     fn string_conversion(&mut self, expression: Arg) -> Result<()>;
228 
229     /// Process a character conversion.
char_conversion(&mut self, expression: Arg) -> Result<()>230     fn char_conversion(&mut self, expression: Arg) -> Result<()>;
231 
232     /// Process an untyped conversion.
untyped_conversion(&mut self, _expression: Arg, _params: &FormatParams) -> Result<()>233     fn untyped_conversion(&mut self, _expression: Arg, _params: &FormatParams) -> Result<()> {
234         Err(Error::new("untyped conversion (%v) not supported"))
235     }
236 }
237 
238 /// An argument to a `pw_format` backed macro.
239 ///
240 /// `pw_format` backed macros have special case recognition of type casts
241 /// (`value as ty`) in order to annotate a type for typeless printing w/o
242 /// relying on experimental features.  If an argument is given in that form,
243 /// it will be represented as an [`Arg::ExprCast`] here.  Otherwise it will
244 /// be an [`Arg::Expr`].
245 #[derive(Clone, Debug)]
246 pub enum Arg {
247     /// An argument that is an type cast expression.
248     ExprCast(ExprCast),
249     /// An argument that is an expression.
250     Expr(Expr),
251 }
252 
253 impl Parse for Arg {
parse(input: ParseStream) -> syn::parse::Result<Self>254     fn parse(input: ParseStream) -> syn::parse::Result<Self> {
255         // Try parsing as an explicit cast first.  This lets the user name a
256         // type when type_alias_impl_trait is not enabled.
257         let fork = input.fork();
258         if let Ok(cast) = fork.parse::<ExprCast>() {
259             // Speculative parsing and `advance_to` is discouraged due to error
260             // presentation.  However, since `ExprCast` is a subset of `Expr`,
261             //  any errors in parsing here will be reported when trying to parse
262             //  as an `Expr` below.
263             input.advance_to(&fork);
264             return Ok(Self::ExprCast(cast));
265         }
266 
267         // Otherwise prase as an expression.
268         input.parse::<Expr>().map(Self::Expr)
269     }
270 }
271 
272 impl ToTokens for Arg {
to_tokens(&self, tokens: &mut TokenStream2)273     fn to_tokens(&self, tokens: &mut TokenStream2) {
274         match self {
275             Self::Expr(expr) => expr.to_tokens(tokens),
276             Self::ExprCast(cast) => cast.to_tokens(tokens),
277         }
278     }
279 }
280 
281 /// A trait for parsing a string into a [`FormatString`].
282 pub trait FormatStringParser {
283     /// Parse `format_string` and return the results as a `[FormatString]`.
parse_format_string(format_string: &str) -> std::result::Result<FormatString, String>284     fn parse_format_string(format_string: &str) -> std::result::Result<FormatString, String>;
285 }
286 
287 /// An implementation of [`FormatStringParser`] that parsers `printf` style format strings.
288 #[derive(Debug)]
289 pub struct PrintfFormatStringParser;
290 impl FormatStringParser for PrintfFormatStringParser {
parse_format_string(format_string: &str) -> std::result::Result<FormatString, String>291     fn parse_format_string(format_string: &str) -> std::result::Result<FormatString, String> {
292         FormatString::parse_printf(format_string)
293     }
294 }
295 
296 /// An implementation of [`FormatStringParser`] that parsers `core::fmt` style format strings.
297 #[derive(Debug)]
298 pub struct CoreFmtFormatStringParser;
299 impl FormatStringParser for CoreFmtFormatStringParser {
parse_format_string(format_string: &str) -> std::result::Result<FormatString, String>300     fn parse_format_string(format_string: &str) -> std::result::Result<FormatString, String> {
301         FormatString::parse_core_fmt(format_string)
302     }
303 }
304 
305 /// A parsed format string and it's arguments.
306 ///
307 /// To parse a `FormatAndArgs`, use the [`FormatAndArgsFlavor`] variant which
308 /// is generic over [`FormatStringParser`] to allow parsing either `printf` or
309 /// `core::fmt` style format strings.
310 ///
311 /// Arguments are parsed according to the pattern:
312 /// `($format_string:literal, $($args:expr),*)`
313 ///
314 /// To support uses where format strings need to be built by macros at compile
315 /// time, the format string can be specified as a set of string literals
316 /// separated by the custom `PW_FMT_CONCAT` keyword.
317 #[derive(Debug)]
318 pub struct FormatAndArgs {
319     format_string: LitStr,
320     parsed: FormatString,
321     args: VecDeque<Arg>,
322 }
323 
324 /// A variant of [`FormatAndArgs`] that is generic over format string flavor.
325 ///
326 /// `FormatAndArgsFlavor` implements [`syn::parse::Parse`] for it's specified
327 /// format string flavor.  Instantiate `FormatAndArgsFlavor` with either
328 /// [`PrintfFormatStringParser`] or [`CoreFmtFormatStringParser`] to specify
329 /// which format string flavor should be used.
330 ///
331 /// `FormatAndArgsFlavor` trivially converts into [`FormatAndArgs`] with the
332 /// [`From`] trait.
333 #[derive(Debug)]
334 pub struct FormatAndArgsFlavor<T: FormatStringParser> {
335     format_and_args: FormatAndArgs,
336     phantom: PhantomData<T>,
337 }
338 
339 impl<T: FormatStringParser> From<FormatAndArgsFlavor<T>> for FormatAndArgs {
from(val: FormatAndArgsFlavor<T>) -> Self340     fn from(val: FormatAndArgsFlavor<T>) -> Self {
341         val.format_and_args
342     }
343 }
344 
345 impl<T: FormatStringParser> Parse for FormatAndArgsFlavor<T> {
parse(input: ParseStream) -> syn::parse::Result<Self>346     fn parse(input: ParseStream) -> syn::parse::Result<Self> {
347         let punctuated =
348             Punctuated::<LitStr, keywords::PW_FMT_CONCAT>::parse_separated_nonempty(input)?;
349         let span = punctuated.span();
350         let format_string = LitStr::new(
351             &punctuated.into_iter().fold(String::new(), |mut acc, s| {
352                 acc.push_str(&s.value());
353                 acc
354             }),
355             span,
356         );
357 
358         let args = if input.is_empty() {
359             // If there are no more tokens, no arguments were specified.
360             VecDeque::new()
361         } else {
362             // Eat the `,` following the format string.
363             input.parse::<Token![,]>()?;
364 
365             let punctuated = Punctuated::<Arg, Token![,]>::parse_terminated(input)?;
366             punctuated.into_iter().collect()
367         };
368 
369         let parsed = T::parse_format_string(&format_string.value()).map_err(|e| {
370             syn::Error::new_spanned(
371                 format_string.to_token_stream(),
372                 format!("Error parsing format string {e}"),
373             )
374         })?;
375 
376         Ok(FormatAndArgsFlavor {
377             format_and_args: FormatAndArgs {
378                 format_string,
379                 parsed,
380                 args,
381             },
382             phantom: PhantomData,
383         })
384     }
385 }
386 
387 // Grab the next argument returning a descriptive error if no more args are left.
next_arg(spec: &ConversionSpec, args: &mut VecDeque<Arg>) -> Result<Arg>388 fn next_arg(spec: &ConversionSpec, args: &mut VecDeque<Arg>) -> Result<Arg> {
389     args.pop_front()
390         .ok_or_else(|| Error::new(&format!("No argument given for {spec:?}")))
391 }
392 
393 // Handle a single format conversion specifier (i.e. `%08x`).  Grabs the
394 // necessary arguments for the specifier from `args` and generates code
395 // to marshal the arguments into the buffer declared in `_tokenize_to_buffer`.
396 // Returns an error if args is too short of if a format specifier is unsupported.
handle_conversion( generator: &mut dyn FormatMacroGenerator, spec: &ConversionSpec, args: &mut VecDeque<Arg>, ) -> Result<()>397 fn handle_conversion(
398     generator: &mut dyn FormatMacroGenerator,
399     spec: &ConversionSpec,
400     args: &mut VecDeque<Arg>,
401 ) -> Result<()> {
402     match spec.primitive {
403         Primitive::Integer | Primitive::Unsigned => {
404             // TODO: b/281862660 - Support Width::Variable and Precision::Variable.
405             if spec.min_field_width == MinFieldWidth::Variable {
406                 return Err(Error::new(
407                     "Variable width '*' integer formats are not supported.",
408                 ));
409             }
410 
411             if spec.precision == Precision::Variable {
412                 return Err(Error::new(
413                     "Variable precision '*' integer formats are not supported.",
414                 ));
415             }
416 
417             if spec.style == Style::Binary {
418                 return Err(Error::new("Binary output style is not supported."));
419             }
420 
421             let arg = next_arg(spec, args)?;
422             let bits = match spec.length.unwrap_or(Length::Long) {
423                 Length::Char => 8,
424                 Length::Short => 16,
425                 Length::Long => 32,
426                 Length::LongLong => 64,
427                 Length::IntMax => 64,
428                 Length::Size => 32,
429                 Length::PointerDiff => 32,
430                 Length::LongDouble => {
431                     return Err(Error::new(
432                         "Long double length parameter invalid for integer formats",
433                     ))
434                 }
435             };
436             let params = spec.try_into()?;
437 
438             generator.integer_conversion(&params, spec.primitive == Primitive::Integer, bits, arg)
439         }
440         Primitive::String => {
441             // TODO: b/281862660 - Support Width::Variable and Precision::Variable.
442             if spec.min_field_width == MinFieldWidth::Variable {
443                 return Err(Error::new(
444                     "Variable width '*' string formats are not supported.",
445                 ));
446             }
447 
448             if spec.precision == Precision::Variable {
449                 return Err(Error::new(
450                     "Variable precision '*' string formats are not supported.",
451                 ));
452             }
453 
454             let arg = next_arg(spec, args)?;
455             generator.string_conversion(arg)
456         }
457         Primitive::Character => {
458             let arg = next_arg(spec, args)?;
459             generator.char_conversion(arg)
460         }
461 
462         Primitive::Untyped => {
463             let arg = next_arg(spec, args)?;
464             let params = spec.try_into()?;
465             generator.untyped_conversion(arg, &params)
466         }
467 
468         Primitive::Float => {
469             // TODO: b/281862328 - Support floating point numbers.
470             Err(Error::new("Floating point numbers are not supported."))
471         }
472 
473         // TODO: b/281862333 - Support pointers.
474         Primitive::Pointer => Err(Error::new("Pointer types are not supported.")),
475     }
476 }
477 
478 /// Generate code for a `pw_format` style proc macro.
479 ///
480 /// `generate` takes a [`FormatMacroGenerator`] and a [`FormatAndArgs`] struct
481 /// and uses them to produce the code output for a proc macro.
generate( mut generator: impl FormatMacroGenerator, format_and_args: FormatAndArgs, ) -> core::result::Result<TokenStream2, syn::Error>482 pub fn generate(
483     mut generator: impl FormatMacroGenerator,
484     format_and_args: FormatAndArgs,
485 ) -> core::result::Result<TokenStream2, syn::Error> {
486     let mut args = format_and_args.args;
487     let mut errors = Vec::new();
488 
489     for fragment in format_and_args.parsed.fragments {
490         let result = match fragment {
491             FormatFragment::Conversion(spec) => handle_conversion(&mut generator, &spec, &mut args),
492             FormatFragment::Literal(string) => generator.string_fragment(&string),
493         };
494         if let Err(e) = result {
495             errors.push(syn::Error::new_spanned(
496                 format_and_args.format_string.to_token_stream(),
497                 e.text,
498             ));
499         }
500     }
501 
502     if !errors.is_empty() {
503         return Err(errors
504             .into_iter()
505             .reduce(|mut accumulated_errors, error| {
506                 accumulated_errors.combine(error);
507                 accumulated_errors
508             })
509             .expect("errors should not be empty"));
510     }
511 
512     generator.finalize().map_err(|e| {
513         syn::Error::new_spanned(format_and_args.format_string.to_token_stream(), e.text)
514     })
515 }
516 
517 /// A specialized generator for proc macros that produce `printf` style format strings.
518 ///
519 /// For proc macros that need to translate a `pw_format` invocation into a
520 /// `printf` style format string, `PrintfFormatMacroGenerator` offer a
521 /// specialized form of [`FormatMacroGenerator`] that builds the format string
522 /// and provides it as an argument to
523 /// [`finalize`](PrintfFormatMacroGenerator::finalize).
524 ///
525 /// In cases where a generator needs to override the conversion specifier it
526 /// can return it from its appropriate conversion method.  An example of using
527 /// this would be wanting to pass a Rust string directly to a `printf` call
528 /// over FFI.  In that case,
529 /// [`string_conversion`](PrintfFormatMacroGenerator::string_conversion) could
530 /// return `Ok(Some("%.*s".to_string()))` to allow both the length and string
531 /// pointer to be passed to `printf`.
532 pub trait PrintfFormatMacroGenerator {
533     /// Called by [`generate_printf`] at the end of code generation.
534     ///
535     /// Works like [`FormatMacroGenerator::finalize`] with the addition of
536     /// being provided a `printf_style` format string.
finalize( self, format_string_fragments: &[PrintfFormatStringFragment], ) -> Result<TokenStream2>537     fn finalize(
538         self,
539         format_string_fragments: &[PrintfFormatStringFragment],
540     ) -> Result<TokenStream2>;
541 
542     /// Process a string fragment.
543     ///
544     /// **NOTE**: This string may contain unescaped `%` characters.
545     /// However, most implementations of this train can simply ignore string
546     /// fragments as they will be included (with properly escaped `%`
547     /// characters) as part of the format string passed to
548     /// [`PrintfFormatMacroGenerator::finalize`].
549     ///
550     /// See [`FormatMacroGenerator::string_fragment`] for a disambiguation
551     /// between a string fragment and string conversion.
string_fragment(&mut self, string: &str) -> Result<()>552     fn string_fragment(&mut self, string: &str) -> Result<()>;
553 
554     /// Process an integer conversion.
555     ///
556     /// May optionally return a printf format string (i.e. "%d") to override the
557     /// default.
integer_conversion(&mut self, ty: Ident, expression: Arg) -> Result<Option<String>>558     fn integer_conversion(&mut self, ty: Ident, expression: Arg) -> Result<Option<String>>;
559 
560     /// Process a string conversion.
561     ///
562     /// May optionally return a printf format string (i.e. "%s") to override the
563     /// default.
564     ///
565     /// See [`FormatMacroGenerator::string_fragment`] for a disambiguation
566     /// between a string fragment and string conversion.
string_conversion(&mut self, expression: Arg) -> Result<Option<String>>567     fn string_conversion(&mut self, expression: Arg) -> Result<Option<String>>;
568 
569     /// Process a character conversion.
570     ///
571     /// May optionally return a printf format string (i.e. "%c") to override the
572     /// default.
char_conversion(&mut self, expression: Arg) -> Result<Option<String>>573     fn char_conversion(&mut self, expression: Arg) -> Result<Option<String>>;
574 
575     /// Process and untyped conversion.
untyped_conversion(&mut self, _expression: Arg) -> Result<()>576     fn untyped_conversion(&mut self, _expression: Arg) -> Result<()> {
577         Err(Error::new("untyped conversion not supported"))
578     }
579 }
580 
581 /// A fragment of a printf format string.
582 ///
583 /// Printf format strings are built of multiple fragments.  These fragments can
584 /// be either a string ([`PrintfFormatStringFragment::String`]) or an expression
585 /// that evaluates to a `const &str` ([`PrintfFormatStringFragment::Expr`]).
586 /// These fragments can then be used to create a single `const &str` for use by
587 /// code generation.
588 ///
589 /// # Example
590 /// ```
591 /// use pw_bytes::concat_static_strs;
592 /// use pw_format::macros::{PrintfFormatStringFragment, Result};
593 /// use quote::quote;
594 ///
595 /// fn handle_fragments(format_string_fragments: &[PrintfFormatStringFragment]) -> Result<()> {
596 ///   let format_string_pieces: Vec<_> = format_string_fragments
597 ///     .iter()
598 ///     .map(|fragment| fragment.as_token_stream("__pw_log_backend_crate"))
599 ///     .collect::<Result<Vec<_>>>()?;
600 ///
601 ///   quote! {
602 ///     let format_string = concat_static_strs!("prefix: ", #(#format_string_pieces),*, "\n");
603 ///   };
604 ///   Ok(())
605 /// }
606 /// ```
607 pub enum PrintfFormatStringFragment {
608     /// A fragment that is a string.
609     String(String),
610 
611     /// An expressions that can be converted to a `const &str`.
612     Expr {
613         /// Argument to convert.
614         arg: Arg,
615         /// Trait to used for getting the format specifier for the argument.
616         ///
617         /// One of `PrintfFormatter`, `PrintfHexFormatter`, `PrintfUpperHexFormatter
618         format_trait: Ident,
619     },
620 }
621 
622 impl PrintfFormatStringFragment {
623     /// Returns a [`proc_macro2::TokenStream`] representing this fragment.
as_token_stream(&self, printf_formatter_trait_location: &str) -> Result<TokenStream2>624     pub fn as_token_stream(&self, printf_formatter_trait_location: &str) -> Result<TokenStream2> {
625         let crate_name = format_ident!("{}", printf_formatter_trait_location);
626         match self {
627             Self::String(s) => Ok(quote! {#s}),
628             #[cfg(not(feature = "nightly_tait"))]
629             Self::Expr { arg, format_trait } => {
630                 let Arg::ExprCast(cast) = arg else {
631                     return Err(Error::new(&format!(
632                       "Expected argument to untyped format (%v/{{}}) to be a cast expression (e.g. x as i32), but found {}.",
633                       arg.to_token_stream()
634                     )));
635                 };
636                 let ty = &cast.ty;
637                 Ok(quote! {
638                   {
639                     use #crate_name::#format_trait;
640                     <#ty as #format_trait>::FORMAT_ARG
641                   }
642                 })
643             }
644             #[cfg(feature = "nightly_tait")]
645             Self::Expr { expr, format_trait } => Ok(quote! {
646               {
647                 use #crate_name::#format_trait;
648                 type T = impl #format_trait;
649                 let _: &T = &(#expr);
650                 let arg = <T as #format_trait>::FORMAT_ARG;
651                 arg
652               }
653             }),
654         }
655     }
656 }
657 
658 // Wraps a `PrintfFormatMacroGenerator` in a `FormatMacroGenerator` that
659 // generates the format string as it goes.
660 struct PrintfGenerator<GENERATOR: PrintfFormatMacroGenerator> {
661     inner: GENERATOR,
662     format_string_fragments: Vec<PrintfFormatStringFragment>,
663 }
664 
665 impl<GENERATOR: PrintfFormatMacroGenerator> PrintfGenerator<GENERATOR> {
666     // Append `format_string` to the current set of format string fragments.
append_format_string(&mut self, format_string: &str)667     fn append_format_string(&mut self, format_string: &str) {
668         // If the last fragment is a string, append to that.
669         if let PrintfFormatStringFragment::String(s) = self
670             .format_string_fragments
671             .last_mut()
672             .expect("format_string_fragments always has at least one entry")
673         {
674             s.push_str(format_string)
675         } else {
676             // If the last fragment is not a string, add a new string fragment.
677             self.format_string_fragments
678                 .push(PrintfFormatStringFragment::String(
679                     format_string.to_string(),
680                 ));
681         }
682     }
683 }
684 
685 impl<GENERATOR: PrintfFormatMacroGenerator> FormatMacroGenerator for PrintfGenerator<GENERATOR> {
finalize(self) -> Result<TokenStream2>686     fn finalize(self) -> Result<TokenStream2> {
687         self.inner.finalize(&self.format_string_fragments)
688     }
689 
string_fragment(&mut self, string: &str) -> Result<()>690     fn string_fragment(&mut self, string: &str) -> Result<()> {
691         // Escape '%' characters.
692         let format_string = string.replace('%', "%%");
693 
694         self.append_format_string(&format_string);
695         self.inner.string_fragment(string)
696     }
697 
integer_conversion( &mut self, params: &FormatParams, signed: bool, type_width: u8, expression: Arg, ) -> Result<()>698     fn integer_conversion(
699         &mut self,
700         params: &FormatParams,
701         signed: bool,
702         type_width: u8, // in bits
703         expression: Arg,
704     ) -> Result<()> {
705         let length_modifier = match type_width {
706             8 => "hh",
707             16 => "h",
708             32 => "",
709             64 => "ll",
710             _ => {
711                 return Err(Error::new(&format!(
712                     "printf backend does not support {} bit field width",
713                     type_width
714                 )))
715             }
716         };
717 
718         let (conversion, ty) = match params.style {
719             Style::None => {
720                 if signed {
721                     ("d", format_ident!("i{type_width}"))
722                 } else {
723                     ("u", format_ident!("u{type_width}"))
724                 }
725             }
726             Style::Octal => ("o", format_ident!("u{type_width}")),
727             Style::Hex => ("x", format_ident!("u{type_width}")),
728             Style::UpperHex => ("X", format_ident!("u{type_width}")),
729             _ => {
730                 return Err(Error::new(&format!(
731                     "printf backend does not support formatting integers with {:?} style",
732                     params.style
733                 )))
734             }
735         };
736 
737         match self.inner.integer_conversion(ty, expression)? {
738             Some(s) => self.append_format_string(&s),
739             None => self.append_format_string(&format!(
740                 "%{}{}{}",
741                 params.field_params(),
742                 length_modifier,
743                 conversion
744             )),
745         }
746 
747         Ok(())
748     }
749 
string_conversion(&mut self, expression: Arg) -> Result<()>750     fn string_conversion(&mut self, expression: Arg) -> Result<()> {
751         match self.inner.string_conversion(expression)? {
752             Some(s) => self.append_format_string(&s),
753             None => self.append_format_string("%s"),
754         }
755         Ok(())
756     }
757 
char_conversion(&mut self, expression: Arg) -> Result<()>758     fn char_conversion(&mut self, expression: Arg) -> Result<()> {
759         match self.inner.char_conversion(expression)? {
760             Some(s) => self.append_format_string(&s),
761             None => self.append_format_string("%c"),
762         }
763         Ok(())
764     }
765 
untyped_conversion(&mut self, expression: Arg, params: &FormatParams) -> Result<()>766     fn untyped_conversion(&mut self, expression: Arg, params: &FormatParams) -> Result<()> {
767         self.inner.untyped_conversion(expression.clone())?;
768 
769         self.append_format_string(&format!("%{}", params.field_params()));
770         self.format_string_fragments
771             .push(PrintfFormatStringFragment::Expr {
772                 arg: expression,
773                 format_trait: params.printf_format_trait()?,
774             });
775         Ok(())
776     }
777 }
778 
779 /// Generate code for a `pw_format` style proc macro that needs a `printf` format string.
780 ///
781 /// `generate_printf` is a specialized version of [`generate`] which works with
782 /// [`PrintfFormatMacroGenerator`]
generate_printf( generator: impl PrintfFormatMacroGenerator, format_and_args: FormatAndArgs, ) -> core::result::Result<TokenStream2, syn::Error>783 pub fn generate_printf(
784     generator: impl PrintfFormatMacroGenerator,
785     format_and_args: FormatAndArgs,
786 ) -> core::result::Result<TokenStream2, syn::Error> {
787     let generator = PrintfGenerator {
788         inner: generator,
789         format_string_fragments: vec![PrintfFormatStringFragment::String("".into())],
790     };
791     generate(generator, format_and_args)
792 }
793 
794 /// A specialized generator for proc macros that produce [`core::fmt`] style format strings.
795 ///
796 /// For proc macros that need to translate a `pw_format` invocation into a
797 /// [`core::fmt`] style format string, `CoreFmtFormatMacroGenerator` offer a
798 /// specialized form of [`FormatMacroGenerator`] that builds the format string
799 /// and provides it as an argument to
800 /// [`finalize`](CoreFmtFormatMacroGenerator::finalize).
801 ///
802 /// In cases where a generator needs to override the conversion specifier (i.e.
803 /// `{}`, it can return it from its appropriate conversion method.
804 pub trait CoreFmtFormatMacroGenerator {
805     /// Called by [`generate_core_fmt`] at the end of code generation.
806     ///
807     /// Works like [`FormatMacroGenerator::finalize`] with the addition of
808     /// being provided a [`core::fmt`] format string.
finalize(self, format_string: String) -> Result<TokenStream2>809     fn finalize(self, format_string: String) -> Result<TokenStream2>;
810 
811     /// Process a string fragment.
812     ///
813     /// **NOTE**: This string may contain unescaped `{` and `}` characters.
814     /// However, most implementations of this train can simply ignore string
815     /// fragments as they will be included (with properly escaped `{` and `}`
816     /// characters) as part of the format string passed to
817     /// [`CoreFmtFormatMacroGenerator::finalize`].
818     ///
819     ///
820     /// See [`FormatMacroGenerator::string_fragment`] for a disambiguation
821     /// between a string fragment and string conversion.
string_fragment(&mut self, string: &str) -> Result<()>822     fn string_fragment(&mut self, string: &str) -> Result<()>;
823 
824     /// Process an integer conversion.
integer_conversion(&mut self, ty: Ident, expression: Arg) -> Result<Option<String>>825     fn integer_conversion(&mut self, ty: Ident, expression: Arg) -> Result<Option<String>>;
826 
827     /// Process a string conversion.
string_conversion(&mut self, expression: Arg) -> Result<Option<String>>828     fn string_conversion(&mut self, expression: Arg) -> Result<Option<String>>;
829 
830     /// Process a character conversion.
char_conversion(&mut self, expression: Arg) -> Result<Option<String>>831     fn char_conversion(&mut self, expression: Arg) -> Result<Option<String>>;
832 
833     /// Process an untyped conversion.
untyped_conversion(&mut self, _expression: Arg) -> Result<()>834     fn untyped_conversion(&mut self, _expression: Arg) -> Result<()> {
835         Err(Error::new("untyped conversion ({}) not supported"))
836     }
837 }
838 
839 // Wraps a `CoreFmtFormatMacroGenerator` in a `FormatMacroGenerator` that
840 // generates the format string as it goes.
841 struct CoreFmtGenerator<GENERATOR: CoreFmtFormatMacroGenerator> {
842     inner: GENERATOR,
843     format_string: String,
844 }
845 
846 impl<GENERATOR: CoreFmtFormatMacroGenerator> FormatMacroGenerator for CoreFmtGenerator<GENERATOR> {
finalize(self) -> Result<TokenStream2>847     fn finalize(self) -> Result<TokenStream2> {
848         self.inner.finalize(self.format_string)
849     }
850 
string_fragment(&mut self, string: &str) -> Result<()>851     fn string_fragment(&mut self, string: &str) -> Result<()> {
852         // Escape '{' and '} characters.
853         let format_string = string.replace('{', "{{").replace('}', "}}");
854 
855         self.format_string.push_str(&format_string);
856         self.inner.string_fragment(string)
857     }
858 
integer_conversion( &mut self, params: &FormatParams, signed: bool, type_width: u8, expression: Arg, ) -> Result<()>859     fn integer_conversion(
860         &mut self,
861         params: &FormatParams,
862         signed: bool,
863         type_width: u8, // in bits
864         expression: Arg,
865     ) -> Result<()> {
866         let ty = if signed {
867             format_ident!("i{type_width}")
868         } else {
869             format_ident!("u{type_width}")
870         };
871 
872         let conversion = params.core_fmt_specifier()?;
873 
874         match self.inner.integer_conversion(ty, expression)? {
875             Some(s) => self.format_string.push_str(&s),
876             None => self.format_string.push_str(&conversion),
877         }
878 
879         Ok(())
880     }
881 
string_conversion(&mut self, expression: Arg) -> Result<()>882     fn string_conversion(&mut self, expression: Arg) -> Result<()> {
883         match self.inner.string_conversion(expression)? {
884             Some(s) => self.format_string.push_str(&s),
885             None => self.format_string.push_str("{}"),
886         }
887         Ok(())
888     }
889 
char_conversion(&mut self, expression: Arg) -> Result<()>890     fn char_conversion(&mut self, expression: Arg) -> Result<()> {
891         match self.inner.char_conversion(expression)? {
892             Some(s) => self.format_string.push_str(&s),
893             None => self.format_string.push_str("{}"),
894         }
895         Ok(())
896     }
897 
untyped_conversion(&mut self, expression: Arg, params: &FormatParams) -> Result<()>898     fn untyped_conversion(&mut self, expression: Arg, params: &FormatParams) -> Result<()> {
899         self.inner.untyped_conversion(expression)?;
900         self.format_string.push_str(&params.core_fmt_specifier()?);
901         Ok(())
902     }
903 }
904 
905 /// Generate code for a `pw_format` style proc macro that needs a [`core::fmt`] format string.
906 ///
907 /// `generate_core_fmt` is a specialized version of [`generate`] which works with
908 /// [`CoreFmtFormatMacroGenerator`]
generate_core_fmt( generator: impl CoreFmtFormatMacroGenerator, format_and_args: FormatAndArgs, ) -> core::result::Result<TokenStream2, syn::Error>909 pub fn generate_core_fmt(
910     generator: impl CoreFmtFormatMacroGenerator,
911     format_and_args: FormatAndArgs,
912 ) -> core::result::Result<TokenStream2, syn::Error> {
913     let generator = CoreFmtGenerator {
914         inner: generator,
915         format_string: "".into(),
916     };
917     generate(generator, format_and_args)
918 }
919