use crate::error::AnalyticsError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Event {
pub kind: String,
pub session_id: String,
pub timestamp_ms: u64,
}
impl Event {
pub fn new(kind: impl Into<String>, session_id: impl Into<String>, timestamp_ms: u64) -> Self {
Self {
kind: kind.into(),
session_id: session_id.into(),
timestamp_ms,
}
}
}
#[derive(Debug)]
pub struct EventBuffer {
capacity: usize,
events: Vec<Event>,
}
impl EventBuffer {
pub fn new(capacity: usize) -> Result<Self, AnalyticsError> {
if capacity == 0 {
return Err(AnalyticsError::InvalidInput("capacity must be > 0".into()));
}
Ok(Self {
capacity,
events: Vec::with_capacity(capacity),
})
}
pub fn push(&mut self, event: Event) -> Result<(), AnalyticsError> {
if self.events.len() >= self.capacity {
return Err(AnalyticsError::InvalidInput(format!(
"event buffer full (capacity = {})",
self.capacity
)));
}
self.events.push(event);
Ok(())
}
pub fn drain(&mut self) -> Vec<Event> {
std::mem::take(&mut self.events)
}
#[must_use]
pub fn len(&self) -> usize {
self.events.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
#[must_use]
pub fn capacity(&self) -> usize {
self.capacity
}
}
#[cfg(test)]
mod tests {
use super::*;
fn ev(kind: &str) -> Event {
Event::new(kind, "s1", 0)
}
#[test]
fn zero_capacity_errors() {
assert!(EventBuffer::new(0).is_err());
}
#[test]
fn push_and_drain() {
let mut buf = EventBuffer::new(4).expect("valid");
buf.push(ev("play")).expect("room");
buf.push(ev("pause")).expect("room");
let events = buf.drain();
assert_eq!(events.len(), 2);
assert_eq!(events[0].kind, "play");
assert_eq!(events[1].kind, "pause");
}
#[test]
fn drain_clears_buffer() {
let mut buf = EventBuffer::new(4).expect("valid");
buf.push(ev("seek")).expect("room");
let _ = buf.drain();
assert!(buf.is_empty());
assert_eq!(buf.len(), 0);
}
#[test]
fn push_beyond_capacity_errors() {
let mut buf = EventBuffer::new(2).expect("valid");
buf.push(ev("a")).expect("room");
buf.push(ev("b")).expect("room");
assert!(buf.push(ev("c")).is_err());
assert_eq!(buf.len(), 2);
}
#[test]
fn drain_empty_returns_empty_vec() {
let mut buf = EventBuffer::new(5).expect("valid");
assert_eq!(buf.drain(), Vec::<Event>::new());
}
#[test]
fn capacity_reported_correctly() {
let buf = EventBuffer::new(7).expect("valid");
assert_eq!(buf.capacity(), 7);
}
#[test]
fn multiple_drain_cycles() {
let mut buf = EventBuffer::new(3).expect("valid");
for cycle in 0u64..3 {
buf.push(Event::new("e", "s", cycle)).expect("room");
buf.push(Event::new("e", "s", cycle + 100)).expect("room");
let batch = buf.drain();
assert_eq!(batch.len(), 2);
assert!(buf.is_empty());
}
}
}