use crate::prelude::*;
#[cfg(feature = "std")]
use core::cell::RefCell;
use rustc_hash::FxHashMap;
#[cfg(feature = "std")]
use crate::value::Value;
#[cfg(feature = "std")]
#[derive(Debug, Clone)]
pub(crate) enum SpanTree {
Leaf(usize, usize),
Sequence {
start: usize,
end: usize,
items: Vec<SpanTree>,
},
Mapping {
start: usize,
end: usize,
entries: Vec<((usize, usize), SpanTree)>,
},
}
#[derive(Debug)]
pub struct SpanContext {
pub spans: FxHashMap<usize, (usize, usize)>,
pub source: Arc<str>,
}
#[cfg(feature = "std")]
mod tls {
use super::{RefCell, SpanContext};
thread_local! {
pub(super) static SPAN_CONTEXT: RefCell<Option<SpanContext>> = const { RefCell::new(None) };
}
}
#[cfg(feature = "std")]
pub(crate) struct SpanContextGuard {
ctx: SpanContext,
}
#[cfg(feature = "std")]
impl SpanContextGuard {
pub(crate) fn as_ref(&self) -> &SpanContext {
&self.ctx
}
}
#[cfg(feature = "std")]
impl Drop for SpanContextGuard {
fn drop(&mut self) {
tls::SPAN_CONTEXT.with(|cell| {
*cell.borrow_mut() = None;
});
}
}
#[cfg(feature = "std")]
pub(crate) fn set_span_context(ctx: SpanContext) -> SpanContextGuard {
let thread_local_ctx = SpanContext {
spans: FxHashMap::default(),
source: Arc::clone(&ctx.source),
};
tls::SPAN_CONTEXT.with(|cell| {
*cell.borrow_mut() = Some(thread_local_ctx);
});
SpanContextGuard { ctx }
}
#[cfg(feature = "std")]
pub(crate) fn build_span_map(value: &Value, tree: &SpanTree) -> FxHashMap<usize, (usize, usize)> {
let mut map = FxHashMap::default();
walk(value, tree, &mut map);
map
}
#[cfg(feature = "std")]
fn walk(value: &Value, tree: &SpanTree, map: &mut FxHashMap<usize, (usize, usize)>) {
let p: *const Value = value;
let ptr = p as usize;
match tree {
SpanTree::Leaf(start, end) => {
let _ = map.insert(ptr, (*start, *end));
}
SpanTree::Sequence { start, end, items } => {
let _ = map.insert(ptr, (*start, *end));
if let Value::Sequence(seq) = value {
for (v, t) in seq.iter().zip(items.iter()) {
walk(v, t, map);
}
}
}
SpanTree::Mapping {
start,
end,
entries,
} => {
let _ = map.insert(ptr, (*start, *end));
if let Value::Mapping(mapping) = value {
for ((_, v), (_, vt)) in mapping.iter().zip(entries.iter()) {
walk(v, vt, map);
}
}
}
}
}