#[macro_export]
#[cfg(debug_assertions)]
macro_rules! timed {
($label:expr, $callback:expr, $block:expr) => {{
let __timed_start = ::std::time::Instant::now();
let __timed_result = $block;
($callback)($label, __timed_start.elapsed());
__timed_result
}};
}
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! timed {
($label:expr, $callback:expr, $block:expr) => {
$block
};
}
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! timed_dbg {
($label:expr, $block:expr) => {{
let __start = ::std::time::Instant::now();
let __result = $block;
$crate::__varve_log_timing!($label, __start.elapsed());
__result
}};
}
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! timed_dbg {
($label:expr, $block:expr) => {
$block
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __varve_log_timing {
($label:expr, $elapsed:expr) => {
#[cfg(feature = "debug_eprintln")]
{
eprintln!("[varve] {}: {:?}", $label, $elapsed);
}
#[cfg(all(not(feature = "debug_eprintln"), feature = "log_trace"))]
{
::tracing::trace!("[varve] {}: {:?}", $label, $elapsed);
}
#[cfg(all(
not(feature = "debug_eprintln"),
not(feature = "log_trace"),
feature = "log_debug"
))]
{
::tracing::debug!("[varve] {}: {:?}", $label, $elapsed);
}
#[cfg(all(
not(feature = "debug_eprintln"),
not(feature = "log_trace"),
not(feature = "log_debug"),
feature = "log_info"
))]
{
::tracing::info!("[varve] {}: {:?}", $label, $elapsed);
}
#[cfg(all(
not(feature = "debug_eprintln"),
not(feature = "log_trace"),
not(feature = "log_debug"),
not(feature = "log_info"),
feature = "log_warn"
))]
{
::tracing::warn!("[varve] {}: {:?}", $label, $elapsed);
}
#[cfg(all(
not(feature = "debug_eprintln"),
not(feature = "log_trace"),
not(feature = "log_debug"),
not(feature = "log_info"),
not(feature = "log_warn"),
feature = "log_error"
))]
{
::tracing::error!("[varve] {}: {:?}", $label, $elapsed);
}
#[cfg(not(any(
feature = "debug_eprintln",
feature = "log_trace",
feature = "log_debug",
feature = "log_info",
feature = "log_warn",
feature = "log_error"
)))]
{
let _ = ($label, $elapsed);
}
};
}
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! debug_only {
($block:expr) => {
$block
};
}
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! debug_only {
($block:expr) => {
()
};
}
#[cfg(test)]
mod tests {
use std::time::Duration;
#[test]
fn test_timed_returns_block_result() {
let result = timed!("test", |_: &str, _: Duration| {}, { 42 });
assert_eq!(result, 42);
}
#[test]
fn test_timed_calls_callback() {
use std::cell::Cell;
let called = Cell::new(false);
let _: () = timed!(
"test",
|label: &str, dur: Duration| {
assert_eq!(label, "test");
assert!(dur.as_nanos() > 0);
called.set(true);
},
{
std::thread::sleep(Duration::from_micros(10));
}
);
#[cfg(debug_assertions)]
assert!(called.get(), "callback should be called in debug builds");
}
#[test]
fn test_timed_dbg_returns_block_result() {
let result = timed_dbg!("test_op", { "hello" });
assert_eq!(result, "hello");
}
#[test]
fn test_debug_only_executes_in_debug() {
use std::cell::Cell;
let executed = Cell::new(false);
debug_only!({
executed.set(true);
});
#[cfg(debug_assertions)]
assert!(executed.get());
#[cfg(not(debug_assertions))]
assert!(!executed.get());
}
#[test]
fn test_timed_with_named_function() {
use std::sync::atomic::{AtomicBool, Ordering};
static CALLED: AtomicBool = AtomicBool::new(false);
fn my_callback(_label: &str, _dur: Duration) {
CALLED.store(true, Ordering::SeqCst);
}
let result = timed!("named_fn_test", my_callback, { 123 });
assert_eq!(result, 123);
#[cfg(debug_assertions)]
assert!(CALLED.load(Ordering::SeqCst));
}
}