rust_supervisor/journal/ring.rs
1//! Fixed-capacity event journal.
2//!
3//! The journal stores recent lifecycle events for diagnostics and replay. It
4//! does not own subscribers or exporters.
5
6use crate::event::payload::SupervisorEvent;
7use crate::event::time::EventSequence;
8use serde::{Deserialize, Serialize};
9use std::collections::VecDeque;
10
11/// Fixed-capacity lifecycle event journal.
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
13pub struct EventJournal {
14 /// Maximum number of events retained in memory.
15 pub capacity: usize,
16 /// Recent events in oldest-to-newest order.
17 pub events: VecDeque<SupervisorEvent>,
18 /// Number of events dropped because capacity was full.
19 pub dropped_count: u64,
20 /// Last sequence written to the journal.
21 pub last_sequence: Option<EventSequence>,
22}
23
24impl EventJournal {
25 /// Creates an event journal with fixed capacity.
26 ///
27 /// # Arguments
28 ///
29 /// - `capacity`: Maximum number of events retained. Zero is allowed and
30 /// drops every pushed event.
31 ///
32 /// # Returns
33 ///
34 /// Returns an empty [`EventJournal`].
35 ///
36 /// # Examples
37 ///
38 /// ```
39 /// let journal = rust_supervisor::journal::ring::EventJournal::new(2);
40 /// assert_eq!(journal.capacity, 2);
41 /// ```
42 pub fn new(capacity: usize) -> Self {
43 Self {
44 capacity,
45 events: VecDeque::with_capacity(capacity),
46 dropped_count: 0,
47 last_sequence: None,
48 }
49 }
50
51 /// Pushes an event and drops the oldest event when full.
52 ///
53 /// # Arguments
54 ///
55 /// - `event`: Event that should be retained when capacity permits.
56 ///
57 /// # Returns
58 ///
59 /// Returns the new dropped count.
60 pub fn push(&mut self, event: SupervisorEvent) -> u64 {
61 self.last_sequence = Some(event.sequence);
62 if self.capacity == 0 {
63 self.dropped_count = self.dropped_count.saturating_add(1);
64 return self.dropped_count;
65 }
66 if self.events.len() == self.capacity {
67 self.events.pop_front();
68 self.dropped_count = self.dropped_count.saturating_add(1);
69 }
70 self.events.push_back(event);
71 self.dropped_count
72 }
73
74 /// Returns recent events with newest events retained.
75 ///
76 /// # Arguments
77 ///
78 /// - `limit`: Maximum number of events to return.
79 ///
80 /// # Returns
81 ///
82 /// Returns events in oldest-to-newest order.
83 ///
84 /// # Examples
85 ///
86 /// ```
87 /// let journal = rust_supervisor::journal::ring::EventJournal::new(4);
88 /// assert!(journal.recent(2).is_empty());
89 /// ```
90 pub fn recent(&self, limit: usize) -> Vec<SupervisorEvent> {
91 let skip = self.events.len().saturating_sub(limit);
92 self.events.iter().skip(skip).cloned().collect()
93 }
94
95 /// Returns the number of retained events.
96 ///
97 /// # Arguments
98 ///
99 /// This function has no arguments.
100 ///
101 /// # Returns
102 ///
103 /// Returns the current event count.
104 pub fn len(&self) -> usize {
105 self.events.len()
106 }
107
108 /// Reports whether the journal has no retained events.
109 ///
110 /// # Arguments
111 ///
112 /// This function has no arguments.
113 ///
114 /// # Returns
115 ///
116 /// Returns `true` when the journal is empty.
117 pub fn is_empty(&self) -> bool {
118 self.events.is_empty()
119 }
120}