use std::{
borrow::Borrow,
cell::{Ref, RefCell},
fmt::Display,
sync::Mutex,
};
pub use libcrux_macros::trace_span;
pub trait Trace: Sized {
type Label: Clone;
type TimeStamp: TimeStamp;
fn emit(&self, ev: TraceEvent<Self::Label, Self::TimeStamp>);
fn report(self) -> Vec<TraceEvent<Self::Label, Self::TimeStamp>>;
fn emit_span(&self, label: Self::Label) -> SpanHandle<Self> {
let event = TraceEvent {
ty: EventType::SpanOpen,
at: Self::TimeStamp::now(),
label: label.clone(),
};
self.emit(event);
SpanHandle {
trace: self,
label: Some(label),
}
}
fn emit_on_the_fly(&self, label: Self::Label) {
let event = TraceEvent {
ty: EventType::OnTheFly,
at: Self::TimeStamp::now(),
label: label.clone(),
};
self.emit(event);
}
}
pub trait TimeStamp {
fn now() -> Self;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EventType {
SpanOpen,
SpanClose,
OnTheFly,
}
#[derive(Debug, Clone)]
pub struct TraceEvent<Label, TimeStamp> {
pub ty: EventType,
pub at: TimeStamp,
pub label: Label,
}
impl<Label: Display, TimeStamp: Display> Display for TraceEvent<Label, TimeStamp> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { ty, at, label } = self;
write!(f, "{ty:?}: {label}@{at}")
}
}
pub struct SpanHandle<'a, T: Trace> {
trace: &'a T,
label: Option<T::Label>,
}
impl<'a, T: Trace> Drop for SpanHandle<'a, T> {
fn drop(&mut self) {
let event = TraceEvent {
ty: EventType::SpanClose,
at: T::TimeStamp::now(),
label: self.label.take().unwrap(),
};
self.trace.emit(event)
}
}
#[derive(Debug)]
pub struct MutexTrace<Label, TimeStamp>(Mutex<Vec<TraceEvent<Label, TimeStamp>>>);
impl<Label: Clone, TS: TimeStamp> Trace for MutexTrace<Label, TS> {
type Label = Label;
type TimeStamp = TS;
fn emit(&self, ev: TraceEvent<Self::Label, Self::TimeStamp>) {
self.0.lock().unwrap().push(ev)
}
fn report(self) -> Vec<TraceEvent<Self::Label, Self::TimeStamp>> {
self.0.into_inner().unwrap()
}
}
impl<Label: Clone, TS: TimeStamp> Default for MutexTrace<Label, TS> {
fn default() -> Self {
Self(Default::default())
}
}
impl<Label: Clone, TS: TimeStamp + Clone> Clone for MutexTrace<Label, TS> {
fn clone(&self) -> Self {
let guard = self.0.lock().unwrap();
let vector: &Vec<_> = guard.borrow();
Self(Mutex::new(vector.clone()))
}
}
#[derive(Debug)]
pub struct RefCellTrace<Label, TimeStamp>(RefCell<Vec<TraceEvent<Label, TimeStamp>>>);
impl<Label: Clone, TS: TimeStamp> Trace for RefCellTrace<Label, TS> {
type Label = Label;
type TimeStamp = TS;
fn emit(&self, ev: TraceEvent<Self::Label, Self::TimeStamp>) {
self.0.borrow_mut().push(ev);
}
fn report(self) -> Vec<TraceEvent<Self::Label, Self::TimeStamp>> {
self.0.into_inner()
}
}
impl<Label: Clone, TS: TimeStamp> RefCellTrace<Label, TS> {
pub fn entries(&self) -> Ref<'_, [TraceEvent<Label, TS>]> {
Ref::map(self.0.borrow(), Vec::as_slice)
}
}
impl<Label: Clone, TS: TimeStamp> Default for RefCellTrace<Label, TS> {
fn default() -> Self {
Self(Default::default())
}
}
impl<Label: Clone, TS: TimeStamp + Clone> Clone for RefCellTrace<Label, TS> {
fn clone(&self) -> Self {
let vector = self.0.borrow().as_slice().to_vec();
Self(RefCell::new(vector))
}
}
impl TimeStamp for std::time::Instant {
fn now() -> Self {
Self::now()
}
}