pub const RERUN_SESSION_TRACESTATE_KEY: &str = "rerun_session_id";
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct RerunTracingSessionId(String);
impl RerunTracingSessionId {
pub fn parse(s: &str) -> Option<Self> {
let rest = s.strip_prefix("rs_")?;
if rest.len() == 8
&& rest
.bytes()
.all(|b| b.is_ascii_digit() || (b'a'..=b'f').contains(&b))
{
Some(Self(s.to_owned()))
} else {
None
}
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for RerunTracingSessionId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
impl From<RerunTracingSessionId> for String {
fn from(id: RerunTracingSessionId) -> Self {
id.0
}
}
static ACTIVE_TRACING_SESSION_COUNT: std::sync::atomic::AtomicUsize =
std::sync::atomic::AtomicUsize::new(0);
pub fn inc_active_tracing_session_count() {
ACTIVE_TRACING_SESSION_COUNT.fetch_add(1, std::sync::atomic::Ordering::Release);
}
pub fn dec_active_tracing_session_count() {
ACTIVE_TRACING_SESSION_COUNT.fetch_sub(1, std::sync::atomic::Ordering::Release);
}
tokio::task_local! {
static CURRENT_TRACING_SESSION_ID: Option<RerunTracingSessionId>;
}
#[must_use]
pub fn with_current_tracing_session<F>(
f: F,
) -> tokio::task::futures::TaskLocalFuture<Option<RerunTracingSessionId>, F>
where
F: std::future::Future,
{
let sid = read_current_tracing_session_id_at_boundary();
CURRENT_TRACING_SESSION_ID.scope(sid, f)
}
fn read_current_tracing_session_id_at_boundary() -> Option<RerunTracingSessionId> {
if ACTIVE_TRACING_SESSION_COUNT.load(std::sync::atomic::Ordering::Acquire) == 0 {
return None;
}
read_current_tracing_session_id_via_pyo3()
}
pub fn current_rerun_session_id() -> Option<RerunTracingSessionId> {
if ACTIVE_TRACING_SESSION_COUNT.load(std::sync::atomic::Ordering::Acquire) == 0 {
return None;
}
if let Ok(opt) = CURRENT_TRACING_SESSION_ID.try_with(|sid| sid.clone()) {
return opt;
}
read_current_tracing_session_id_via_pyo3()
}
#[cfg(all(feature = "pyo3", not(test)))]
fn read_current_tracing_session_id_via_pyo3() -> Option<RerunTracingSessionId> {
pyo3::Python::attach(crate::python_bridge::current_rerun_session_id_from_contextvar)
}
#[cfg(any(not(feature = "pyo3"), test))]
fn read_current_tracing_session_id_via_pyo3() -> Option<RerunTracingSessionId> {
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rejects_malformed_ids() {
assert!(RerunTracingSessionId::parse("").is_none());
assert!(RerunTracingSessionId::parse("rs_").is_none());
assert!(RerunTracingSessionId::parse("rs_cafebab").is_none()); assert!(RerunTracingSessionId::parse("rs_cafebabe1").is_none()); assert!(RerunTracingSessionId::parse("rs_CAFEBABE").is_none()); assert!(RerunTracingSessionId::parse("rs_cafebabz").is_none()); assert!(RerunTracingSessionId::parse("xx_cafebabe").is_none()); assert!(RerunTracingSessionId::parse("cafebabe").is_none()); }
#[test]
fn accepts_well_formed_id() {
assert_eq!(
RerunTracingSessionId::parse("rs_cafebabe")
.unwrap()
.as_str(),
"rs_cafebabe",
);
assert!(RerunTracingSessionId::parse("rs_00000000").is_some());
assert!(RerunTracingSessionId::parse("rs_ffffffff").is_some());
assert!(RerunTracingSessionId::parse("rs_0123abcd").is_some());
}
#[test]
fn gate_inc_dec_round_trips() {
use std::sync::atomic::Ordering;
assert_eq!(ACTIVE_TRACING_SESSION_COUNT.load(Ordering::Acquire), 0);
inc_active_tracing_session_count();
assert_eq!(ACTIVE_TRACING_SESSION_COUNT.load(Ordering::Acquire), 1);
dec_active_tracing_session_count();
assert_eq!(ACTIVE_TRACING_SESSION_COUNT.load(Ordering::Acquire), 0);
}
}