1use super::*;
18
19use syn::{
20 parse::{Parse, ParseStream},
21 Token,
22};
23
24pub(crate) mod kw {
25 syn::custom_keyword!(target);
26 syn::custom_keyword!(freq);
27 syn::custom_keyword!(max_rate);
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub(crate) struct Target {
32 kw: kw::target,
33 colon: Token![:],
34 expr: syn::Expr,
35}
36
37impl Parse for Target {
38 fn parse(input: ParseStream) -> Result<Self> {
39 Ok(Self { kw: input.parse()?, colon: input.parse()?, expr: input.parse()? })
40 }
41}
42
43impl ToTokens for Target {
44 fn to_tokens(&self, tokens: &mut TokenStream) {
45 let kw = &self.kw;
46 let colon = &self.colon;
47 let expr = &self.expr;
48 tokens.extend(quote! {
49 #kw #colon #expr
50 })
51 }
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub(crate) enum FormatMarker {
56 Questionmark(Token![?]),
57 Percentage(Token![%]),
58 None,
59}
60
61impl Parse for FormatMarker {
62 fn parse(input: ParseStream) -> Result<Self> {
63 let lookahead = input.lookahead1();
64 if lookahead.peek(Token![?]) {
65 input.parse().map(Self::Questionmark)
66 } else if lookahead.peek(Token![%]) {
67 input.parse().map(Self::Percentage)
68 } else {
69 Ok(Self::None)
70 }
71 }
72}
73
74impl ToTokens for FormatMarker {
75 fn to_tokens(&self, tokens: &mut TokenStream) {
76 tokens.extend(match self {
77 Self::Percentage(p) => p.to_token_stream(),
78 Self::Questionmark(q) => q.to_token_stream(),
79 Self::None => TokenStream::new(),
80 })
81 }
82}
83
84#[derive(Debug, Clone, PartialEq, Eq)]
85pub(crate) struct ValueWithAliasIdent {
86 pub alias: Ident,
87 pub eq: Token![=],
88 pub marker: FormatMarker,
89 pub expr: syn::Expr,
90}
91
92impl Parse for ValueWithAliasIdent {
93 fn parse(input: ParseStream) -> Result<Self> {
94 Ok(Self {
95 alias: input.parse()?,
96 eq: input.parse()?,
97 marker: input.parse()?,
98 expr: input.parse()?,
99 })
100 }
101}
102
103impl ToTokens for ValueWithAliasIdent {
104 fn to_tokens(&self, tokens: &mut TokenStream) {
105 let alias = &self.alias;
106 let eq = &self.eq;
107 let marker = &self.marker;
108 let expr = &self.expr;
109 tokens.extend(quote! {
110 #alias #eq #marker #expr
111 })
112 }
113}
114
115#[derive(Debug, Clone, PartialEq, Eq)]
116
117pub(crate) struct ValueWithFormatMarker {
118 pub marker: FormatMarker,
119 pub ident: Ident,
120 pub dot: Option<Token![.]>,
121 pub inner: Punctuated<syn::Member, Token![.]>,
122}
123
124impl Parse for ValueWithFormatMarker {
125 fn parse(input: ParseStream) -> Result<Self> {
126 let marker = input.parse::<FormatMarker>()?;
127 let ident = input.parse::<syn::Ident>()?;
128
129 let mut inner = Punctuated::<syn::Member, Token![.]>::new();
130
131 let lookahead = input.lookahead1();
132 let dot = if lookahead.peek(Token![.]) {
133 let dot = Some(input.parse::<Token![.]>()?);
134
135 loop {
136 let member = input.parse::<syn::Member>()?;
137 inner.push_value(member);
138
139 let lookahead = input.lookahead1();
140 if !lookahead.peek(Token![.]) {
141 break
142 }
143
144 let token = input.parse::<Token![.]>()?;
145 inner.push_punct(token);
146 }
147
148 dot
149 } else {
150 None
151 };
152 Ok(Self { marker, ident, dot, inner })
153 }
154}
155
156impl ToTokens for ValueWithFormatMarker {
157 fn to_tokens(&self, tokens: &mut TokenStream) {
158 let marker = &self.marker;
159 let ident = &self.ident;
160 let dot = &self.dot;
161 let inner = &self.inner;
162 tokens.extend(quote! {
163 #marker #ident #dot #inner
164 })
165 }
166}
167
168#[derive(Debug, Clone, PartialEq, Eq)]
170
171pub(crate) enum Value {
172 Alias(ValueWithAliasIdent),
173 Value(ValueWithFormatMarker),
174}
175
176impl Value {
177 pub fn as_ident(&self) -> &Ident {
178 match self {
179 Self::Alias(alias) => &alias.alias,
180 Self::Value(value) => &value.ident,
181 }
182 }
183}
184
185impl Parse for Value {
186 fn parse(input: ParseStream) -> Result<Self> {
187 if input.fork().parse::<ValueWithAliasIdent>().is_ok() {
188 input.parse().map(Self::Alias)
189 } else if input.fork().parse::<ValueWithFormatMarker>().is_ok() {
190 input.parse().map(Self::Value)
191 } else {
192 Err(syn::Error::new(Span::call_site(), "Neither value nor aliased value."))
193 }
194 }
195}
196
197impl ToTokens for Value {
198 fn to_tokens(&self, tokens: &mut TokenStream) {
199 tokens.extend(match self {
200 Self::Alias(alias) => quote! { #alias },
201 Self::Value(value) => quote! { #value },
202 })
203 }
204}
205
206#[derive(Debug, Clone)]
215pub(crate) struct FmtGroup {
216 pub format_str: syn::LitStr,
217 pub maybe_comma: Option<Token![,]>,
218 pub rest: TokenStream,
219}
220
221impl Parse for FmtGroup {
222 fn parse(input: ParseStream) -> Result<Self> {
223 let format_str = input
224 .parse()
225 .map_err(|e| syn::Error::new(e.span(), "Expected format specifier"))?;
226
227 let (maybe_comma, rest) = if input.peek(Token![,]) {
228 let comma = input.parse::<Token![,]>()?;
229 let rest = input.parse()?;
230 (Some(comma), rest)
231 } else {
232 (None, TokenStream::new())
233 };
234
235 if !input.is_empty() {
236 return Err(syn::Error::new(input.span(), "Unexpected data, expected closing `)`."))
237 }
238
239 Ok(Self { format_str, maybe_comma, rest })
240 }
241}
242
243impl ToTokens for FmtGroup {
244 fn to_tokens(&self, tokens: &mut TokenStream) {
245 let format_str = &self.format_str;
246 let maybe_comma = &self.maybe_comma;
247 let rest = &self.rest;
248
249 tokens.extend(quote! { #format_str #maybe_comma #rest });
250 }
251}
252
253#[derive(Debug, Clone, PartialEq, Eq)]
254pub(crate) struct Freq {
255 kw: kw::freq,
256 colon: Token![:],
257 pub expr: syn::Expr,
258}
259
260impl Parse for Freq {
261 fn parse(input: ParseStream) -> Result<Self> {
262 Ok(Self { kw: input.parse()?, colon: input.parse()?, expr: input.parse()? })
263 }
264}
265
266#[derive(Debug, Clone, PartialEq, Eq)]
267pub(crate) struct MaxRate {
268 kw: kw::max_rate,
269 colon: Token![:],
270 pub expr: syn::Expr,
271}
272
273impl Parse for MaxRate {
274 fn parse(input: ParseStream) -> Result<Self> {
275 Ok(Self { kw: input.parse()?, colon: input.parse()?, expr: input.parse()? })
276 }
277}
278
279pub(crate) struct ArgsIfFrequent {
280 pub freq: Freq,
281 pub max_rate: MaxRate,
282 pub rest: TokenStream,
283}
284
285impl Parse for ArgsIfFrequent {
286 fn parse(input: ParseStream) -> Result<Self> {
287 let freq = input.parse()?;
288 let _: Token![,] = input.parse()?;
289 let max_rate = input.parse()?;
290 let _: Token![,] = input.parse()?;
291 let rest = input.parse()?;
292
293 Ok(Self { freq, max_rate, rest })
294 }
295}
296
297#[derive(Debug, Clone)]
299pub(crate) struct Args {
300 pub target: Option<Target>,
301 pub comma: Option<Token![,]>,
302 pub values: Punctuated<Value, Token![,]>,
303 pub fmt: Option<FmtGroup>,
304}
305
306impl Parse for Args {
307 fn parse(input: ParseStream) -> Result<Self> {
308 let lookahead = input.lookahead1();
309 let (target, comma) = if lookahead.peek(kw::target) {
310 let target = input.parse()?;
311 let comma = input.parse::<Token![,]>()?;
312 (Some(target), Some(comma))
313 } else {
314 (None, None)
315 };
316
317 let mut values = Punctuated::new();
318 loop {
319 if input.fork().parse::<Value>().is_ok() {
320 values.push_value(input.parse::<Value>()?);
321 } else {
322 break
323 }
324 if input.peek(Token![,]) {
325 values.push_punct(input.parse::<Token![,]>()?);
326 } else {
327 break
328 }
329 }
330
331 let fmt = if values.empty_or_trailing() && !input.is_empty() {
332 let fmt = input.parse::<FmtGroup>()?;
333 Some(fmt)
334 } else {
335 None
336 };
337
338 Ok(Self { target, comma, values, fmt })
339 }
340}
341
342impl ToTokens for Args {
343 fn to_tokens(&self, tokens: &mut TokenStream) {
344 let target = &self.target;
345 let comma = &self.comma;
346 let values = &self.values;
347 let fmt = &self.fmt;
348 tokens.extend(quote! {
349 #target #comma #values #fmt
350 })
351 }
352}
353
354#[derive(Debug, Clone, Copy, PartialEq, Eq)]
359pub(crate) enum Level {
360 Error,
361 Warn,
362 Info,
363 Debug,
364 Trace,
365}
366
367impl ToTokens for Level {
368 fn to_tokens(&self, tokens: &mut TokenStream) {
369 let span = Span::call_site();
370 let variant = match self {
371 Self::Error => Ident::new("ERROR", span),
372 Self::Warn => Ident::new("WARN", span),
373 Self::Info => Ident::new("INFO", span),
374 Self::Debug => Ident::new("DEBUG", span),
375 Self::Trace => Ident::new("TRACE", span),
376 };
377 let krate = support_crate();
378 tokens.extend(quote! {
379 #krate :: Level :: #variant
380 })
381 }
382}