/rust/registry/src/index.crates.io-1949cf8c6b5b557f/prodash-31.0.0/src/messages.rs
Line | Count | Source |
1 | | use std::time::SystemTime; |
2 | | |
3 | | /// The severity of a message |
4 | | #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] |
5 | | pub enum MessageLevel { |
6 | | /// Rarely sent information related to the progress, not to be confused with the progress itself |
7 | | Info, |
8 | | /// Used to indicate that a task has failed, along with the reason |
9 | | Failure, |
10 | | /// Indicates a task was completed successfully |
11 | | Success, |
12 | | } |
13 | | |
14 | | /// A message to be stored along with the progress tree. |
15 | | /// |
16 | | /// It is created by [`Tree::message(…)`](./struct.Item.html#method.message). |
17 | | #[derive(Debug, Clone, Eq, PartialEq)] |
18 | | pub struct Message { |
19 | | /// The time at which the message was sent. |
20 | | pub time: SystemTime, |
21 | | /// The severity of the message |
22 | | pub level: MessageLevel, |
23 | | /// The name of the task that created the `Message` |
24 | | pub origin: String, |
25 | | /// The message itself |
26 | | pub message: String, |
27 | | } |
28 | | |
29 | | /// A ring buffer for messages. |
30 | | #[derive(Debug, Clone, Eq, PartialEq)] |
31 | | pub struct MessageRingBuffer { |
32 | | pub(crate) buf: Vec<Message>, |
33 | | cursor: usize, |
34 | | total: usize, |
35 | | } |
36 | | |
37 | | impl MessageRingBuffer { |
38 | | /// Create a new instance the ability to hold `capacity` amount of messages. |
39 | 0 | pub fn with_capacity(capacity: usize) -> MessageRingBuffer { |
40 | 0 | MessageRingBuffer { |
41 | 0 | buf: Vec::with_capacity(capacity), |
42 | 0 | cursor: 0, |
43 | 0 | total: 0, |
44 | 0 | } |
45 | 0 | } |
46 | | |
47 | | /// Push a `message` from `origin` at severity `level` into the buffer, possibly overwriting the last message added. |
48 | 0 | pub fn push_overwrite(&mut self, level: MessageLevel, origin: String, message: impl Into<String>) { |
49 | 0 | let msg = Message { |
50 | 0 | time: SystemTime::now(), |
51 | 0 | level, |
52 | 0 | origin, |
53 | 0 | message: message.into(), |
54 | 0 | }; |
55 | 0 | if self.has_capacity() { |
56 | 0 | self.buf.push(msg) |
57 | 0 | } else { |
58 | 0 | self.buf[self.cursor] = msg; |
59 | 0 | self.cursor = (self.cursor + 1) % self.buf.len(); |
60 | 0 | } |
61 | 0 | self.total = self.total.wrapping_add(1); |
62 | 0 | } |
63 | | |
64 | | /// Copy all messages currently contained in the buffer to `out`. |
65 | 0 | pub fn copy_all(&self, out: &mut Vec<Message>) { |
66 | 0 | out.clear(); |
67 | 0 | if self.buf.is_empty() { |
68 | 0 | return; |
69 | 0 | } |
70 | 0 | out.extend_from_slice(&self.buf[self.cursor % self.buf.len()..]); |
71 | 0 | if self.cursor != self.buf.len() { |
72 | 0 | out.extend_from_slice(&self.buf[..self.cursor]); |
73 | 0 | } |
74 | 0 | } |
75 | | |
76 | | /// Copy all new messages into `out` that where received since the last time this method was called provided |
77 | | /// its `previous` return value. |
78 | 0 | pub fn copy_new(&self, out: &mut Vec<Message>, previous: Option<MessageCopyState>) -> MessageCopyState { |
79 | 0 | out.clear(); |
80 | 0 | match previous { |
81 | 0 | Some(MessageCopyState { cursor, buf_len, total }) => { |
82 | 0 | if self.total.saturating_sub(total) >= self.buf.capacity() { |
83 | 0 | self.copy_all(out); |
84 | 0 | } else { |
85 | 0 | let new_elements_below_cap = self.buf.len().saturating_sub(buf_len); |
86 | 0 | let cursor_ofs: isize = self.cursor as isize - cursor as isize; |
87 | 0 | match cursor_ofs { |
88 | | // there was some capacity left without wrapping around |
89 | 0 | 0 => { |
90 | 0 | out.extend_from_slice(&self.buf[self.buf.len() - new_elements_below_cap..]); |
91 | 0 | } |
92 | | // cursor advanced |
93 | 0 | c if c > 0 => { |
94 | 0 | out.extend_from_slice(&self.buf[(cursor % self.buf.len())..self.cursor]); |
95 | 0 | } |
96 | | // cursor wrapped around |
97 | 0 | c if c < 0 => { |
98 | 0 | out.extend_from_slice(&self.buf[(cursor % self.buf.len())..]); |
99 | 0 | out.extend_from_slice(&self.buf[..self.cursor]); |
100 | 0 | } |
101 | 0 | _ => unreachable!("logic dictates that… yeah, you really shouldn't ever see this!"), |
102 | | } |
103 | | } |
104 | | } |
105 | 0 | None => self.copy_all(out), |
106 | | }; |
107 | 0 | MessageCopyState { |
108 | 0 | cursor: self.cursor, |
109 | 0 | buf_len: self.buf.len(), |
110 | 0 | total: self.total, |
111 | 0 | } |
112 | 0 | } |
113 | | |
114 | 0 | fn has_capacity(&self) -> bool { |
115 | 0 | self.buf.len() < self.buf.capacity() |
116 | 0 | } |
117 | | } |
118 | | |
119 | | /// State used to keep track of what's new since the last time message were copied. |
120 | | /// |
121 | | /// Note that due to the nature of a ring buffer, there is no guarantee that you see all messages. |
122 | | pub struct MessageCopyState { |
123 | | cursor: usize, |
124 | | buf_len: usize, |
125 | | total: usize, |
126 | | } |