use std::sync::Arc;
use super::debug_gate::DebugGate;
pub async fn run<F, R>(label: &'static str, f: F) -> Option<R>
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
match tokio::task::spawn_blocking(f).await {
Ok(r) => Some(r),
Err(e) => {
tracing::warn!("{label} panicked: {e}");
None
}
}
}
pub async fn run_gated<F, R>(gate: &Arc<DebugGate>, section: &'static str, f: F) -> Option<R>
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
let gate = Arc::clone(gate);
run(section, move || {
gate.pass(section);
f()
})
.await
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn returns_value_when_no_panic() {
let r = run("test", || 42).await;
assert_eq!(r, Some(42));
}
#[tokio::test]
async fn returns_none_on_panic() {
let r: Option<i32> = run("test", || panic!("boom")).await;
assert_eq!(r, None);
}
#[tokio::test]
async fn gated_returns_value_when_no_panic() {
let gate = Arc::new(DebugGate::default());
let r = run_gated(&gate, "sec", || 7).await;
assert_eq!(r, Some(7));
}
#[tokio::test]
async fn gated_returns_none_on_panic() {
let gate = Arc::new(DebugGate::default());
let r: Option<i32> = run_gated(&gate, "sec", || panic!("boom")).await;
assert_eq!(r, None);
}
}