Coverage Report

Created: 2025-10-13 07:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/brotli-decompressor-5.0.0/src/reader.rs
Line
Count
Source
1
#[cfg(feature="std")]
2
use std::io::{self, Error, ErrorKind, Read};
3
#[cfg(feature="std")]
4
pub use alloc_stdlib::StandardAlloc;
5
#[cfg(all(feature="unsafe",feature="std"))]
6
pub use alloc_stdlib::HeapAlloc;
7
pub use huffman::{HuffmanCode, HuffmanTreeGroup};
8
pub use state::BrotliState;
9
// use io_wrappers::write_all;
10
pub use io_wrappers::{CustomRead, CustomWrite};
11
#[cfg(feature="std")]
12
pub use io_wrappers::{IntoIoReader, IoReaderWrapper, IoWriterWrapper};
13
pub use super::decode::{BrotliDecompressStream, BrotliResult};
14
pub use alloc::{AllocatedStackMemory, Allocator, SliceWrapper, SliceWrapperMut, StackAllocator};
15
16
#[cfg(feature="std")]
17
pub struct DecompressorCustomAlloc<R: Read,
18
     BufferType : SliceWrapperMut<u8>,
19
     AllocU8 : Allocator<u8>,
20
     AllocU32 : Allocator<u32>,
21
     AllocHC : Allocator<HuffmanCode> >(DecompressorCustomIo<io::Error,
22
                                                             IntoIoReader<R>,
23
                                                             BufferType,
24
                                                             AllocU8, AllocU32, AllocHC>);
25
26
27
#[cfg(feature="std")]
28
impl<R: Read,
29
     BufferType : SliceWrapperMut<u8>,
30
     AllocU8,
31
     AllocU32,
32
     AllocHC> DecompressorCustomAlloc<R, BufferType, AllocU8, AllocU32, AllocHC>
33
 where AllocU8 : Allocator<u8>, AllocU32 : Allocator<u32>, AllocHC : Allocator<HuffmanCode>
34
    {
35
36
0
    pub fn new(r: R, buffer : BufferType,
37
0
               alloc_u8 : AllocU8, alloc_u32 : AllocU32, alloc_hc : AllocHC) -> Self {
38
0
        DecompressorCustomAlloc::<R, BufferType, AllocU8, AllocU32, AllocHC>(
39
0
          DecompressorCustomIo::<Error,
40
0
                                 IntoIoReader<R>,
41
0
                                 BufferType,
42
0
                                 AllocU8, AllocU32, AllocHC>::new(IntoIoReader::<R>(r),
43
0
                                                                  buffer,
44
0
                                                                  alloc_u8, alloc_u32, alloc_hc,
45
0
                                                                  Error::new(ErrorKind::InvalidData,
46
0
                                                                             "Invalid Data")))
47
0
    }
48
49
0
    pub fn new_with_custom_dictionary(r: R, buffer : BufferType,
50
0
               alloc_u8 : AllocU8, alloc_u32 : AllocU32, alloc_hc : AllocHC,
51
0
               dict: AllocU8::AllocatedMemory) -> Self {
52
0
        DecompressorCustomAlloc::<R, BufferType, AllocU8, AllocU32, AllocHC>(
53
0
          DecompressorCustomIo::<Error,
54
0
                                 IntoIoReader<R>,
55
0
                                 BufferType,
56
0
                                 AllocU8, AllocU32, AllocHC>::new_with_custom_dictionary(IntoIoReader::<R>(r),
57
0
                                                                                   buffer,
58
0
                                                                                   alloc_u8, alloc_u32, alloc_hc,
59
0
                                                                                   dict,
60
0
                                                                                   Error::new(ErrorKind::InvalidData,
61
0
                                                                                              "Invalid Data")))
62
0
    }
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomAlloc<&[u8], alloc_stdlib::heap_alloc::WrapBox<u8>, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc>>::new_with_custom_dictionary
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomAlloc<_, _, _, _, _>>::new_with_custom_dictionary
63
64
0
    pub fn get_ref(&self) -> &R {
65
0
      &self.0.get_ref().0
66
0
    }
67
0
    pub fn get_mut(&mut self) -> &mut R {
68
0
      &mut self.0.get_mut().0
69
0
    }
70
0
    pub fn into_inner(self) -> R {
71
0
      self.0.into_inner().0
72
0
    }
73
}
74
#[cfg(feature="std")]
75
impl<R: Read,
76
     BufferType : SliceWrapperMut<u8>,
