1use std::collections::VecDeque;
2
3use crate::event::SyncEvent;
4
5#[derive(Debug)]
29pub struct EventBuffer {
30 buffer: VecDeque<SyncEvent>,
31 capacity: usize,
32}
33
34impl EventBuffer {
35 #[must_use]
39 pub fn new(capacity: usize) -> Self {
40 Self { buffer: VecDeque::with_capacity(capacity), capacity }
41 }
42
43 pub fn push(&mut self, event: SyncEvent) -> Option<SyncEvent> {
48 let evicted =
49 if self.buffer.len() >= self.capacity { self.buffer.pop_front() } else { None };
50 if self.capacity > 0 {
52 self.buffer.push_back(event);
53 }
54 evicted
55 }
56
57 pub fn drain_all(&mut self) -> Vec<SyncEvent> {
59 self.buffer.drain(..).collect()
60 }
61
62 #[must_use]
64 pub fn len(&self) -> usize {
65 self.buffer.len()
66 }
67
68 #[must_use]
70 pub fn is_empty(&self) -> bool {
71 self.buffer.is_empty()
72 }
73
74 #[must_use]
76 pub fn is_full(&self) -> bool {
77 self.buffer.len() >= self.capacity
78 }
79
80 #[must_use]
82 pub const fn capacity(&self) -> usize {
83 self.capacity
84 }
85
86 #[must_use]
88 pub fn recent(&self, count: usize) -> Vec<&SyncEvent> {
89 let start = self.buffer.len().saturating_sub(count);
90 self.buffer.iter().skip(start).collect()
91 }
92
93 pub fn clear(&mut self) {
95 self.buffer.clear();
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use serde_json::json;
103
104 fn make_event(name: &str) -> SyncEvent {
105 SyncEvent::new(name, "entity", "id", json!({}))
106 }
107
108 #[test]
109 fn push_within_capacity() {
110 let mut buffer = EventBuffer::new(5);
111 let evicted = buffer.push(make_event("a"));
112 assert!(evicted.is_none());
113 assert_eq!(buffer.len(), 1);
114 }
115
116 #[test]
117 fn push_at_capacity_evicts() {
118 let mut buffer = EventBuffer::new(2);
119 buffer.push(make_event("a"));
120 buffer.push(make_event("b"));
121 assert!(buffer.is_full());
122
123 let evicted = buffer.push(make_event("c"));
124 assert!(evicted.is_some());
125 assert_eq!(evicted.unwrap().event_type, "a");
126 assert_eq!(buffer.len(), 2);
127 }
128
129 #[test]
130 fn eviction_preserves_fifo_order() {
131 let mut buffer = EventBuffer::new(3);
132 buffer.push(make_event("a"));
133 buffer.push(make_event("b"));
134 buffer.push(make_event("c"));
135
136 let evicted = buffer.push(make_event("d"));
138 assert_eq!(evicted.unwrap().event_type, "a");
139
140 let drained = buffer.drain_all();
141 assert_eq!(drained[0].event_type, "b");
142 assert_eq!(drained[1].event_type, "c");
143 assert_eq!(drained[2].event_type, "d");
144 }
145
146 #[test]
147 fn drain_all_empties_buffer() {
148 let mut buffer = EventBuffer::new(10);
149 buffer.push(make_event("a"));
150 buffer.push(make_event("b"));
151
152 let drained = buffer.drain_all();
153 assert_eq!(drained.len(), 2);
154 assert!(buffer.is_empty());
155 }
156
157 #[test]
158 fn drain_all_empty_buffer() {
159 let mut buffer = EventBuffer::new(10);
160 let drained = buffer.drain_all();
161 assert!(drained.is_empty());
162 }
163
164 #[test]
165 fn is_empty_and_is_full() {
166 let mut buffer = EventBuffer::new(2);
167 assert!(buffer.is_empty());
168 assert!(!buffer.is_full());
169
170 buffer.push(make_event("a"));
171 assert!(!buffer.is_empty());
172 assert!(!buffer.is_full());
173
174 buffer.push(make_event("b"));
175 assert!(!buffer.is_empty());
176 assert!(buffer.is_full());
177 }
178
179 #[test]
180 fn zero_capacity_buffer() {
181 let mut buffer = EventBuffer::new(0);
182 assert!(buffer.is_full());
183
184 let evicted = buffer.push(make_event("a"));
186 assert!(evicted.is_none()); assert!(buffer.is_empty());
188 assert_eq!(buffer.len(), 0);
189 }
190
191 #[test]
192 fn capacity_accessor() {
193 let buffer = EventBuffer::new(42);
194 assert_eq!(buffer.capacity(), 42);
195 }
196
197 #[test]
198 fn recent_events() {
199 let mut buffer = EventBuffer::new(10);
200 buffer.push(make_event("a"));
201 buffer.push(make_event("b"));
202 buffer.push(make_event("c"));
203
204 let recent = buffer.recent(2);
205 assert_eq!(recent.len(), 2);
206 assert_eq!(recent[0].event_type, "b");
207 assert_eq!(recent[1].event_type, "c");
208 }
209
210 #[test]
211 fn recent_more_than_available() {
212 let mut buffer = EventBuffer::new(10);
213 buffer.push(make_event("a"));
214
215 let recent = buffer.recent(5);
216 assert_eq!(recent.len(), 1);
217 }
218
219 #[test]
220 fn clear_buffer() {
221 let mut buffer = EventBuffer::new(10);
222 buffer.push(make_event("a"));
223 buffer.push(make_event("b"));
224 buffer.clear();
225 assert!(buffer.is_empty());
226 assert_eq!(buffer.len(), 0);
227 }
228
229 #[test]
230 fn debug_impl() {
231 let buffer = EventBuffer::new(10);
232 let debug = format!("{buffer:?}");
233 assert!(debug.contains("EventBuffer"));
234 }
235
236 #[test]
237 fn multiple_evictions() {
238 let mut buffer = EventBuffer::new(2);
239 buffer.push(make_event("a"));
240 buffer.push(make_event("b"));
241
242 let e1 = buffer.push(make_event("c"));
243 assert_eq!(e1.unwrap().event_type, "a");
244
245 let e2 = buffer.push(make_event("d"));
246 assert_eq!(e2.unwrap().event_type, "b");
247
248 let remaining = buffer.drain_all();
249 assert_eq!(remaining.len(), 2);
250 assert_eq!(remaining[0].event_type, "c");
251 assert_eq!(remaining[1].event_type, "d");
252 }
253}