use serde::{Deserialize, Serialize};
use crate::checkpoint::NodeId;
#[derive(Debug, Clone)]
pub struct TraceStep<E> {
pub step: usize,
pub node_id: NodeId,
pub mutations: Vec<E>,
}
#[derive(Debug, Clone, Default)]
pub struct ExecutionTrace<E> {
pub steps: Vec<TraceStep<E>>,
}
impl<E> ExecutionTrace<E> {
pub fn new() -> Self {
Self { steps: Vec::new() }
}
pub fn push(&mut self, step: TraceStep<E>) {
self.steps.push(step);
}
pub fn len(&self) -> usize {
self.steps.len()
}
pub fn is_empty(&self) -> bool {
self.steps.is_empty()
}
}
pub trait TraceSink<E>: Send + Sync {
fn record_step(&mut self, step: TraceStep<E>);
}
#[derive(Debug)]
pub struct MemoryTraceSink<E: Send + Sync> {
pub trace: ExecutionTrace<E>,
}
impl<E: Send + Sync> Default for MemoryTraceSink<E> {
fn default() -> Self {
Self {
trace: ExecutionTrace::new(),
}
}
}
impl<E: Send + Sync> MemoryTraceSink<E> {
pub fn new() -> Self {
Self::default()
}
pub fn into_trace(self) -> ExecutionTrace<E> {
self.trace
}
}
impl<E: Send + Sync> TraceSink<E> for MemoryTraceSink<E> {
fn record_step(&mut self, step: TraceStep<E>) {
self.trace.push(step);
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExportedTrace {
pub steps: Vec<ExportedTraceStep>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExportedTraceStep {
pub step: usize,
pub node_id: String,
pub mutations: Vec<serde_json::Value>,
}
impl<E: Serialize> ExecutionTrace<E> {
pub fn export(&self) -> ExportedTrace {
ExportedTrace {
steps: self
.steps
.iter()
.map(|s| ExportedTraceStep {
step: s.step,
node_id: s.node_id.0.clone(),
mutations: s
.mutations
.iter()
.filter_map(|e| serde_json::to_value(e).ok())
.collect(),
})
.collect(),
}
}
}