77
     AllocU8 : Allocator<u8>,
78
     AllocU32 : Allocator<u32>,
79
     AllocHC : Allocator<HuffmanCode> > Read for DecompressorCustomAlloc<R,
80
                                                                         BufferType,
81
                                                                         AllocU8,
82
                                                                         AllocU32,
83
                                                                         AllocHC> {
84
0
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
85
0
       self.0.read(buf)
86
0
    }
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomAlloc<&[u8], alloc_stdlib::heap_alloc::WrapBox<u8>, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc> as std::io::Read>::read
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomAlloc<_, _, _, _, _> as std::io::Read>::read
87
}
88
89
90
#[cfg(not(any(feature="unsafe", not(feature="std"))))]
91
pub struct Decompressor<R: Read>(DecompressorCustomAlloc<R,
92
                                                         <StandardAlloc
93
                                                          as Allocator<u8>>::AllocatedMemory,
94
                                                         StandardAlloc,
95
                                                         StandardAlloc,
96
                                                         StandardAlloc>);
97
98
99
#[cfg(not(any(feature="unsafe", not(feature="std"))))]
100
impl<R: Read> Decompressor<R> {
101
0
  pub fn new(r: R, buffer_size: usize) -> Self {
102
0
     let dict = <StandardAlloc as Allocator<u8>>::AllocatedMemory::default();
103
0
     Self::new_with_custom_dict(r, buffer_size, dict)
104
0
  }
Unexecuted instantiation: <brotli_decompressor::reader::Decompressor<&[u8]>>::new
Unexecuted instantiation: <brotli_decompressor::reader::Decompressor<_>>::new
105
0
  pub fn new_with_custom_dict(r: R, buffer_size: usize, dict: <StandardAlloc as Allocator<u8>>::AllocatedMemory) -> Self {
106
0
    let mut alloc = StandardAlloc::default();
107
0
    let buffer = <StandardAlloc as Allocator<u8>>::alloc_cell(&mut alloc, if buffer_size == 0 {4096} else {buffer_size});
108
0
    Decompressor::<R>(DecompressorCustomAlloc::<R,
109
0
                                                <StandardAlloc
110
0
                                                 as Allocator<u8>>::AllocatedMemory,
111
0
                                                StandardAlloc,
112
0
                                                StandardAlloc,
113
0
                                                StandardAlloc>::new_with_custom_dictionary(r,
114
0
                                                                              buffer,
115
0
                                                                              alloc,
116
0
                                                                              StandardAlloc::default(),
117
0
                                                                              StandardAlloc::default(),
118
0
                                                                              dict))
119
0
  }
Unexecuted instantiation: <brotli_decompressor::reader::Decompressor<&[u8]>>::new_with_custom_dict
Unexecuted instantiation: <brotli_decompressor::reader::Decompressor<_>>::new_with_custom_dict
120
121
0
  pub fn get_ref(&self) -> &R {
122
0
    &self.0.get_ref()
123
0
  }
124
0
  pub fn get_mut(&mut self) -> &mut R {
125
0
    &mut ((self.0).0).get_mut().0
126
0
  }
127
0
  pub fn into_inner(self) -> R {
128
0
    self.0.into_inner()
129
0
  }
130
}
131
132
133
#[cfg(all(feature="unsafe", feature="std"))]
134
pub struct Decompressor<R: Read>(DecompressorCustomAlloc<R,
135
                                                         <HeapAlloc<u8>
136
                                                          as Allocator<u8>>::AllocatedMemory,
137
                                                         HeapAlloc<u8>,
138
                                                         HeapAlloc<u32>,
139
                                                         HeapAlloc<HuffmanCode> >);
