moirai-pal 0.7.0

Platform Abstraction Layer for Moirai async I/O operations
Documentation
//! Reactor construction metrics and thread-local active-reactor restoration.

use super::super::core::IoReactor;
use std::sync::atomic::Ordering;

#[test]
fn test_reactor_metrics() {
    let reactor = IoReactor::new().unwrap();
    let metrics = reactor.metrics();
    assert_eq!(metrics.events_processed.load(Ordering::Relaxed), 0);
    assert_eq!(metrics.peak_fd_count.load(Ordering::Relaxed), 0);
}

#[test]
fn with_active_restores_thread_local_on_panic() {
    // Regression: if `f` panics, `with_active` must still restore the previous
    // thread-local reactor (via RAII), not leave a dangling pointer to the inner
    // reactor that a later `with_current` would dereference (use-after-free).
    let outer = IoReactor::new().expect("outer reactor");
    let inner = IoReactor::new().expect("inner reactor");

    outer.with_active(|| {
        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            inner.with_active(|| panic!("boom"));
        }));
        let payload = result.expect_err("inner closure must have panicked");
        assert_eq!(payload.downcast_ref::<&str>(), Some(&"boom"));

        // The active reactor must be restored to `outer`, never left as `inner`.
        let restored = IoReactor::with_current(|active| {
            active.is_some_and(|active| std::ptr::eq(active, &outer))
        });
        assert!(
            restored,
            "thread-local must be restored to the outer reactor after panic"
        );
    });
}