1use std::io;
2
3use super::*;
4
5#[derive(Debug)]
13pub struct Reserve<T: BufferedReader<C>, C: fmt::Debug + Sync + Send> {
14 reserve: usize,
15 cookie: C,
16 reader: T,
17}
18
19assert_send_and_sync!(Reserve<T, C>
20 where T: BufferedReader<C>,
21 C: fmt::Debug);
22
23impl<T: BufferedReader<C>, C: fmt::Debug + Sync + Send> fmt::Display for Reserve<T, C> {
24 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25 f.debug_struct("Reserve")
26 .field("reserve", &self.reserve)
27 .finish()
28 }
29}
30
31impl<T: BufferedReader<()>> Reserve<T, ()> {
32 pub fn new(reader: T, reserve: usize) -> Self {
37 Self::with_cookie(reader, reserve, ())
38 }
39}
40
41impl<T: BufferedReader<C>, C: fmt::Debug + Sync + Send> Reserve<T, C> {
42 pub fn with_cookie(reader: T, reserve: usize, cookie: C)
47 -> Reserve<T, C> {
48 Reserve {
49 reader,
50 reserve,
51 cookie,
52 }
53 }
54}
55
56impl<T: BufferedReader<C>, C: fmt::Debug + Sync + Send> io::Read for Reserve<T, C> {
57 fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
58 let to_read = {
59 let data = self.reader.data(buf.len() + self.reserve)?;
60 if data.len() > self.reserve {
61 data.len() - self.reserve
62 } else {
63 return Ok(0);
64 }
65 };
66
67 let to_read = cmp::min(buf.len(), to_read);
68
69 self.reader.read(&mut buf[..to_read])
70 }
71}
72
73impl<T: BufferedReader<C>, C: fmt::Debug + Send + Sync> BufferedReader<C> for Reserve<T, C> {
74 fn buffer(&self) -> &[u8] {
75 let buf = self.reader.buffer();
76 if buf.len() > self.reserve {
77 &buf[..buf.len() - self.reserve]
78 } else {
79 b""
80 }
81 }
82
83 fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
86 let data = self.reader.data(amount + self.reserve)?;
87 if data.len() <= self.reserve {
88 Ok(b"")
90 } else {
91 Ok(&data[..data.len() - self.reserve])
93 }
94 }
95
96 fn consume(&mut self, amount: usize) -> &[u8] {
97 assert!(amount <= self.buffer().len());
98
99 let data = self.reader.consume(amount);
102 assert!(data.len() >= amount);
103
104 if data.len() > amount {
105 if data.len() > amount + self.reserve {
109 return &data[..data.len() - self.reserve];
110 }
111 }
112 &data[..amount]
113 }
114
115 fn data_consume(&mut self, amount: usize) -> Result<&[u8], io::Error> {
116 let amount = cmp::min(amount, self.data(amount)?.len());
117 Ok(self.consume(amount))
118 }
119
120 fn data_consume_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
121 self.data_hard(amount)?;
122 Ok(self.consume(amount))
123 }
124
125 fn get_mut(&mut self) -> Option<&mut dyn BufferedReader<C>> {
126 Some(&mut self.reader)
127 }
128
129 fn get_ref(&self) -> Option<&dyn BufferedReader<C>> {
130 Some(&self.reader)
131 }
132
133 fn into_inner<'b>(self: Box<Self>) -> Option<Box<dyn BufferedReader<C> + 'b>>
134 where Self: 'b {
135 Some(self.reader.into_boxed())
136 }
137
138 fn cookie_set(&mut self, cookie: C) -> C {
139 use std::mem;
140
141 mem::replace(&mut self.cookie, cookie)
142 }
143
144 fn cookie_ref(&self) -> &C {
145 &self.cookie
146 }
147
148 fn cookie_mut(&mut self) -> &mut C {
149 &mut self.cookie
150 }
151}
152
153#[cfg(test)]
154mod test {
155 use super::*;
156
157 #[test]
158 fn data() {
159 use crate::Memory;
160
161 fn read_chunk<'a, R: BufferedReader<C>, C: fmt::Debug + Sync + Send>(
174 orig: &[u8], r: &mut R, to_read: usize, cursor: usize, total: usize,
175 mode: usize)
176 {
177 let data_len = {
179 let data = r.data(to_read).unwrap();
180 assert_eq!(data, &orig[cursor..cursor + data.len()]);
181 data.len()
182 };
183 assert!(data_len <= total - cursor);
184 assert_eq!(r.buffer().len(), data_len);
185
186 let data_hard_len = {
188 let data_hard = r.data_hard(to_read).unwrap();
189 assert_eq!(data_hard, &orig[cursor..cursor + data_hard.len()]);
190 data_hard.len()
191 };
192 assert!(data_len <= data_hard_len);
193 assert!(data_hard_len <= total - cursor);
194 assert_eq!(r.buffer().len(), data_hard_len);
195
196
197
198 assert!(r.data_hard(total - cursor + 1).is_err());
201
202 let data_len = {
204 let data = r.data(to_read).unwrap();
205 assert_eq!(data, &orig[cursor..cursor + data.len()]);
206 data.len()
207 };
208 assert!(data_len <= total - cursor);
209 assert_eq!(r.buffer().len(), data_len);
210
211
212 assert!(r.data_consume_hard(total - cursor + 1).is_err());
214
215 let data_len = {
217 let data = r.data(to_read).unwrap();
218 assert_eq!(data, &orig[cursor..cursor + data.len()]);
219 data.len()
220 };
221 assert!(data_len <= total - cursor);
222 assert_eq!(r.buffer().len(), data_len);
223
224
225
226 match mode {
228 0 => {
229 let l = r.consume(to_read).len();
231 assert!(to_read <= l);
232 assert!(l <= total - cursor);
233 }
234 1 => {
235 let data_len = {
237 let data = r.data_consume(to_read).unwrap();
238 assert_eq!(data, &orig[cursor..cursor + data.len()]);
239 data.len()
240 };
241 assert!(data_len <= total - cursor);
242 assert!(r.buffer().len() <= total - cursor - to_read);
243 }
244 2 => {
245 let data_len = {
247 let data = r.data_consume_hard(to_read).unwrap();
248 assert_eq!(data, &orig[cursor..cursor + data.len()]);
249 data.len()
250 };
251 assert!(data_len <= total - cursor);
252 assert!(r.buffer().len() <= total - cursor - to_read);
253 }
254 _ => panic!("Invalid mode"),
255 }
256 }
257
258 fn test(orig: &[u8], mode: usize, reserve: usize,
259 mid1: usize, mid2: usize) {
260 let total = orig.len() - reserve;
261
262 let mut r = Reserve::new(
263 Memory::new(orig), reserve);
264
265 read_chunk(orig, &mut r, mid1, 0, total, mode);
267
268 read_chunk(orig, &mut r, mid2 - mid1, mid1, total, mode);
270
271 read_chunk(orig, &mut r, total - mid2, mid2, total, mode);
273
274 assert_eq!(r.data(100).unwrap().len(), 0);
276 assert_eq!(r.buffer().len(), 0);
277 assert!(r.data_hard(100).is_err());
278 assert_eq!(r.data_hard(0).unwrap().len(), 0);
279
280 let mut g = Box::new(r).into_inner().unwrap();
281 read_chunk(orig, &mut g,
282 orig.len() - total, total, orig.len(),
283 mode);
284 }
285
286 let orig : &[u8] = b"abcdefghijklmnopqrstuvwxyz";
288
289 for mode in 0..3 {
292 for reserve in 0..orig.len() {
293 let total = orig.len() - reserve;
294
295 for mid1 in 0..total {
296 for mid2 in mid1..total {
297 test(orig, mode, reserve, mid1, mid2);
298 }
299 }
300 }
301 }
302 }
303}