Skip to main content

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}