no-block-pls 0.1.0

Instrument async Rust code to surface blocking work between await points
Documentation
#[cfg(test)]
mod loop_wraparound_tests {
    use crate::inject_guard_module;

    #[test]
    fn test_loop_wraparound_detection() {
        let source = r#"
async fn process_items(&self, items: Vec<Item>) -> Result<()> {
    let mut remaining = items;

    while let Some(item) = remaining.pop() {
        // Line 6: First await in the loop
        let data = fetch_data(item).await;

        // Lines 9-11: Synchronous work
        let processed = expensive_computation(data);
        println!("Processed: {:?}", processed);
        validate(&processed)?;

        // Line 14: Second await in the loop
        save_result(processed).await?;

        // Lines 17-19: More synchronous work after last await
        // This section will show wraparound when loop continues
        do_cleanup();
        log_metrics();
        update_cache();
    }

    Ok(())
}
"#;

        let result = inject_guard_module(source, 10).unwrap();

        // Verify the guard module is injected
        assert!(result.contains("mod __async_profile_guard__"));

        // Verify the wraparound detection logic is present
        assert!(result.contains("let wraparound = to_line < self.from_line;"));
        assert!(result.contains("loop wraparound"));

        // Verify the instrumentation points are added
        assert!(result.contains("__guard.end_section("));
        assert!(result.contains("__guard.start_section("));
        assert!(result.contains("__guard.checkpoint("));
        assert!(!result.contains("line!()"));

        // The instrumented code should have:
        // 1. Guard creation at function start
        // 2. end_section/start_section around each await
        // 3. The synchronous code between awaits will be timed

        println!("Instrumented code:\n{}", result);
    }

    #[test]
    fn test_nested_loops_with_awaits() {
        let source = r#"
async fn nested_loops(&self) -> Result<()> {
    for i in 0..10 {
        println!("Outer loop: {}", i);

        for j in 0..5 {
            // Inner loop await
            let data = fetch(i, j).await;
            process(data);
        }

        // Outer loop await
        checkpoint(i).await?;
    }
    Ok(())
}
"#;

        let result = inject_guard_module(source, 10).unwrap();

        // Both loops should be instrumented
        assert!(result.contains("__guard"));

        // Should handle nested loop wraparounds correctly
        println!("Nested loops instrumented:\n{}", result);
    }

    #[test]
    fn test_loop_with_early_continue() {
        let source = r#"
async fn loop_with_continue(&self, items: Vec<Item>) -> Result<()> {
    for item in items {
        let data = fetch(item).await;

        if !data.is_valid() {
            // Early continue - timing should still work
            continue;
        }

        let processed = heavy_processing(data);
        save(processed).await?;

        // Work after last await
        cleanup();
    }
    Ok(())
}
"#;

        let result = inject_guard_module(source, 10).unwrap();
        assert!(result.contains("__guard"));
        assert!(result.contains("__guard.end_section("));
        assert!(result.contains("__guard.start_section("));
        assert!(result.contains("continue;"));
        assert!(!result.contains("line!()"));

        println!("Loop with continue instrumented:\n{}", result);
    }
}