ironrdp_graphics/zgfx/
circular_buffer.rs

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        // will take the offset if the destination length is greater than the offset,
21        // i.e. greater than the current buffer position.
22        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}