1use std::cell::RefCell;
9use std::collections::HashMap;
10use std::fmt::Debug;
11use std::sync::Arc;
12
13pub type ContextMap = HashMap<String, ContextValue>;
15
16#[derive(Clone, Debug, PartialEq)]
18pub enum ContextValue {
19 String(String),
20 Integer(i64),
21 Float(f64),
22 Bool(bool),
23 }
25
26impl std::fmt::Display for ContextValue {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 match self {
29 ContextValue::String(s) => write!(f, "{}", s),
30 ContextValue::Integer(i) => write!(f, "{}", i),
31 ContextValue::Float(fl) => write!(f, "{}", fl),
32 ContextValue::Bool(b) => write!(f, "{}", b),
33 }
34 }
35}
36
37thread_local! {
38 static CONTEXT_STACK: RefCell<Vec<ContextMap>> = const { RefCell::new(vec![]) };
39}
40
41pub fn push_context(ctx: ContextMap) {
43 CONTEXT_STACK.with(|stack| stack.borrow_mut().push(ctx));
44}
45
46pub fn pop_context() {
48 CONTEXT_STACK.with(|stack| {
49 stack.borrow_mut().pop();
50 });
51}
52
53pub fn current_context() -> ContextMap {
55 CONTEXT_STACK.with(|stack| {
56 let mut merged = ContextMap::new();
57 for ctx in stack.borrow().iter() {
58 for (k, v) in ctx.iter() {
59 merged.insert(k.clone(), v.clone());
60 }
61 }
62 merged
63 })
64}
65
66pub fn set_context_value(key: &str, value: ContextValue) {
68 CONTEXT_STACK.with(|stack| {
69 if let Some(top) = stack.borrow_mut().last_mut() {
70 top.insert(key.to_string(), value);
71 }
72 });
73}
74
75pub fn get_context_value(key: &str) -> Option<ContextValue> {
77 CONTEXT_STACK.with(|stack| {
78 for ctx in stack.borrow().iter().rev() {
79 if let Some(val) = ctx.get(key) {
80 return Some(val.clone());
81 }
82 }
83 None
84 })
85}
86
87pub fn has_context() -> bool {
89 CONTEXT_STACK.with(|stack| !stack.borrow().is_empty())
90}
91
92pub fn propagate_context_for_async() -> Arc<ContextMap> {
94 Arc::new(current_context())
95}
96
97pub fn set_context_from_arc(ctx: Arc<ContextMap>) {
98 push_context(ctx.as_ref().clone());
99}