use std::time::SystemTime;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum MessageLevel {
Info,
Failure,
Success,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Message {
pub time: SystemTime,
pub level: MessageLevel,
pub origin: String,
pub message: String,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MessageRingBuffer {
pub(crate) buf: Vec<Message>,
cursor: usize,
total: usize,
}
impl MessageRingBuffer {
pub fn with_capacity(capacity: usize) -> MessageRingBuffer {
MessageRingBuffer {
buf: Vec::with_capacity(capacity),
cursor: 0,
total: 0,
}
}
pub fn push_overwrite(&mut self, level: MessageLevel, origin: String, message: impl Into<String>) {
let msg = Message {
time: SystemTime::now(),
level,
origin,
message: message.into(),
};
if self.has_capacity() {
self.buf.push(msg)
} else {
self.buf[self.cursor] = msg;
self.cursor = (self.cursor + 1) % self.buf.len();
}
self.total = self.total.wrapping_add(1);
}
pub fn copy_all(&self, out: &mut Vec<Message>) {
out.clear();
if self.buf.is_empty() {
return;
}
out.extend_from_slice(&self.buf[self.cursor % self.buf.len()..]);
if self.cursor != self.buf.len() {
out.extend_from_slice(&self.buf[..self.cursor]);
}
}
pub fn copy_new(&self, out: &mut Vec<Message>, previous: Option<MessageCopyState>) -> MessageCopyState {
out.clear();
match previous {
Some(MessageCopyState { cursor, buf_len, total }) => {
if self.total.saturating_sub(total) >= self.buf.capacity() {
self.copy_all(out);
} else {
let new_elements_below_cap = self.buf.len().saturating_sub(buf_len);
let cursor_ofs: isize = self.cursor as isize - cursor as isize;
match cursor_ofs {
c if c == 0 => {
out.extend_from_slice(&self.buf[self.buf.len() - new_elements_below_cap..]);
}
c if c > 0 => {
out.extend_from_slice(&self.buf[(cursor % self.buf.len())..self.cursor]);
}
c if c < 0 => {
out.extend_from_slice(&self.buf[(cursor % self.buf.len())..]);
out.extend_from_slice(&self.buf[..self.cursor]);
}
_ => unreachable!("logic dictates that… yeah, you really shouldn't ever see this!"),
}
}
}
None => self.copy_all(out),
};
MessageCopyState {
cursor: self.cursor,
buf_len: self.buf.len(),
total: self.total,
}
}
fn has_capacity(&self) -> bool {
self.buf.len() < self.buf.capacity()
}
}
pub struct MessageCopyState {
cursor: usize,
buf_len: usize,
total: usize,
}