xchecker_utils/
ring_buffer.rs1use std::collections::VecDeque;
6use std::fmt;
7
8#[derive(Debug, Clone)]
10pub struct RingBuffer {
11 buffer: VecDeque<u8>,
12 max_bytes: usize,
13 total_bytes_written: usize,
14}
15
16impl RingBuffer {
17 #[must_use]
19 pub fn new(max_bytes: usize) -> Self {
20 Self {
21 buffer: VecDeque::with_capacity(max_bytes.min(8192)),
22 max_bytes,
23 total_bytes_written: 0,
24 }
25 }
26
27 pub fn write(&mut self, data: &[u8]) {
31 self.total_bytes_written += data.len();
32
33 for &byte in data {
34 if self.buffer.len() >= self.max_bytes {
35 self.buffer.pop_front();
37 }
38 self.buffer.push_back(byte);
39 }
40 }
41
42 #[must_use]
44 #[allow(dead_code)] pub fn len(&self) -> usize {
46 self.buffer.len()
47 }
48
49 #[must_use]
51 #[allow(dead_code)] pub fn is_empty(&self) -> bool {
53 self.buffer.is_empty()
54 }
55
56 #[must_use]
58 pub const fn total_bytes_written(&self) -> usize {
59 self.total_bytes_written
60 }
61
62 #[must_use]
64 pub const fn was_truncated(&self) -> bool {
65 self.total_bytes_written > self.max_bytes
66 }
67}
68
69impl fmt::Display for RingBuffer {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 let bytes: Vec<u8> = self.buffer.iter().copied().collect();
72 write!(f, "{}", String::from_utf8_lossy(&bytes))
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_ring_buffer_basic() {
82 let mut buffer = RingBuffer::new(10);
83 buffer.write(b"hello");
84 assert_eq!(buffer.to_string(), "hello");
85 assert_eq!(buffer.len(), 5);
86 assert!(!buffer.is_empty());
87 }
88
89 #[test]
90 fn test_ring_buffer_truncation() {
91 let mut buffer = RingBuffer::new(10);
92 buffer.write(b"hello");
93 buffer.write(b"world");
94 buffer.write(b"!");
95
96 assert_eq!(buffer.len(), 10);
98 assert_eq!(buffer.to_string(), "elloworld!");
99 assert_eq!(buffer.total_bytes_written(), 11);
100 assert!(buffer.was_truncated());
101 }
102
103 #[test]
104 fn test_ring_buffer_large_write() {
105 let mut buffer = RingBuffer::new(5);
106 buffer.write(b"hello world");
107
108 assert_eq!(buffer.len(), 5);
110 assert_eq!(buffer.to_string(), "world");
111 assert_eq!(buffer.total_bytes_written(), 11);
112 assert!(buffer.was_truncated());
113 }
114
115 #[test]
116 fn test_ring_buffer_exact_capacity() {
117 let mut buffer = RingBuffer::new(10);
118 buffer.write(b"1234567890");
119
120 assert_eq!(buffer.len(), 10);
121 assert_eq!(buffer.to_string(), "1234567890");
122 assert!(!buffer.was_truncated());
123 }
124
125 #[test]
126 fn test_ring_buffer_multiple_writes() {
127 let mut buffer = RingBuffer::new(10);
128 buffer.write(b"12345");
129 buffer.write(b"67890");
130 buffer.write(b"ABCDE");
131
132 assert_eq!(buffer.len(), 10);
134 assert_eq!(buffer.to_string(), "67890ABCDE");
135 assert_eq!(buffer.total_bytes_written(), 15);
136 assert!(buffer.was_truncated());
137 }
138
139 #[test]
140 fn test_ring_buffer_empty() {
141 let buffer = RingBuffer::new(10);
142 assert!(buffer.is_empty());
143 assert_eq!(buffer.len(), 0);
144 assert_eq!(buffer.to_string(), "");
145 assert!(!buffer.was_truncated());
146 }
147
148 #[test]
149 fn test_ring_buffer_utf8_handling() {
150 let mut buffer = RingBuffer::new(20);
151 buffer.write("Hello 世界".as_bytes());
152 assert_eq!(buffer.to_string(), "Hello 世界");
153 }
154
155 #[test]
156 fn test_ring_buffer_invalid_utf8() {
157 let mut buffer = RingBuffer::new(10);
158 buffer.write(&[0xFF, 0xFE, 0xFD]);
160 let result = buffer.to_string();
162 assert!(!result.is_empty());
163 }
164}