1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use std::cell::RefCell;
use std::collections::HashSet;
pub(crate) use tracing_core::span::Id;
struct ContextId {
id: Id,
duplicate: bool,
}
pub(crate) struct SpanStack {
stack: Vec<ContextId>,
ids: HashSet<Id>,
}
impl SpanStack {
pub(crate) fn new() -> Self {
SpanStack {
stack: vec![],
ids: HashSet::new(),
}
}
pub(crate) fn push(&mut self, id: Id) {
let duplicate = self.ids.contains(&id);
if !duplicate {
self.ids.insert(id.clone());
}
self.stack.push(ContextId { id, duplicate })
}
pub(crate) fn pop(&mut self, expected_id: &Id) -> Option<Id> {
if let Some((idx, _)) = self
.stack
.iter()
.enumerate()
.rev()
.find(|(_, ctx_id)| ctx_id.id == *expected_id)
{
let ContextId { id, duplicate } = self.stack.remove(idx);
if !duplicate {
self.ids.remove(&id);
}
Some(id)
} else {
None
}
}
#[inline]
pub(crate) fn current(&self) -> Option<&Id> {
self.stack
.iter()
.rev()
.find(|context_id| !context_id.duplicate)
.map(|context_id| &context_id.id)
}
}
thread_local! {
static CONTEXT: RefCell<SpanStack> = RefCell::new(SpanStack::new());
}
#[cfg(test)]
mod tests {
use super::{Id, SpanStack};
#[test]
fn pop_last_span() {
let mut stack = SpanStack::new();
let id = Id::from_u64(1);
stack.push(id.clone());
assert_eq!(Some(id.clone()), stack.pop(&id));
}
#[test]
fn pop_first_span() {
let mut stack = SpanStack::new();
stack.push(Id::from_u64(1));
stack.push(Id::from_u64(2));
let id = Id::from_u64(1);
assert_eq!(Some(id.clone()), stack.pop(&id));
}
}