xref: /aosp_15_r20/external/pigweed/pw_log/rust/pw_log_backend_println_macro.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 use proc_macro::TokenStream;
16 use proc_macro2::Ident;
17 use quote::quote;
18 use syn::{
19     parse::{Parse, ParseStream},
20     parse_macro_input, Expr, Token,
21 };
22 
23 use pw_format::macros::{
24     generate_core_fmt, Arg, CoreFmtFormatMacroGenerator, CoreFmtFormatStringParser,
25     FormatAndArgsFlavor, FormatStringParser, PrintfFormatStringParser, Result,
26 };
27 
28 type TokenStream2 = proc_macro2::TokenStream;
29 
30 // Arguments to `pw_log[f]_backend`.  A log level followed by a [`pw_format`]
31 // format string.
32 #[derive(Debug)]
33 struct PwLogArgs<T: FormatStringParser> {
34     log_level: Expr,
35     format_and_args: FormatAndArgsFlavor<T>,
36 }
37 
38 impl<T: FormatStringParser> Parse for PwLogArgs<T> {
parse(input: ParseStream) -> syn::parse::Result<Self>39     fn parse(input: ParseStream) -> syn::parse::Result<Self> {
40         let log_level: Expr = input.parse()?;
41         input.parse::<Token![,]>()?;
42         let format_and_args: FormatAndArgsFlavor<_> = input.parse()?;
43 
44         Ok(PwLogArgs {
45             log_level,
46             format_and_args,
47         })
48     }
49 }
50 
51 // Generator that implements [`pw_format::CoreFmtFormatMacroGenerator`] to take
52 // a log line and turn it into [`std::println`] calls.
53 struct LogfGenerator<'a> {
54     log_level: &'a Expr,
55     args: Vec<TokenStream2>,
56 }
57 
58 impl<'a> LogfGenerator<'a> {
new(log_level: &'a Expr) -> Self59     fn new(log_level: &'a Expr) -> Self {
60         Self {
61             log_level,
62             args: Vec::new(),
63         }
64     }
65 }
66 
67 // Use a [`pw_format::CoreFmtFormatMacroGenerator`] to prepare arguments to call
68 // [`std::println`].
69 impl<'a> CoreFmtFormatMacroGenerator for LogfGenerator<'a> {
finalize(self, format_string: String) -> Result<TokenStream2>70     fn finalize(self, format_string: String) -> Result<TokenStream2> {
71         let log_level = self.log_level;
72         let args = &self.args;
73         let format_string = format!("[{{}}] {format_string}");
74         Ok(quote! {
75           {
76             use std::println;
77             println!(#format_string, __pw_log_backend_crate::log_level_tag(#log_level), #(#args),*);
78           }
79         })
80     }
81 
string_fragment(&mut self, _string: &str) -> Result<()>82     fn string_fragment(&mut self, _string: &str) -> Result<()> {
83         // String fragments are encoded directly into the format string.
84         Ok(())
85     }
86 
integer_conversion(&mut self, ty: Ident, expression: Arg) -> Result<Option<String>>87     fn integer_conversion(&mut self, ty: Ident, expression: Arg) -> Result<Option<String>> {
88         self.args.push(quote! {((#expression) as #ty)});
89         Ok(None)
90     }
91 
string_conversion(&mut self, expression: Arg) -> Result<Option<String>>92     fn string_conversion(&mut self, expression: Arg) -> Result<Option<String>> {
93         self.args.push(quote! {((#expression) as &str)});
94         Ok(None)
95     }
96 
char_conversion(&mut self, expression: Arg) -> Result<Option<String>>97     fn char_conversion(&mut self, expression: Arg) -> Result<Option<String>> {
98         self.args.push(quote! {((#expression) as char)});
99         Ok(None)
100     }
101 
untyped_conversion(&mut self, expression: Arg) -> Result<()>102     fn untyped_conversion(&mut self, expression: Arg) -> Result<()> {
103         self.args.push(quote! {(#expression)});
104         Ok(())
105     }
106 }
107 
108 #[proc_macro]
_pw_log_backend(tokens: TokenStream) -> TokenStream109 pub fn _pw_log_backend(tokens: TokenStream) -> TokenStream {
110     let input = parse_macro_input!(tokens as PwLogArgs<CoreFmtFormatStringParser>);
111 
112     let generator = LogfGenerator::new(&input.log_level);
113 
114     match generate_core_fmt(generator, input.format_and_args.into()) {
115         Ok(token_stream) => token_stream.into(),
116         Err(e) => e.to_compile_error().into(),
117     }
118 }
119 
120 #[proc_macro]
_pw_logf_backend(tokens: TokenStream) -> TokenStream121 pub fn _pw_logf_backend(tokens: TokenStream) -> TokenStream {
122     let input = parse_macro_input!(tokens as PwLogArgs<PrintfFormatStringParser>);
123 
124     let generator = LogfGenerator::new(&input.log_level);
125 
126     match generate_core_fmt(generator, input.format_and_args.into()) {
127         Ok(token_stream) => token_stream.into(),
128         Err(e) => e.to_compile_error().into(),
129     }
130 }
131