use std::cell::RefCell;
use std::sync::Arc;
thread_local! {
static ACTIVE_AUTH_CONTEXT_STACK: RefCell<Vec<Arc<serde_json::Value>>> =
const { RefCell::new(Vec::new()) };
}
#[must_use = "dropping the guard immediately pops the auth-context scope"]
pub struct AuthContextScopeGuard {
_private: (),
}
impl Drop for AuthContextScopeGuard {
fn drop(&mut self) {
ACTIVE_AUTH_CONTEXT_STACK.with(|stack| {
stack.borrow_mut().pop();
});
}
}
pub fn enter_auth_context(context: serde_json::Value) -> AuthContextScopeGuard {
ACTIVE_AUTH_CONTEXT_STACK.with(|stack| stack.borrow_mut().push(Arc::new(context)));
AuthContextScopeGuard { _private: () }
}
pub fn current_auth_context() -> Option<Arc<serde_json::Value>> {
ACTIVE_AUTH_CONTEXT_STACK.with(|stack| stack.borrow().last().cloned())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nested_scopes_shadow_and_restore() {
assert!(current_auth_context().is_none());
let outer = enter_auth_context(serde_json::json!({"who": "outer"}));
assert_eq!(
current_auth_context().as_deref(),
Some(&serde_json::json!({"who": "outer"}))
);
{
let _inner = enter_auth_context(serde_json::json!({"who": "inner"}));
assert_eq!(
current_auth_context().as_deref(),
Some(&serde_json::json!({"who": "inner"}))
);
}
assert_eq!(
current_auth_context().as_deref(),
Some(&serde_json::json!({"who": "outer"}))
);
drop(outer);
assert!(current_auth_context().is_none());
}
}