140
141
142
#[cfg(all(feature="unsafe", feature="std"))]
143
impl<R: Read> Decompressor<R> {
144
  pub fn new(r: R, buffer_size: usize) -> Self {
145
     let dict = <HeapAlloc<u8> as Allocator<u8>>::AllocatedMemory::default();
146
     Self::new_with_custom_dictionary(r, buffer_size, dict)
147
  }
148
  pub fn new_with_custom_dictionary(r: R, buffer_size: usize, dict: <HeapAlloc<u8>
149
                                                 as Allocator<u8>>::AllocatedMemory) -> Self {
150
    let mut alloc_u8 = HeapAlloc::<u8>::new(0);
151
    let buffer = alloc_u8.alloc_cell(if buffer_size == 0 {4096} else {buffer_size});
152
    let alloc_u32 = HeapAlloc::<u32>::new(0);
153
    let alloc_hc = HeapAlloc::<HuffmanCode>::new(HuffmanCode{
154
        bits:0, value: 0,
155
    });
156
    Decompressor::<R>(DecompressorCustomAlloc::<R,
157
                                                <HeapAlloc<u8>
158
                                                 as Allocator<u8>>::AllocatedMemory,
159
                                                HeapAlloc<u8>,
160
                                                HeapAlloc<u32>,
161
                                                HeapAlloc<HuffmanCode> >
162
      ::new_with_custom_dictionary(r, buffer, alloc_u8, alloc_u32, alloc_hc, dict))
163
  }
164
165
  pub fn get_ref(&self) -> &R {
166
    self.0.get_ref()
167
  }
168
  pub fn get_mut(&mut self) -> &mut R {
169
    &mut (self.0).0.get_mut().0
170
  }
171
  pub fn into_inner(self) -> R {
172
    self.0.into_inner()
173
  }
174
}
175
176
177
#[cfg(feature="std")]
178
impl<R: Read> Read for Decompressor<R> {
179
0
  fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
180
0
    self.0.read(buf)
181
0
  }
Unexecuted instantiation: <brotli_decompressor::reader::Decompressor<&[u8]> as std::io::Read>::read
Unexecuted instantiation: <brotli_decompressor::reader::Decompressor<_> as std::io::Read>::read
182
}
183
184
pub struct DecompressorCustomIo<ErrType,
185
                                R: CustomRead<ErrType>,
186
                                BufferType: SliceWrapperMut<u8>,
187
                                AllocU8: Allocator<u8>,
188
                                AllocU32: Allocator<u32>,
189
                                AllocHC: Allocator<HuffmanCode>>
190
{
191
  input_buffer: BufferType,
192
  total_out: usize,
193
  input_offset: usize,
194
  input_len: usize,
195
  input: R,
196
  error_if_invalid_data: Option<ErrType>,
197
  state: BrotliState<AllocU8, AllocU32, AllocHC>,
198
  done: bool,
199
}
200
201
impl<ErrType,
202
     R: CustomRead<ErrType>,
203
     BufferType : SliceWrapperMut<u8>,
204
     AllocU8,
205
     AllocU32,
206
     AllocHC> DecompressorCustomIo<ErrType, R, BufferType, AllocU8, AllocU32, AllocHC>
207
 where AllocU8 : Allocator<u8>, AllocU32 : Allocator<u32>, AllocHC : Allocator<HuffmanCode>
