use std::marker::PhantomData;
#[derive(Debug, Clone, Copy)]
pub struct ReplayAuthority {
_phantom: PhantomData<()>,
}
impl ReplayAuthority {
pub const fn new() -> Self {
ReplayAuthority {
_phantom: PhantomData,
}
}
pub const fn witness_key() -> &'static str {
"wasm4pm-replay"
}
}
impl Default for ReplayAuthority {
fn default() -> Self {
Self::new()
}
}
pub trait ReplayEngine<M> {
fn replay(&self, _model: &M, log_events: &[LogEvent]) -> ReplayTrace;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LogEvent {
pub activity: String,
pub timestamp: u64,
pub case_id: Option<String>,
}
impl LogEvent {
pub fn new(activity: String, timestamp: u64) -> Self {
LogEvent {
activity,
timestamp,
case_id: None,
}
}
pub fn with_case_id(mut self, case_id: String) -> Self {
self.case_id = Some(case_id);
self
}
}
#[derive(Debug, Clone)]
pub struct ReplayTrace {
pub transitions: Vec<String>,
pub successful_steps: usize,
pub missed_activities: usize,
pub remaining_tokens: usize,
pub log: Vec<String>,
}
impl ReplayTrace {
pub fn new() -> Self {
ReplayTrace {
transitions: Vec::new(),
successful_steps: 0,
missed_activities: 0,
remaining_tokens: 0,
log: Vec::new(),
}
}
pub fn is_successful(&self) -> bool {
self.missed_activities == 0 && self.remaining_tokens == 0
}
pub fn fire_transition(&mut self, transition: String) {
self.transitions.push(transition);
self.successful_steps += 1;
}
pub fn miss_activity(&mut self, activity: String) {
self.missed_activities += 1;
self.log.push(format!("Missed activity: {}", activity));
}
}
impl Default for ReplayTrace {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn replay_authority_construction() {
let _auth = ReplayAuthority::new();
assert_eq!(ReplayAuthority::witness_key(), "wasm4pm-replay");
}
#[test]
fn replay_authority_default() {
let _auth = ReplayAuthority::default();
assert_eq!(ReplayAuthority::witness_key(), "wasm4pm-replay");
}
#[test]
fn log_event_creation() {
let event = LogEvent::new("submit".to_string(), 1000);
assert_eq!(event.activity, "submit");
assert_eq!(event.timestamp, 1000);
assert_eq!(event.case_id, None);
}
#[test]
fn log_event_with_case_id() {
let event = LogEvent::new("submit".to_string(), 1000).with_case_id("case-001".to_string());
assert_eq!(event.case_id, Some("case-001".to_string()));
}
#[test]
fn replay_trace_creation() {
let trace = ReplayTrace::new();
assert!(trace.is_successful());
assert_eq!(trace.successful_steps, 0);
}
#[test]
fn replay_trace_with_deviation() {
let mut trace = ReplayTrace::new();
trace.fire_transition("t1".to_string());
trace.miss_activity("submit".to_string());
assert!(!trace.is_successful());
assert_eq!(trace.successful_steps, 1);
assert_eq!(trace.missed_activities, 1);
}
#[test]
fn replay_trace_default() {
let trace = ReplayTrace::default();
assert!(trace.is_successful());
assert_eq!(trace.missed_activities, 0);
assert_eq!(trace.remaining_tokens, 0);
}
}