use std::sync::{Arc, Mutex};
use std::time::Instant;
use thag_profiler::warn_once;
static WARNING_COUNTER: Mutex<u32> = Mutex::new(0);
fn debug_log(msg: &str) {
println!("[LOG] {}", msg);
if msg.contains("This warning should only appear once") {
let mut counter = WARNING_COUNTER.lock().unwrap();
*counter += 1;
}
}
fn demo_simple_warning() {
println!("\n=== Simple Warning Suppression ===\n");
let condition = true;
println!("Calling function 5 times...");
for i in 1..=5 {
println!("\nCall #{}: ", i);
warn_once!(condition, || {
debug_log("This warning should only appear once");
});
println!("Function work completed");
}
let counter = *WARNING_COUNTER.lock().unwrap();
println!("\nWarning was logged {} time(s)", counter);
assert_eq!(counter, 1, "Warning should be logged exactly once");
}
fn demo_early_return() {
println!("\n=== Early Return Pattern ===\n");
*WARNING_COUNTER.lock().unwrap() = 0;
println!("Calling function 5 times...");
for i in 1..=5 {
println!("\nCall #{}: ", i);
let result = function_with_early_return();
println!("Result: {}", result);
}
let counter = *WARNING_COUNTER.lock().unwrap();
println!("\nWarning was logged {} time(s)", counter);
assert_eq!(counter, 1, "Warning should be logged exactly once");
}
fn function_with_early_return() -> &'static str {
let feature_disabled = true;
warn_once!(
feature_disabled,
|| {
debug_log("This warning should only appear once");
},
return "Feature disabled"
);
"Feature enabled"
}
fn demo_multiple_conditions() {
println!("\n=== Multiple Independent Warnings ===\n");
*WARNING_COUNTER.lock().unwrap() = 0;
let warning_counts = Arc::new(Mutex::new(vec![0, 0]));
println!("Calling two different warning conditions 5 times each...");
for i in 1..=5 {
println!("\nIteration #{}:", i);
let counts = warning_counts.clone();
warn_once!(true, || {
println!("[LOG] First warning - should appear once");
let mut counters = counts.lock().unwrap();
counters[0] += 1;
});
let counts = warning_counts.clone();
warn_once!(i % 3 == 0, || {
println!("[LOG] Second warning - should appear once when condition is met");
let mut counters = counts.lock().unwrap();
counters[1] += 1;
});
}
let counts = warning_counts.lock().unwrap();
println!("\nWarning #1 was logged {} time(s)", counts[0]);
println!("Warning #2 was logged {} time(s)", counts[1]);
assert_eq!(counts[0], 1, "First warning should be logged exactly once");
assert_eq!(counts[1], 1, "Second warning should be logged exactly once");
}
fn demo_performance() {
println!("\n=== Performance Comparison ===\n");
const ITERATIONS: u32 = 10_000_000;
println!("Running {} iterations", ITERATIONS);
let start = Instant::now();
{
use std::sync::atomic::{AtomicBool, Ordering};
static WARNING_SHOWN: AtomicBool = AtomicBool::new(false);
for _ in 0..ITERATIONS {
if !WARNING_SHOWN.load(Ordering::Relaxed) {
if !WARNING_SHOWN.swap(true, Ordering::Relaxed) {
}
}
}
}
let naive_time = start.elapsed();
let start = Instant::now();
{
for _ in 0..ITERATIONS {
warn_once!(true, || {
});
}
}
let warn_once_time = start.elapsed();
println!("Naive approach time: {:?}", naive_time);
println!("warn_once time: {:?}", warn_once_time);
println!(
"Speedup: {:.2}x",
naive_time.as_nanos() as f64 / warn_once_time.as_nanos() as f64
);
}
fn demo_record_dealloc_conversion() {
println!("\n=== Real-world Example: record_dealloc ===\n");
println!("Before: Complex nested if-statements with duplicate code:");
println!("```rust");
println!("fn record_dealloc(address: usize, size: usize) {{");
println!(" // [recursion prevention code omitted for brevity]");
println!(" let is_mem_prof = lazy_static_var!(bool,");
println!(" get_global_profile_type() == ProfileType::Memory || profile_type == ProfileType::Both,");
println!(" );");
println!(" if !is_mem_prof {{");
println!(" // Fast path check - no synchronization overhead after first warning");
println!(" if unsafe {{ WARNED }} {{");
println!(" return;");
println!(" }}");
println!(" ");
println!(
" // Slow path with proper synchronization - only hit by the first few threads"
);
println!(
" if !WARNED_ABOUT_SKIPPING.swap(true, std::sync::atomic::Ordering::Relaxed) {{"
);
println!(" debug_log!(");
println!(" \"Skipping deallocation recording because profile_type={{:?}}\",");
println!(" profile_type");
println!(" );");
println!(" // Update fast path flag for future calls");
println!(" unsafe {{ WARNED = true; }}");
println!(" }}");
println!(" return;");
println!(" }}");
println!(" // [rest of function omitted for brevity]");
println!("}}");
println!("```");
println!("\nAfter: Using warn_once! macro:");
println!("```rust");
println!("fn record_dealloc(address: usize, size: usize) {{");
println!(" // [recursion prevention code omitted for brevity]");
println!(" let is_mem_prof = lazy_static_var!(bool,");
println!(" get_global_profile_type() == ProfileType::Memory || profile_type == ProfileType::Both,");
println!(" );");
println!(" // Use warn_once! macro for clean, optimized warning suppression");
println!(" warn_once!(!is_mem_prof, || {{");
println!(" debug_log!(");
println!(" \"Skipping deallocation recording because profile_type={{:?}}\",");
println!(" profile_type");
println!(" );");
println!(" }}, return);");
println!(" // [rest of function omitted for brevity]");
println!("}}");
println!("```");
println!("\nBenefits:\n");
println!("1. Code is more readable and maintainable");
println!("2. Pattern is abstracted for reuse across the codebase");
println!("3. Same ultra-low overhead fast path");
println!("4. Thread-safety preserved");
println!("5. Eliminates possibility of coding errors in the pattern");
}
fn main() {
println!("Demonstrating the warn_once pattern");
println!("====================================\n");
demo_simple_warning();
demo_early_return();
demo_multiple_conditions();
demo_performance();
demo_record_dealloc_conversion();
println!("\n=== warn_once Implementation ===\n");
println!("```rust");
println!("macro_rules! warn_once {{");
println!(" ($condition:expr, $warning_fn:expr) => {{{{");
println!(" // Fast path using non-atomic bool for zero overhead after first warning");
println!(" static mut WARNED: bool = false;");
println!(" // Thread-safe initialization using atomic");
println!(" static WARNED_ABOUT_SKIPPING: std::sync::atomic::AtomicBool =");
println!(" std::sync::atomic::AtomicBool::new(false);");
println!(" if $condition {{");
println!(" // Fast path check - no synchronization overhead after first warning");
println!(" if unsafe {{ WARNED }} {{");
println!(" // Skip - already warned");
println!(" }} else {{");
println!(" // Slow path with proper synchronization - only hit once");
println!(" if !WARNED_ABOUT_SKIPPING.swap(true, std::sync::atomic::Ordering::Relaxed) {{");
println!(" // Execute the warning function");
println!(" $warning_fn();");
println!(" // Update fast path flag for future calls");
println!(" unsafe {{ WARNED = true; }}");
println!(" }}");
println!(" }}");
println!(" true // Return true if condition was met");
println!(" }} else {{");
println!(" false // Return false if condition was not met");
println!(" }}");
println!(" }}}};");
println!("}}");
println!("```");
}