Skip to content

Commit

Permalink
elapsed & limit
Browse files Browse the repository at this point in the history
  • Loading branch information
ironpeak committed Dec 27, 2024
1 parent c540d4b commit 8761a27
Showing 1 changed file with 129 additions and 30 deletions.
159 changes: 129 additions & 30 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,50 @@ use proc_macro2::Span;
use quote::{quote, ToTokens};
use syn::{parse_macro_input, punctuated::Punctuated, spanned::Spanned, token::Semi, *};

fn parse_time(expr: &Expr) -> Result<Duration> {
enum TimeUnit {
Nanoseconds,
Milliseconds,
Seconds,
Minutes,
Hours,
Days,
}

impl TimeUnit {
fn to_duration(&self, amount: u64) -> Duration {
match self {
TimeUnit::Nanoseconds => Duration::from_nanos(amount),
TimeUnit::Milliseconds => Duration::from_millis(amount),
TimeUnit::Seconds => Duration::from_secs(amount),
TimeUnit::Minutes => Duration::from_secs(amount * 60),
TimeUnit::Hours => Duration::from_secs(amount * 60 * 60),
TimeUnit::Days => Duration::from_secs(amount * 60 * 60 * 24),
}
}
}

fn parse_time(expr: &Expr) -> Result<(u64, TimeUnit)> {
match expr {
Expr::Lit(expr_lit) => match &expr_lit.lit {
syn::Lit::Int(literal) => match literal.suffix() {
"ns" => Ok(Duration::from_nanos(literal.base10_parse::<u64>()?)),
"ms" => Ok(Duration::from_millis(literal.base10_parse::<u64>()?)),
"s" => Ok(Duration::from_secs(literal.base10_parse::<u64>()?)),
"m" => Ok(Duration::from_secs(literal.base10_parse::<u64>()? * 60)),
"h" => Ok(Duration::from_secs(
literal.base10_parse::<u64>()? * 60 * 60,
)),
"d" => Ok(Duration::from_secs(
literal.base10_parse::<u64>()? * 60 * 60 * 24,
)),
"" => Ok(Duration::from_millis(literal.base10_parse::<u64>()?)),
suffix => Err(syn::Error::new(
expr.span(),
format!("Unexpected a numeric literal suffix {}", suffix),
)),
},
syn::Lit::Int(literal) => {
let amount = literal.base10_parse::<u64>()?;
let unit = match literal.suffix() {
"ns" => TimeUnit::Nanoseconds,
"ms" => TimeUnit::Milliseconds,
"s" => TimeUnit::Seconds,
"m" => TimeUnit::Minutes,
"h" => TimeUnit::Hours,
"d" => TimeUnit::Days,
"" => TimeUnit::Milliseconds,
suffix => {
return Err(syn::Error::new(
expr.span(),
format!("Unexpected a numeric literal suffix {}", suffix),
))
}
};
Ok((amount, unit))
}
_ => Err(syn::Error::new(expr.span(), "Expected a numeric literal")),
},
_ => Err(syn::Error::new(expr.span(), "Expected a numeric literal")),
Expand All @@ -42,14 +66,17 @@ pub fn slow_function_warning(args: TokenStream, input: TokenStream) -> TokenStre
} else {
Punctuated::default()
};

let Item::Fn(function) = syn::parse(input).unwrap() else {
panic!("slow_function_warning can only be used on functions");
};
let time = if let Some(time_expr) = args.get(0) {

let (time, unit) = if let Some(time_expr) = args.get(0) {
parse_time(time_expr).unwrap()
} else {
Duration::from_millis(1)
(1, TimeUnit::Milliseconds)
};

let stmt = if let Some(stmt) = args.get(1) {
Stmt::Expr(stmt.clone(), Some(Semi::default()))
} else {
Expand All @@ -61,11 +88,9 @@ pub fn slow_function_warning(args: TokenStream, input: TokenStream) -> TokenStre
)
.unwrap()
};
slow_function_warning_common(time, stmt, function)
}

fn slow_function_warning_common(time: Duration, stmt: Stmt, function: ItemFn) -> TokenStream {
let nano_seconds = time.as_nanos();
let duration = unit.to_duration(time);
let nano_seconds = duration.as_nanos();
let function_name_ident = function.sig.ident.clone();
let function_name = Lit::Str(LitStr::new(
&function_name_ident.to_string(),
Expand Down Expand Up @@ -125,6 +150,48 @@ fn slow_function_warning_common(time: Duration, stmt: Stmt, function: ItemFn) ->
.unwrap()
};

let elapsed_str = match unit {
TimeUnit::Nanoseconds => quote! {
format!("{}ns", elapsed.as_nanos())
},
TimeUnit::Milliseconds => quote! {
format!("{}ms", elapsed.as_millis())
},
TimeUnit::Seconds => quote! {
format!("{}s", elapsed.as_secs())
},
TimeUnit::Minutes => quote! {
format!("{}m", elapsed.as_secs() / 60)
},
TimeUnit::Hours => quote! {
format!("{}h", elapsed.as_secs() / 60 / 60)
},
TimeUnit::Days => quote! {
format!("{}d", elapsed.as_secs() / 60 / 60 / 24)
},
};

let limit_str = match unit {
TimeUnit::Nanoseconds => quote! {
format!("{}ns", limit.as_nanos())
},
TimeUnit::Milliseconds => quote! {
format!("{}ms", limit.as_millis())
},
TimeUnit::Seconds => quote! {
format!("{}s", limit.as_secs())
},
TimeUnit::Minutes => quote! {
format!("{}m", limit.as_secs() / 60)
},
TimeUnit::Hours => quote! {
format!("{}h", limit.as_secs() / 60 / 60)
},
TimeUnit::Days => quote! {
format!("{}d", limit.as_secs() / 60 / 60 / 24)
},
};

result.block = syn::parse(
quote! {{
#closure_decleration
Expand All @@ -136,13 +203,45 @@ fn slow_function_warning_common(time: Duration, stmt: Stmt, function: ItemFn) ->
if start.elapsed().as_nanos() > #nano_seconds {
let module = module_path!();
let function = #function_name;

let elapsed = start.elapsed();
let ns = elapsed.as_nanos();
let nanos = ns;
let ms = elapsed.as_millis();
let millis = ms;
let s = elapsed.as_secs();
let secs = s;
let elapsed_str = #elapsed_str;
let elapsed_ns = elapsed.as_nanos();
let elapsed_nanos = elapsed_ns;
let elapsed_nanoseconds = elapsed_ns;
let elapsed_ms = elapsed.as_millis();
let elapsed_millis = elapsed_ms;
let elapsed_milliseconds = elapsed_ms;
let elapsed_s = elapsed.as_secs();
let elapsed_secs = elapsed_s;
let elapsed_seconds = elapsed_s;
let elapsed_m = elapsed.as_secs() / 60;
let elapsed_min = elapsed_m;
let elapsed_minutes = elapsed_m;
let elapsed_h = elapsed.as_secs() / 60 / 60;
let elapsed_hours = elapsed_h;
let elapsed_d = elapsed.as_secs() / 60 / 60 / 24;
let elapsed_days = elapsed_d;

let limit = Duration::from_nanos(#nano_seconds as u64);
let limit_str = #limit_str;
let limit_ns = limit.as_nanos();
let limit_nanos = limit_ns;
let limit_nanoseconds = limit_ns;
let limit_ms = limit.as_millis();
let limit_millis = limit_ms;
let limit_milliseconds = limit_ms;
let limit_s = limit.as_secs();
let limit_secs = limit_s;
let limit_seconds = limit_s;
let limit_m = limit.as_secs() / 60;
let limit_min = limit_m;
let limit_minutes = limit_m;
let limit_h = limit.as_secs() / 60 / 60;
let limit_hours = limit_h;
let limit_d = limit.as_secs() / 60 / 60 / 24;
let limit_days = limit_d;

#stmt
}
result
Expand Down

0 comments on commit 8761a27

Please sign in to comment.