use std::cell::RefCell;
use uuid::Uuid;
tokio::task_local! {
static SPAN_STACK: RefCell<Vec<Uuid>>;
}
pub fn push(run_id: Uuid) {
let _ = SPAN_STACK.try_with(|s| s.borrow_mut().push(run_id));
}
pub fn pop(expected: Uuid) {
let _ = SPAN_STACK.try_with(|s| {
let mut v = s.borrow_mut();
if v.last().copied() == Some(expected) {
v.pop();
}
});
}
pub fn peek() -> Option<Uuid> {
SPAN_STACK
.try_with(|s| s.borrow().last().copied())
.ok()
.flatten()
}
pub async fn scope<F, T>(f: F) -> T
where
F: std::future::Future<Output = T>,
{
SPAN_STACK.scope(RefCell::new(Vec::new()), f).await
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn peek_outside_scope_is_none() {
assert_eq!(peek(), None);
}
#[tokio::test]
async fn push_pop_within_scope() {
scope(async {
assert_eq!(peek(), None);
let a = Uuid::new_v4();
push(a);
assert_eq!(peek(), Some(a));
let b = Uuid::new_v4();
push(b);
assert_eq!(peek(), Some(b));
pop(b);
assert_eq!(peek(), Some(a));
pop(a);
assert_eq!(peek(), None);
})
.await;
}
#[tokio::test]
async fn pop_only_when_top_matches() {
scope(async {
let a = Uuid::new_v4();
let b = Uuid::new_v4();
push(a);
pop(b); assert_eq!(peek(), Some(a));
pop(a);
assert_eq!(peek(), None);
})
.await;
}
}