208
{
209
210
0
    pub fn new(r: R, buffer : BufferType,
211
0
               alloc_u8 : AllocU8, alloc_u32 : AllocU32, alloc_hc : AllocHC,
212
0
               invalid_data_error_type : ErrType) -> Self {
213
0
     let dict = AllocU8::AllocatedMemory::default();
214
0
     Self::new_with_custom_dictionary(r, buffer, alloc_u8, alloc_u32, alloc_hc, dict, invalid_data_error_type)
215
0
    }
216
0
    pub fn new_with_custom_dictionary(r: R, buffer : BufferType,
217
0
               alloc_u8 : AllocU8, alloc_u32 : AllocU32, alloc_hc : AllocHC,
218
0
               dict: AllocU8::AllocatedMemory,
219
0
               invalid_data_error_type : ErrType) -> Self {
220
0
        DecompressorCustomIo::<ErrType, R, BufferType, AllocU8, AllocU32, AllocHC>{
221
0
            input_buffer : buffer,
222
0
            total_out : 0,
223
0
            input_offset : 0,
224
0
            input_len : 0,
225
0
            input: r,
226
0
            state : BrotliState::new_with_custom_dictionary(alloc_u8,
227
0
                                     alloc_u32,
228
0
                                     alloc_hc,
229
0
                                     dict),
230
0
            error_if_invalid_data : Some(invalid_data_error_type),
231
0
            done: false,
232
0
        }
233
0
    }
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomIo<std::io::error::Error, brotli_decompressor::io_wrappers::IntoIoReader<&[u8]>, alloc_stdlib::heap_alloc::WrapBox<u8>, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc>>::new_with_custom_dictionary
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomIo<_, _, _, _, _, _>>::new_with_custom_dictionary
234
235
0
    pub fn get_ref(&self) -> &R {
236
0
      &self.input
237
0
    }
238
0
    pub fn get_mut(&mut self) -> &mut R {
239
0
      &mut self.input
240
0
    }
241
0
    pub fn into_inner(self) -> R {
242
0
      match self {
243
        DecompressorCustomIo {
244
0
          input_buffer: _ib,
245
0
          total_out: _to,
246
0
          state: _state,
247
0
          input_offset: _io,
248
0
          input_len: _il,
249
0
          error_if_invalid_data:_eiid,
250
0
          input,
251
0
          done: _done,
252
        } =>{
253
0
          input
254
        }
255
    }
256
0
    }
257
258
0
    pub fn copy_to_front(&mut self) {
259
0
        let avail_in = self.input_len - self.input_offset;
260
0
        if self.input_offset == self.input_buffer.slice_mut().len() {
261
0
            self.input_offset = 0;
262
0
            self.input_len = 0;
263
0
        } else if self.input_offset + 256 > self.input_buffer.slice_mut().len() && avail_in < self.input_offset {
264
0
            let (first, second) = self.input_buffer.slice_mut().split_at_mut(self.input_offset);
265
0
            self.input_len -= self.input_offset;
266
0
            first[0..avail_in].clone_from_slice(&second[0..avail_in]);
267
0
            self.input_offset = 0;
268
0
        }
269
0
    }
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomIo<std::io::error::Error, brotli_decompressor::io_wrappers::IntoIoReader<&[u8]>, alloc_stdlib::heap_alloc::WrapBox<u8>, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc>>::copy_to_front
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomIo<_, _, _, _, _, _>>::copy_to_front
270
}
271
272
impl<ErrType,
273
     R: CustomRead<ErrType>,
274
     BufferType : SliceWrapperMut<u8>,
275
     AllocU8 : Allocator<u8>,
276
     AllocU32 : Allocator<u32>,
277
     AllocHC : Allocator<HuffmanCode> > CustomRead<ErrType> for DecompressorCustomIo<ErrType,
278
                                                                                     R,
279
                                                                                     BufferType,
280
                                                                                     AllocU8,
281
                                                                                     AllocU32,
