1use std::collections::HashSet;
2use syn::{punctuated::Punctuated, Expr, Ident, LitInt, LitStr, Path, Token};
3
4use proc_macro2::TokenStream;
5use quote::{quote, quote_spanned, ToTokens};
6use syn::ext::IdentExt as _;
7use syn::parse::{Parse, ParseStream};
8use syn::token::Brace;
9
10#[derive(Clone, Default, Debug)]
13pub(crate) struct EventArgs {
14 level: Option<Level>,
15 pub(crate) mode: FormatMode,
16}
17
18#[derive(Clone, Default, Debug)]
19pub(crate) struct InstrumentArgs {
20 level: Option<Level>,
21 pub(crate) name: Option<LitStrOrIdent>,
22 target: Option<LitStrOrIdent>,
23 pub(crate) parent: Option<Expr>,
24 pub(crate) follows_from: Option<Expr>,
25 pub(crate) skips: HashSet<Ident>,
26 pub(crate) skip_all: bool,
27 pub(crate) fields: Option<Fields>,
28 pub(crate) err_args: Option<EventArgs>,
29 pub(crate) ret_args: Option<EventArgs>,
30 parse_warnings: Vec<syn::Error>,
32}
33
34impl InstrumentArgs {
35 pub(crate) fn level(&self) -> Level {
36 self.level.clone().unwrap_or(Level::Info)
37 }
38
39 pub(crate) fn target(&self) -> impl ToTokens {
40 if let Some(ref target) = self.target {
41 quote!(#target)
42 } else {
43 quote!(module_path!())
44 }
45 }
46
47 pub(crate) fn warnings(&self) -> impl ToTokens {
54 let warnings = self.parse_warnings.iter().map(|err| {
55 let msg = format!("found unrecognized input, {}", err);
56 let msg = LitStr::new(&msg, err.span());
57 quote_spanned! {err.span()=>
62 #[warn(deprecated)]
63 {
64 #[deprecated(since = "not actually deprecated", note = #msg)]
65 const TRACING_INSTRUMENT_WARNING: () = ();
66 let _ = TRACING_INSTRUMENT_WARNING;
67 }
68 }
69 });
70 quote! {
71 { #(#warnings)* }
72 }
73 }
74}
75
76impl Parse for InstrumentArgs {
77 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
78 let mut args = Self::default();
79 while !input.is_empty() {
80 let lookahead = input.lookahead1();
81 if lookahead.peek(kw::name) {
82 if args.name.is_some() {
83 return Err(input.error("expected only a single `name` argument"));
84 }
85 let name = input.parse::<StrArg<kw::name>>()?.value;
86 args.name = Some(name);
87 } else if lookahead.peek(LitStr) {
88 if args.name.is_some() {
94 return Err(input.error("expected only a single `name` argument"));
95 }
96 args.name = Some(input.parse()?);
97 } else if lookahead.peek(kw::target) {
98 if args.target.is_some() {
99 return Err(input.error("expected only a single `target` argument"));
100 }
101 let target = input.parse::<StrArg<kw::target>>()?.value;
102 args.target = Some(target);
103 } else if lookahead.peek(kw::parent) {
104 if args.target.is_some() {
105 return Err(input.error("expected only a single `parent` argument"));
106 }
107 let parent = input.parse::<ExprArg<kw::parent>>()?;
108 args.parent = Some(parent.value);
109 } else if lookahead.peek(kw::follows_from) {
110 if args.target.is_some() {
111 return Err(input.error("expected only a single `follows_from` argument"));
112 }
113 let follows_from = input.parse::<ExprArg<kw::follows_from>>()?;
114 args.follows_from = Some(follows_from.value);
115 } else if lookahead.peek(kw::level) {
116 if args.level.is_some() {
117 return Err(input.error("expected only a single `level` argument"));
118 }
119 args.level = Some(input.parse()?);
120 } else if lookahead.peek(kw::skip) {
121 if !args.skips.is_empty() {
122 return Err(input.error("expected only a single `skip` argument"));
123 }
124 if args.skip_all {
125 return Err(input.error("expected either `skip` or `skip_all` argument"));
126 }
127 let Skips(skips) = input.parse()?;
128 args.skips = skips;
129 } else if lookahead.peek(kw::skip_all) {
130 if args.skip_all {
131 return Err(input.error("expected only a single `skip_all` argument"));
132 }
133 if !args.skips.is_empty() {
134 return Err(input.error("expected either `skip` or `skip_all` argument"));
135 }
136 let _ = input.parse::<kw::skip_all>()?;
137 args.skip_all = true;
138 } else if lookahead.peek(kw::fields) {
139 if args.fields.is_some() {
140 return Err(input.error("expected only a single `fields` argument"));
141 }
142 args.fields = Some(input.parse()?);
143 } else if lookahead.peek(kw::err) {
144 let _ = input.parse::<kw::err>();
145 let err_args = EventArgs::parse(input)?;
146 args.err_args = Some(err_args);
147 } else if lookahead.peek(kw::ret) {
148 let _ = input.parse::<kw::ret>()?;
149 let ret_args = EventArgs::parse(input)?;
150 args.ret_args = Some(ret_args);
151 } else if lookahead.peek(Token![,]) {
152 let _ = input.parse::<Token![,]>()?;
153 } else {
154 args.parse_warnings.push(lookahead.error());
159 let _ = input.parse::<proc_macro2::TokenTree>();
162 }
163 }
164 Ok(args)
165 }
166}
167
168impl EventArgs {
169 pub(crate) fn level(&self, default: Level) -> Level {
170 self.level.clone().unwrap_or(default)
171 }
172}
173
174impl Parse for EventArgs {
175 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
176 if !input.peek(syn::token::Paren) {
177 return Ok(Self::default());
178 }
179 let content;
180 let _ = syn::parenthesized!(content in input);
181 let mut result = Self::default();
182 let mut parse_one_arg =
183 || {
184 let lookahead = content.lookahead1();
185 if lookahead.peek(kw::level) {
186 if result.level.is_some() {
187 return Err(content.error("expected only a single `level` argument"));
188 }
189 result.level = Some(content.parse()?);
190 } else if result.mode != FormatMode::default() {
191 return Err(content.error("expected only a single format argument"));
192 } else if let Some(ident) = content.parse::<Option<Ident>>()? {
193 match ident.to_string().as_str() {
194 "Debug" => result.mode = FormatMode::Debug,
195 "Display" => result.mode = FormatMode::Display,
196 _ => return Err(syn::Error::new(
197 ident.span(),
198 "unknown event formatting mode, expected either `Debug` or `Display`",
199 )),
200 }
201 }
202 Ok(())
203 };
204 parse_one_arg()?;
205 if !content.is_empty() {
206 if content.lookahead1().peek(Token![,]) {
207 let _ = content.parse::<Token![,]>()?;
208 parse_one_arg()?;
209 } else {
210 return Err(content.error("expected `,` or `)`"));
211 }
212 }
213 Ok(result)
214 }
215}
216
217#[derive(Debug, Clone)]
218pub(super) enum LitStrOrIdent {
219 LitStr(LitStr),
220 Ident(Ident),
221}
222
223impl ToTokens for LitStrOrIdent {
224 fn to_tokens(&self, tokens: &mut TokenStream) {
225 match self {
226 LitStrOrIdent::LitStr(target) => target.to_tokens(tokens),
227 LitStrOrIdent::Ident(ident) => ident.to_tokens(tokens),
228 }
229 }
230}
231
232impl Parse for LitStrOrIdent {
233 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
234 input
235 .parse::<LitStr>()
236 .map(LitStrOrIdent::LitStr)
237 .or_else(|_| input.parse::<Ident>().map(LitStrOrIdent::Ident))
238 }
239}
240
241struct StrArg<T> {
242 value: LitStrOrIdent,
243 _p: std::marker::PhantomData<T>,
244}
245
246impl<T: Parse> Parse for StrArg<T> {
247 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
248 let _ = input.parse::<T>()?;
249 let _ = input.parse::<Token![=]>()?;
250 let value = input.parse()?;
251 Ok(Self {
252 value,
253 _p: std::marker::PhantomData,
254 })
255 }
256}
257
258struct ExprArg<T> {
259 value: Expr,
260 _p: std::marker::PhantomData<T>,
261}
262
263impl<T: Parse> Parse for ExprArg<T> {
264 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
265 let _ = input.parse::<T>()?;
266 let _ = input.parse::<Token![=]>()?;
267 let value = input.parse()?;
268 Ok(Self {
269 value,
270 _p: std::marker::PhantomData,
271 })
272 }
273}
274
275struct Skips(HashSet<Ident>);
276
277impl Parse for Skips {
278 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
279 let _ = input.parse::<kw::skip>();
280 let content;
281 let _ = syn::parenthesized!(content in input);
282 let names = content.parse_terminated(Ident::parse_any, Token![,])?;
283 let mut skips = HashSet::new();
284 for name in names {
285 if skips.contains(&name) {
286 return Err(syn::Error::new(
287 name.span(),
288 "tried to skip the same field twice",
289 ));
290 } else {
291 skips.insert(name);
292 }
293 }
294 Ok(Self(skips))
295 }
296}
297
298#[derive(Clone, Debug, Hash, PartialEq, Eq, Default)]
299pub(crate) enum FormatMode {
300 #[default]
301 Default,
302 Display,
303 Debug,
304}
305
306#[derive(Clone, Debug)]
307pub(crate) struct Fields(pub(crate) Punctuated<Field, Token![,]>);
308
309#[derive(Clone, Debug)]
310pub(crate) struct Field {
311 pub(crate) name: FieldName,
312 pub(crate) value: Option<Expr>,
313 pub(crate) kind: FieldKind,
314}
315
316#[derive(Clone, Debug, Eq, PartialEq)]
317pub(crate) enum FieldKind {
318 Debug,
319 Display,
320 Value,
321}
322
323#[derive(Clone, Debug)]
324pub(crate) enum FieldName {
325 Expr(Expr),
326 Punctuated(Punctuated<Ident, Token![.]>),
327}
328
329impl ToTokens for FieldName {
330 fn to_tokens(&self, tokens: &mut TokenStream) {
331 match self {
332 FieldName::Expr(expr) => {
333 Brace::default().surround(tokens, |tokens| expr.to_tokens(tokens));
334 }
335 FieldName::Punctuated(punctuated) => punctuated.to_tokens(tokens),
336 }
337 }
338}
339
340impl Parse for Fields {
341 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
342 let _ = input.parse::<kw::fields>();
343 let content;
344 let _ = syn::parenthesized!(content in input);
345 let fields = content.parse_terminated(Field::parse, Token![,])?;
346 Ok(Self(fields))
347 }
348}
349
350impl ToTokens for Fields {
351 fn to_tokens(&self, tokens: &mut TokenStream) {
352 self.0.to_tokens(tokens)
353 }
354}
355
356impl Parse for Field {
357 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
358 let mut kind = FieldKind::Value;
359 if input.peek(Token![%]) {
360 input.parse::<Token![%]>()?;
361 kind = FieldKind::Display;
362 } else if input.peek(Token![?]) {
363 input.parse::<Token![?]>()?;
364 kind = FieldKind::Debug;
365 };
366 let name = if input.peek(syn::token::Brace) {
368 let content;
369 let _ = syn::braced!(content in input);
370 let expr = content.call(Expr::parse)?;
371 FieldName::Expr(expr)
372 } else {
373 FieldName::Punctuated(Punctuated::parse_separated_nonempty_with(
374 input,
375 Ident::parse_any,
376 )?)
377 };
378 let value = if input.peek(Token![=]) {
379 input.parse::<Token![=]>()?;
380 if input.peek(Token![%]) {
381 input.parse::<Token![%]>()?;
382 kind = FieldKind::Display;
383 } else if input.peek(Token![?]) {
384 input.parse::<Token![?]>()?;
385 kind = FieldKind::Debug;
386 };
387 Some(input.parse()?)
388 } else {
389 None
390 };
391 Ok(Self { name, value, kind })
392 }
393}
394
395impl ToTokens for Field {
396 fn to_tokens(&self, tokens: &mut TokenStream) {
397 if let Some(ref value) = self.value {
398 let name = &self.name;
399 let kind = &self.kind;
400 tokens.extend(quote! {
401 #name = #kind #value
402 })
403 } else if self.kind == FieldKind::Value {
404 let name = &self.name;
410 tokens.extend(quote!(#name = ::tracing::field::Empty))
411 } else {
412 self.kind.to_tokens(tokens);
413 self.name.to_tokens(tokens);
414 }
415 }
416}
417
418impl ToTokens for FieldKind {
419 fn to_tokens(&self, tokens: &mut TokenStream) {
420 match self {
421 FieldKind::Debug => tokens.extend(quote! { ? }),
422 FieldKind::Display => tokens.extend(quote! { % }),
423 _ => {}
424 }
425 }
426}
427
428#[derive(Clone, Debug)]
429pub(crate) enum Level {
430 Trace,
431 Debug,
432 Info,
433 Warn,
434 Error,
435 Path(Path),
436}
437
438impl Parse for Level {
439 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
440 let _ = input.parse::<kw::level>()?;
441 let _ = input.parse::<Token![=]>()?;
442 let lookahead = input.lookahead1();
443 if lookahead.peek(LitStr) {
444 let str: LitStr = input.parse()?;
445 match str.value() {
446 s if s.eq_ignore_ascii_case("trace") => Ok(Level::Trace),
447 s if s.eq_ignore_ascii_case("debug") => Ok(Level::Debug),
448 s if s.eq_ignore_ascii_case("info") => Ok(Level::Info),
449 s if s.eq_ignore_ascii_case("warn") => Ok(Level::Warn),
450 s if s.eq_ignore_ascii_case("error") => Ok(Level::Error),
451 _ => Err(input.error(
452 "unknown verbosity level, expected one of \"trace\", \
453 \"debug\", \"info\", \"warn\", or \"error\", or a number 1-5",
454 )),
455 }
456 } else if lookahead.peek(LitInt) {
457 fn is_level(lit: &LitInt, expected: u64) -> bool {
458 match lit.base10_parse::<u64>() {
459 Ok(value) => value == expected,
460 Err(_) => false,
461 }
462 }
463 let int: LitInt = input.parse()?;
464 match &int {
465 i if is_level(i, 1) => Ok(Level::Trace),
466 i if is_level(i, 2) => Ok(Level::Debug),
467 i if is_level(i, 3) => Ok(Level::Info),
468 i if is_level(i, 4) => Ok(Level::Warn),
469 i if is_level(i, 5) => Ok(Level::Error),
470 _ => Err(input.error(
471 "unknown verbosity level, expected one of \"trace\", \
472 \"debug\", \"info\", \"warn\", or \"error\", or a number 1-5",
473 )),
474 }
475 } else if lookahead.peek(Ident) {
476 Ok(Self::Path(input.parse()?))
477 } else {
478 Err(lookahead.error())
479 }
480 }
481}
482
483impl ToTokens for Level {
484 fn to_tokens(&self, tokens: &mut TokenStream) {
485 match self {
486 Level::Trace => tokens.extend(quote!(::tracing::Level::TRACE)),
487 Level::Debug => tokens.extend(quote!(::tracing::Level::DEBUG)),
488 Level::Info => tokens.extend(quote!(::tracing::Level::INFO)),
489 Level::Warn => tokens.extend(quote!(::tracing::Level::WARN)),
490 Level::Error => tokens.extend(quote!(::tracing::Level::ERROR)),
491 Level::Path(ref pat) => tokens.extend(quote!(#pat)),
492 }
493 }
494}
495
496mod kw {
497 syn::custom_keyword!(fields);
498 syn::custom_keyword!(skip);
499 syn::custom_keyword!(skip_all);
500 syn::custom_keyword!(level);
501 syn::custom_keyword!(target);
502 syn::custom_keyword!(parent);
503 syn::custom_keyword!(follows_from);
504 syn::custom_keyword!(name);
505 syn::custom_keyword!(err);
506 syn::custom_keyword!(ret);
507}