1use serde::{Deserialize, Serialize};
10
11use crate::checkpoint::NodeId;
12
13#[derive(Debug, Clone)]
17pub struct TraceStep<E> {
18 pub step: usize,
20 pub node_id: NodeId,
22 pub mutations: Vec<E>,
24}
25
26#[derive(Debug, Clone, Default)]
32pub struct ExecutionTrace<E> {
33 pub steps: Vec<TraceStep<E>>,
34}
35
36impl<E> ExecutionTrace<E> {
37 pub fn new() -> Self {
38 Self { steps: Vec::new() }
39 }
40
41 pub fn push(&mut self, step: TraceStep<E>) {
42 self.steps.push(step);
43 }
44
45 pub fn len(&self) -> usize {
46 self.steps.len()
47 }
48
49 pub fn is_empty(&self) -> bool {
50 self.steps.is_empty()
51 }
52}
53
54pub trait TraceSink<E>: Send + Sync {
61 fn record_step(&mut self, step: TraceStep<E>);
63}
64
65#[derive(Debug)]
67pub struct MemoryTraceSink<E: Send + Sync> {
68 pub trace: ExecutionTrace<E>,
69}
70
71impl<E: Send + Sync> Default for MemoryTraceSink<E> {
72 fn default() -> Self {
73 Self {
74 trace: ExecutionTrace::new(),
75 }
76 }
77}
78
79impl<E: Send + Sync> MemoryTraceSink<E> {
80 pub fn new() -> Self {
81 Self::default()
82 }
83
84 pub fn into_trace(self) -> ExecutionTrace<E> {
85 self.trace
86 }
87}
88
89impl<E: Send + Sync> TraceSink<E> for MemoryTraceSink<E> {
90 fn record_step(&mut self, step: TraceStep<E>) {
91 self.trace.push(step);
92 }
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct ExportedTrace {
102 pub steps: Vec<ExportedTraceStep>,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct ExportedTraceStep {
107 pub step: usize,
108 pub node_id: String,
109 pub mutations: Vec<serde_json::Value>,
110}
111
112impl<E: Serialize> ExecutionTrace<E> {
113 pub fn export(&self) -> ExportedTrace {
115 ExportedTrace {
116 steps: self
117 .steps
118 .iter()
119 .map(|s| ExportedTraceStep {
120 step: s.step,
121 node_id: s.node_id.0.clone(),
122 mutations: s
123 .mutations
124 .iter()
125 .filter_map(|e| serde_json::to_value(e).ok())
126 .collect(),
127 })
128 .collect(),
129 }
130 }
131}