use std::sync::Arc;
use crate::WideEvent;
tokio::task_local! {
static CURRENT: Arc<WideEvent>;
}
#[must_use]
pub fn current() -> Option<Arc<WideEvent>> {
CURRENT.try_with(Clone::clone).ok()
}
pub async fn scope<F: std::future::Future>(subsystem: &'static str, f: F) -> F::Output {
scope_with(Arc::new(WideEvent::new(subsystem)), f).await
}
pub async fn scope_with<F: std::future::Future>(event: Arc<WideEvent>, f: F) -> F::Output {
let emit_ref = event.clone();
let result = CURRENT.scope(event, f).await;
emit_ref.emit();
result
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicBool, Ordering};
#[tokio::test]
async fn scope_emits_on_completion() {
let emitted = Arc::new(AtomicBool::new(false));
let emitted_clone = emitted.clone();
scope("test", async {
let evt = current().unwrap();
evt.set_str("key", "value");
evt.set_emit_hook(Arc::new(move |fields| {
emitted_clone.store(true, Ordering::SeqCst);
assert!(fields.contains_key("key"));
}));
})
.await;
assert!(emitted.load(Ordering::SeqCst));
}
#[tokio::test]
async fn current_returns_none_outside_scope() {
assert!(current().is_none());
}
#[tokio::test]
async fn manual_emit_prevents_double() {
let count = Arc::new(std::sync::atomic::AtomicU32::new(0));
let count_clone = count.clone();
scope("test", async {
let evt = current().unwrap();
evt.set_emit_hook(Arc::new(move |_| {
count_clone.fetch_add(1, Ordering::SeqCst);
}));
evt.emit(); })
.await;
assert_eq!(count.load(Ordering::SeqCst), 1);
}
}