1use core::cmp::min;
2use std::io;
3
4pub(crate) struct FixedCircularBuffer {
5 buffer: Vec<u8>,
6 position: usize,
7}
8
9impl FixedCircularBuffer {
10 pub(crate) fn new(size: usize) -> Self {
11 Self {
12 buffer: vec![0; size],
13 position: 0,
14 }
15 }
16
17 pub(crate) fn read_with_offset(&self, offset: usize, length: usize, output: &mut impl io::Write) -> io::Result<()> {
18 let position = (self.buffer.len() + self.position - offset) % self.buffer.len();
19
20 let dst_length = min(offset, length);
23 let mut written = 0;
24
25 if position + dst_length <= self.buffer.len() {
26 while written < length {
27 let to_write = min(length - written, dst_length);
28 output.write_all(&self.buffer[position..position + to_write])?;
29 written += to_write;
30 }
31 } else {
32 let to_front = &self.buffer[position..];
33 let to_back = &self.buffer[..dst_length - to_front.len()];
34
35 while written < length {
36 let to_write = min(length - written, dst_length);
37
38 let to_write_to_front = min(to_front.len(), to_write);
39 output.write_all(&to_front[..to_write_to_front])?;
40 output.write_all(&to_back[..to_write - to_write_to_front])?;
41
42 written += to_write;
43 }
44 }
45
46 Ok(())
47 }
48}
49
50impl io::Write for FixedCircularBuffer {
51 fn write(&mut self, mut buf: &[u8]) -> io::Result<usize> {
52 let bytes_written = buf.len();
53
54 if buf.len() > self.buffer.len() {
55 let residue = buf.len() - self.buffer.len();
56 buf = &buf[residue..];
57 self.position = (self.position + residue) % self.buffer.len();
58 }
59
60 if self.position + buf.len() <= self.buffer.len() {
61 self.buffer[self.position..self.position + buf.len()].clone_from_slice(buf);
62
63 self.position += buf.len();
64 } else {
65 let (to_back, to_front) = buf.split_at(self.buffer.len() - self.position);
66 self.buffer[self.position..].clone_from_slice(to_back);
67 self.buffer[0..to_front.len()].clone_from_slice(to_front);
68
69 self.position = buf.len() - to_back.len();
70 }
71
72 if self.position == self.buffer.len() {
73 self.position = 0;
74 }
75
76 Ok(bytes_written)
77 }
78
79 fn flush(&mut self) -> io::Result<()> {
80 Ok(())
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use std::io::Write as _;
87
88 use super::*;
89
90 #[test]
91 fn fixed_circular_buffer_correctly_writes_buffer_less_then_internal_buffer_size() {
92 let size = 8;
93 let mut circular_buffer = FixedCircularBuffer::new(size);
94 let to_write = [1, 2, 3];
95
96 circular_buffer.write_all(to_write.as_ref()).unwrap();
97
98 assert_eq!(vec![1, 2, 3, 0, 0, 0, 0, 0], circular_buffer.buffer);
99 assert_eq!(to_write.len(), circular_buffer.position);
100 }
101
102 #[test]
103 fn fixed_circular_buffer_correctly_writes_buffer_less_then_internal_buffer_size_to_end() {
104 let size = 8;
105 let mut circular_buffer = FixedCircularBuffer::new(size);
106 circular_buffer.position = 5;
107 let to_write = [1, 2, 3];
108
109 circular_buffer.write_all(to_write.as_ref()).unwrap();
110
111 assert_eq!(vec![0, 0, 0, 0, 0, 1, 2, 3], circular_buffer.buffer);
112 assert_eq!(0, circular_buffer.position);
113 }
114
115 #[test]
116 fn fixed_circular_buffer_correctly_writes_buffer_bigger_then_position_with_remaining_size() {
117 let size = 8;
118 let mut circular_buffer = FixedCircularBuffer::new(size);
119 circular_buffer.position = 6;
120 let to_write = [1, 2, 3];
121
122 circular_buffer.write_all(to_write.as_ref()).unwrap();
123
124 assert_eq!(vec![3, 0, 0, 0, 0, 0, 1, 2], circular_buffer.buffer);
125 assert_eq!(1, circular_buffer.position);
126 }
127
128 #[test]
129 fn fixed_circular_buffer_correctly_writes_buffer_bigger_then_internal_buffer_size() {
130 let size = 8;
131 let mut circular_buffer = FixedCircularBuffer::new(size);
132 let to_write = (1..=10).collect::<Vec<_>>();
133
134 circular_buffer.write_all(to_write.as_ref()).unwrap();
135
136 assert_eq!(vec![9, 10, 3, 4, 5, 6, 7, 8], circular_buffer.buffer);
137 assert_eq!(2, circular_buffer.position);
138 }
139
140 #[test]
141 fn fixed_circular_buffer_correctly_writes_buffer_bigger_then_internal_buffer_size_with_position_at_end() {
142 let size = 8;
143 let mut circular_buffer = FixedCircularBuffer::new(size);
144 circular_buffer.position = 6;
145 let to_write = (1..=10).collect::<Vec<_>>();
146
147 circular_buffer.write_all(to_write.as_ref()).unwrap();
148
149 assert_eq!(vec![3, 4, 5, 6, 7, 8, 9, 10], circular_buffer.buffer);
150 assert_eq!(0, circular_buffer.position);
151 }
152
153 #[test]
154 fn fixed_circular_buffer_correctly_reads_buffer_with_length_not_greater_then_buffer_length() {
155 let circular_buffer = FixedCircularBuffer {
156 buffer: vec![11, 12, 13, 14, 15, 16, 7, 8, 9, 10],
157 position: 6,
158 };
159 let expected = vec![11, 12, 13, 14];
160
161 let mut output = Vec::with_capacity(expected.len());
162 circular_buffer.read_with_offset(6, 4, &mut output).unwrap();
163 assert_eq!(expected, output);
164 }
165
166 #[test]
167 fn fixed_circular_buffer_correctly_reads_buffer_from_end_to_start() {
168 let circular_buffer = FixedCircularBuffer {
169 buffer: vec![11, 12, 13, 14, 15, 16, 7, 8, 9, 10],
170 position: 6,
171 };
172 let expected = vec![8, 9, 10, 11, 12, 13, 14];
173
174 let mut output = Vec::with_capacity(expected.len());
175 circular_buffer.read_with_offset(9, 7, &mut output).unwrap();
176 assert_eq!(expected, output);
177 }
178
179 #[test]
180 fn fixed_circular_buffer_correctly_reads_buffer_with_repeating_one_byte() {
181 let circular_buffer = FixedCircularBuffer {
182 buffer: vec![11, 12, 13, 14, 15, 16, 7, 8, 9, 10],
183 position: 6,
184 };
185 let expected = vec![16; 7];
186
187 let mut output = Vec::with_capacity(expected.len());
188 circular_buffer.read_with_offset(1, 7, &mut output).unwrap();
189 assert_eq!(expected, output);
190 }
191
192 #[test]
193 fn fixed_circular_buffer_correctly_reads_buffer_with_repeating_multiple_bytes() {
194 let circular_buffer = FixedCircularBuffer {
195 buffer: vec![11, 12, 13, 14, 15, 16, 7, 8, 9, 10],
196 position: 6,
197 };
198 let expected = vec![14, 15, 16, 14, 15, 16, 14];
199
200 let mut output = Vec::with_capacity(expected.len());
201 circular_buffer.read_with_offset(3, 7, &mut output).unwrap();
202 assert_eq!(expected, output);
203 }
204
205 #[test]
206 fn fixed_circular_buffer_correctly_reads_buffer_with_repeating_multiple_bytes_from_end_to_start() {
207 let circular_buffer = FixedCircularBuffer {
208 buffer: vec![11, 12, 3, 4, 5, 6, 7, 8, 9, 10],
209 position: 2,
210 };
211 let expected = vec![9, 10, 11, 12, 9, 10, 11];
212
213 let mut output = Vec::with_capacity(expected.len());
214 circular_buffer.read_with_offset(4, 7, &mut output).unwrap();
215 assert_eq!(expected, output);
216 }
217}