prefixes_s/
lib.rs

1//! A procedural macro that allows you to use the `s` attribute to create a `Duration` from a number of seconds.
2//! Part of the [prefixes](https://crates.io/crates/prefixes) crate.
3
4use proc_macro::TokenStream;
5use quote::quote;
6use syn::{parse, LitFloat, LitInt};
7
8#[proc_macro_attribute]
9pub fn s(_: TokenStream, input: TokenStream) -> TokenStream {
10    if let Ok(i) = parse::<LitInt>(input.clone()) {
11        return quote! { ::core::time::Duration::from_secs(#i) }.into();
12    }
13
14    if let Ok(i) = parse::<LitFloat>(input.clone()) {
15        match i.suffix() {
16            "f32" => return quote! { ::core::time::Duration::from_secs_f32(#i) }.into(),
17            "f64" | "" => return quote! { ::core::time::Duration::from_secs_f64(#i) }.into(),
18            s => {
19                return compile_error(
20                    input,
21                    &format!("unexpected float suffix: {s}. Expected 'f32' or 'f64'"),
22                )
23            }
24        }
25    }
26
27    compile_error(input, "expected integer or float literal")
28}
29
30fn compile_error(input: TokenStream, msg: &str) -> TokenStream {
31    syn::Error::new_spanned(
32        proc_macro2::TokenStream::from(input),
33        format!("Could not apply #[s] prefix: {msg}"),
34    )
35    .to_compile_error()
36    .into()
37}