use std::collections::HashMap; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Arc, Mutex}; use swactor::actor::ActorAddress; use crate::state::VersionedValue; // ── Shared handles ─────────────────────────────────────────────────────── /// Shared, append-only event log. pub type EventLog = Arc>>; /// Shared tick counter — the simulation harness increments this. pub type TickCounter = Arc; /// Maps actor addresses to human-readable names like `"node-0"`. pub type NameRegistry = Arc>>; // ── Event types ────────────────────────────────────────────────────────── #[derive(Debug, Clone)] pub struct GossipEvent { pub tick: u64, pub node_name: String, pub node_addr: ActorAddress, pub kind: GossipEventKind, } #[derive(Debug, Clone)] pub enum GossipEventKind { /// A local `Set { key, .. }` was processed. LocalSet { key: String }, /// `DoGossipRound` chose a peer and sent a Push. GossipRoundStarted { target_name: String }, /// `DoGossipRound` had no peers. GossipRoundNoPeers, /// Received a Push from another node. PushReceived { from_name: String, keys_updated: usize, }, /// Received a Query. QueryReceived { key: String }, /// A peer was added. PeerAdded { peer_name: String }, /// A peer was removed. PeerRemoved { peer_name: String }, /// Full state snapshot (requested via `TakeSnapshot`). StateSnapshot { snapshot: NodeSnapshot }, } #[derive(Debug, Clone)] pub struct NodeSnapshot { pub entries: HashMap, pub peer_count: usize, } // ── Simulation trace (complete run output) ─────────────────────────────── #[derive(Debug, Clone)] pub struct SimulationTrace { pub name: String, pub node_names: Vec, pub node_addrs: Vec, pub topology_edges: Vec<(String, String)>, pub events: Vec, pub snapshots_per_round: Vec>, pub num_rounds: usize, pub total_keys: usize, } // ── Helpers ────────────────────────────────────────────────────────────── pub fn current_tick(counter: &TickCounter) -> u64 { counter.load(Ordering::Relaxed) } pub fn resolve_name(registry: &NameRegistry, addr: ActorAddress) -> String { registry .lock() .unwrap() .get(&addr) .cloned() .unwrap_or_else(|| format!("{:?}", &addr.0[..4])) } pub fn record_event(log: &EventLog, event: GossipEvent) { log.lock().unwrap().push(event); }