I've a situation where I have a destination Vec
to which I want to push exactly n
bytes I read from a Read
object.
Read
, however, generally deals with slices. The only method which uses Vec
is read_to_end
, but I need to "bound" the reading to only n
bytes.
So far I can see 3 ways to implement this, but I'm not sure if I'm missing something, or which one is the best (or at least the least bad): playground
use read_to_end
anyway
This is the shortest by far, but it also involves the most stdlib understanding, and I'm not sure I grasp the semantics completely / correctly:
fn read1<T: Read>(mut reader: T, n: usize, sink: &mut Vec<u8>) -> Result<()> {
reader.take(n as u64).read_to_end(sink)?;
Ok(())
}
If this were not a utility function I think by_ref
would also be useful in order to not consume the source reader?
extend the Vec
and read into that buffer
This is way more involved and has the issue that we're adding completely invalid data to the Vec
in order to have a proper "slice" to read into:
fn read2<T: Read>(mut reader: T, n: usize, sink: &mut Vec<u8>) -> Result<()> {
let before = sink.len();
let after = sink.len() + n;
sink.resize(after, 0);
if let Err(e) = reader.read_exact(&mut sink[before..after]) {
sink.resize(before, 0);
return Err(e.into());
}
Ok(())
}
This assumes read_exact
and resize
(down) don't panic.
use a local buffer
This is the most simplistic and complicated: repeatedly read data into a local buffer, then copy from the local buffer into the output vec.
fn read3<T: Read>(mut reader: T, mut n: usize, sink: &mut Vec<u8>) -> Result<()> {
let before = sink.len();
let mut buf = [0;64];
while n > 0 {
let b = &mut buf[0..min(64, n)];
if let Err(e) = reader.read_exact(b) {
sink.resize(before, 0);
return Err(e.into());
}
sink.extend(&*b);
n -= b.len();
}
Ok(())
}
It's what I'd do in a lower level language but it fells icky. Compared to version 2 it does add data to the output vec which we may need to strip out (I elected to do this here but there may be case where that's unnecessary), but unlike solution 2 while it adds partial data to the vec it's valid data.