Skip to content

Commit 338a2c0

Browse files
committed
Reimplement flush_buf with a Guard. Longer, but cleaner.
1 parent 7a6a12b commit 338a2c0

File tree

1 file changed

+50
-17
lines changed

1 file changed

+50
-17
lines changed

src/libstd/io/buffered.rs

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,9 @@ impl<R: Seek> Seek for BufReader<R> {
448448
/// [`flush`]: #method.flush
449449
#[stable(feature = "rust1", since = "1.0.0")]
450450
pub struct BufWriter<W: Write> {
451+
// FIXME: Can this just be W, instead of Option<W>? I don't see any code
452+
// paths that lead to this being None, or that ever check if it IS none,
453+
// even in drop implementations.
451454
inner: Option<W>,
452455
// FIXME: Replace this with a VecDeque. Because VecDeque is a Ring buffer,
453456
// this would enable BufWriter to operate without any interior copies.
@@ -533,32 +536,62 @@ impl<W: Write> BufWriter<W> {
533536
/// `write`), any 0-length writes from `inner` must be reported as i/o
534537
/// errors from this method.
535538
fn flush_buf(&mut self) -> io::Result<()> {
536-
let mut written = 0;
537-
let len = self.buf.len();
538-
let mut ret = Ok(());
539-
while written < len {
539+
/// Helper struct to ensure the buffer is updated after all the writes
540+
/// are complete
541+
struct BufGuard<'a> {
542+
buffer: &'a mut Vec<u8>,
543+
written: usize,
544+
}
545+
546+
impl<'a> BufGuard<'a> {
547+
fn new(buffer: &'a mut Vec<u8>) -> Self {
548+
Self { buffer, written: 0 }
549+
}
550+
551+
/// The unwritten part of the buffer
552+
fn remaining(&self) -> &[u8] {
553+
&self.buffer[self.written..]
554+
}
555+
556+
/// Flag some bytes as removed from the front of the buffer
557+
fn consume(&mut self, amt: usize) {
558+
self.written += amt;
559+
}
560+
561+
/// true if all of the bytes have been written
562+
fn done(&self) -> bool {
563+
self.written >= self.buffer.len()
564+
}
565+
}
566+
567+
impl Drop for BufGuard<'_> {
568+
fn drop(&mut self) {
569+
if self.written > 0 {
570+
self.buffer.drain(..self.written);
571+
}
572+
}
573+
}
574+
575+
let mut guard = BufGuard::new(&mut self.buf);
576+
let inner = self.inner.as_mut().unwrap();
577+
while !guard.done() {
540578
self.panicked = true;
541-
let r = self.inner.as_mut().unwrap().write(&self.buf[written..]);
579+
let r = inner.write(guard.remaining());
542580
self.panicked = false;
543581

544582
match r {
545583
Ok(0) => {
546-
ret =
547-
Err(Error::new(ErrorKind::WriteZero, "failed to write the buffered data"));
548-
break;
584+
return Err(Error::new(
585+
ErrorKind::WriteZero,
586+
"failed to write the buffered data",
587+
))
549588
}
550-
Ok(n) => written += n,
589+
Ok(n) => guard.consume(n),
551590
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
552-
Err(e) => {
553-
ret = Err(e);
554-
break;
555-
}
591+
Err(e) => return Err(e),
556592
}
557593
}
558-
if written > 0 {
559-
self.buf.drain(..written);
560-
}
561-
ret
594+
Ok(())
562595
}
563596

564597
/// Buffer some data without flushing it, regardless of the size of the

0 commit comments

Comments
 (0)