1use std::time::SystemTime;
2
3#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
5pub enum MessageLevel {
6 Info,
8 Failure,
10 Success,
12}
13
14#[derive(Debug, Clone, Eq, PartialEq)]
18pub struct Message {
19 pub time: SystemTime,
21 pub level: MessageLevel,
23 pub origin: String,
25 pub message: String,
27}
28
29#[derive(Debug, Clone, Eq, PartialEq)]
31pub struct MessageRingBuffer {
32 pub(crate) buf: Vec<Message>,
33 cursor: usize,
34 total: usize,
35}
36
37impl MessageRingBuffer {
38 pub fn with_capacity(capacity: usize) -> MessageRingBuffer {
40 MessageRingBuffer {
41 buf: Vec::with_capacity(capacity),
42 cursor: 0,
43 total: 0,
44 }
45 }
46
47 pub fn push_overwrite(&mut self, level: MessageLevel, origin: String, message: impl Into<String>) {
49 let msg = Message {
50 time: SystemTime::now(),
51 level,
52 origin,
53 message: message.into(),
54 };
55 if self.has_capacity() {
56 self.buf.push(msg)
57 } else {
58 self.buf[self.cursor] = msg;
59 self.cursor = (self.cursor + 1) % self.buf.len();
60 }
61 self.total = self.total.wrapping_add(1);
62 }
63
64 pub fn copy_all(&self, out: &mut Vec<Message>) {
66 out.clear();
67 if self.buf.is_empty() {
68 return;
69 }
70 out.extend_from_slice(&self.buf[self.cursor % self.buf.len()..]);
71 if self.cursor != self.buf.len() {
72 out.extend_from_slice(&self.buf[..self.cursor]);
73 }
74 }
75
76 pub fn copy_new(&self, out: &mut Vec<Message>, previous: Option<MessageCopyState>) -> MessageCopyState {
79 out.clear();
80 match previous {
81 Some(MessageCopyState { cursor, buf_len, total }) => {
82 if self.total.saturating_sub(total) >= self.buf.capacity() {
83 self.copy_all(out);
84 } else {
85 let new_elements_below_cap = self.buf.len().saturating_sub(buf_len);
86 let cursor_ofs: isize = self.cursor as isize - cursor as isize;
87 match cursor_ofs {
88 0 => {
90 out.extend_from_slice(&self.buf[self.buf.len() - new_elements_below_cap..]);
91 }
92 c if c > 0 => {
94 out.extend_from_slice(&self.buf[(cursor % self.buf.len())..self.cursor]);
95 }
96 c if c < 0 => {
98 out.extend_from_slice(&self.buf[(cursor % self.buf.len())..]);
99 out.extend_from_slice(&self.buf[..self.cursor]);
100 }
101 _ => unreachable!("logic dictates that… yeah, you really shouldn't ever see this!"),
102 }
103 }
104 }
105 None => self.copy_all(out),
106 };
107 MessageCopyState {
108 cursor: self.cursor,
109 buf_len: self.buf.len(),
110 total: self.total,
111 }
112 }
113
114 fn has_capacity(&self) -> bool {
115 self.buf.len() < self.buf.capacity()
116 }
117}
118
119pub struct MessageCopyState {
123 cursor: usize,
124 buf_len: usize,
125 total: usize,
126}