whycodes_session/
stream_rules.rs1use std::collections::BTreeMap;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
9pub struct StreamRuleLedger {
10 #[serde(default)]
12 pub turn: u64,
13 #[serde(default)]
15 pub fired: BTreeMap<String, u64>,
16}
17
18impl StreamRuleLedger {
19 pub fn is_empty(&self) -> bool {
21 self.fired.is_empty()
22 }
23
24 pub fn begin_turn(&mut self) {
26 self.turn = self.turn.saturating_add(1);
27 }
28
29 pub fn last_fired(&self, name: &str) -> Option<u64> {
31 self.fired.get(name).copied()
32 }
33
34 pub fn record(&mut self, name: &str) {
36 self.fired.insert(name.to_string(), self.turn);
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 #[test]
45 fn ledger_tracks_turns_and_hits() {
46 let mut l = StreamRuleLedger::default();
47 assert!(l.is_empty());
48 l.begin_turn();
49 l.begin_turn();
50 assert_eq!(l.last_fired("a"), None);
51 l.record("a");
52 assert!(!l.is_empty());
53 assert_eq!(l.last_fired("a"), Some(2));
54 let back: StreamRuleLedger = serde_json::from_str("{}").unwrap();
55 assert_eq!(back, StreamRuleLedger::default());
56 }
57}