282
                                                                                     AllocHC> {
283
  /// This variant of read will return Ok(number of bytes read) until the file
284
  /// Is completed at which point it will return Ok(0).
285
  /// However if there are additional unconsumed bytes in the buffer, it will
286
  /// return Err(InvalidData) at that point. Otherwise it will keep returning
287
  /// Ok(0).
288
  ///
289
  /// # Arguments
290
  ///
291
  /// * `buf` - The buffer to read into
292
  ///
293
  /// # Errors
294
  ///
295
  /// Returns Ok(0) if the file has been fully decompressed.
296
  /// If the file has been fully decompressed but there are additional
297
  /// non-brotli bytes in the buffer, then return an InvalidData error.
298
  /// Also upstream errors from the reader are returned.
299
0
  fn read(&mut self, buf: &mut [u8]) -> Result<usize, ErrType > {
300
0
    let mut output_offset : usize = 0;
301
0
    let mut avail_out = buf.len() - output_offset;
302
0
    let mut avail_in = self.input_len - self.input_offset;
303
0
    while avail_out == buf.len() {
304
0
      match BrotliDecompressStream(&mut avail_in,
305
0
                                   &mut self.input_offset,
306
0
                                   &self.input_buffer.slice_mut()[..],
307
0
                                   &mut avail_out,
308
0
                                   &mut output_offset,
309
0
                                   buf,
310
0
                                   &mut self.total_out,
311
0
                                   &mut self.state) {
312
        BrotliResult::NeedsMoreInput => {
313
0
          self.copy_to_front();
314
0
          if output_offset != 0 {
315
            // The decompressor successfully decoded some bytes, but still requires more
316
            // we do not wish to risk self.input.read returning an error, so instead we
317
            // opt to return what we have and do not invoke the read trait method
318
0
            return Ok(output_offset);
319
0
          }
320
0
          match self.input.read(&mut self.input_buffer.slice_mut()[self.input_len..]) {
321
0
            Err(e) => {
322
0
              return Err(e);
323
            },
324
0
            Ok(size) => if size == 0 {
325
0
              return self.error_if_invalid_data.take().map(|e| Err(e)).unwrap_or(Ok(0));
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomIo<std::io::error::Error, brotli_decompressor::io_wrappers::IntoIoReader<&[u8]>, alloc_stdlib::heap_alloc::WrapBox<u8>, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc> as brotli_decompressor::io_wrappers::CustomRead<std::io::error::Error>>::read::{closure#0}
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomIo<_, _, _, _, _, _> as brotli_decompressor::io_wrappers::CustomRead<_>>::read::{closure#0}
326
0
            }else {
327
0
              self.input_len += size;
328
0
              avail_in = self.input_len - self.input_offset;
329
0
            },
330
          }
331
        },
332
        BrotliResult::NeedsMoreOutput => {
333
0
          break;
334
        },
335
        BrotliResult::ResultSuccess => {
336
0
            if output_offset == 0 {
337
0
                if !self.done {
338
0
                    self.done = true;
339
0
                } else if self.input_len != self.input_offset {
340
                    // Did not consume entire input; report error.
341
0
                    return self.error_if_invalid_data.take().map(|e| Err(e)).unwrap_or(Ok(output_offset));
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomIo<std::io::error::Error, brotli_decompressor::io_wrappers::IntoIoReader<&[u8]>, alloc_stdlib::heap_alloc::WrapBox<u8>, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc> as brotli_decompressor::io_wrappers::CustomRead<std::io::error::Error>>::read::{closure#1}
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomIo<_, _, _, _, _, _> as brotli_decompressor::io_wrappers::CustomRead<_>>::read::{closure#1}
342
0
                }
343
0
            }
344
0
            return Ok(output_offset);
345
        }
346
0
        BrotliResult::ResultFailure => return self.error_if_invalid_data.take().map(|e| Err(e)).unwrap_or(Ok(0)),
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomIo<std::io::error::Error, brotli_decompressor::io_wrappers::IntoIoReader<&[u8]>, alloc_stdlib::heap_alloc::WrapBox<u8>, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc> as brotli_decompressor::io_wrappers::CustomRead<std::io::error::Error>>::read::{closure#2}
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomIo<_, _, _, _, _, _> as brotli_decompressor::io_wrappers::CustomRead<_>>::read::{closure#2}
347
      }
348
    }
349
0
    Ok(output_offset)
350
0
  }
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomIo<std::io::error::Error, brotli_decompressor::io_wrappers::IntoIoReader<&[u8]>, alloc_stdlib::heap_alloc::WrapBox<u8>, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc, alloc_stdlib::std_alloc::StandardAlloc> as brotli_decompressor::io_wrappers::CustomRead<std::io::error::Error>>::read
Unexecuted instantiation: <brotli_decompressor::reader::DecompressorCustomIo<_, _, _, _, _, _> as brotli_decompressor::io_wrappers::CustomRead<_>>::read
351
}
352
353
#[cfg(feature="std")]
354
#[test]
355
fn test_no_vanishing_bytes() {
356
    use std::string::ToString;
357
358
    // Output from this command:
359
    let compressed_with_extra = b"\x8f\x02\x80\x68\x65\x6c\x6c\x6f\x0a\x03\x67\x6f\x6f\x64\x62\x79\x65\x0a";
360
    // Make sure that read_to_string returns the data.
361
    let cursor = std::io::Cursor::new(compressed_with_extra);
362
    let mut reader = super::Decompressor::new(cursor, 8000);
363
    assert_eq!(std::io::read_to_string(&mut reader).unwrap(), "hello\n");
364
365
    // However you can call read extra times to make sure there's no data.
366
    let cursor = std::io::Cursor::new(compressed_with_extra);
367
    let mut reader = super::Decompressor::new(cursor, 8000);
368
    let mut data = std::vec::Vec::<u8>::default();
369
    loop {
370
        let mut buf = [0u8;5];
371
        let offset = reader.read(&mut buf).unwrap();
372
        if offset == 0 {
373
            break;
374
        }
375
        data.extend_from_slice(&buf[..offset]);
376
    }
377
    assert_eq!(
378
        &data,
379
        &['h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8, '\n' as u8]);
380
381
    // But calling read, one last time, results in an error because there
382
    // were leftover bytes in the buffer.
383
    let mut buf = [0u8;5];
384
    assert_eq!(reader.read(&mut buf).unwrap_err().kind(),
385
               io::ErrorKind::InvalidData);
386
    data.clear();
387
388
389
}
390
391
#[cfg(feature="std")]
392
#[test]
393
fn test_repeated_read_returns_zero() {
394
    use std::string::ToString;
395
396
    // Output from this command:
397
    let compressed_without_extra = b"\x8f\x02\x80\x68\x65\x6c\x6c\x6f\x0a\x03";
398
    // Make sure that read_to_string returns the data.
399
    let cursor = std::io::Cursor::new(compressed_without_extra);
400
    let mut reader = super::Decompressor::new(cursor, 8000);
401
    assert_eq!(std::io::read_to_string(&mut reader).unwrap(), "hello\n");
402
403
    // However you can call read extra times to make sure there's no data.
404
    let cursor = std::io::Cursor::new(compressed_without_extra);
405
    let mut reader = super::Decompressor::new(cursor, 8000);
406
    let mut data = std::vec::Vec::<u8>::default();
407
    loop {
408
        let mut buf = [0u8;5];
409
        let offset = reader.read(&mut buf).unwrap();
410
        if offset == 0 {
411
            break;
412
        }
413
        data.extend_from_slice(&buf[..offset]);
414
    }
415
    assert_eq!(&data, &['h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8, '\n' as u8]);
416
    let mut buf = [0u8;5];
417
    assert_eq!(reader.read(&mut buf).unwrap(), 0);
418
    data.clear();
419
420
421
}
422