@@ -448,6 +448,9 @@ impl<R: Seek> Seek for BufReader<R> {
448
448
/// [`flush`]: #method.flush
449
449
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
450
450
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.
451
454
inner : Option < W > ,
452
455
// FIXME: Replace this with a VecDeque. Because VecDeque is a Ring buffer,
453
456
// this would enable BufWriter to operate without any interior copies.
@@ -533,32 +536,62 @@ impl<W: Write> BufWriter<W> {
533
536
/// `write`), any 0-length writes from `inner` must be reported as i/o
534
537
/// errors from this method.
535
538
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 ( ) {
540
578
self . panicked = true ;
541
- let r = self . inner . as_mut ( ) . unwrap ( ) . write ( & self . buf [ written.. ] ) ;
579
+ let r = inner. write ( guard . remaining ( ) ) ;
542
580
self . panicked = false ;
543
581
544
582
match r {
545
583
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
+ ) )
549
588
}
550
- Ok ( n) => written += n ,
589
+ Ok ( n) => guard . consume ( n ) ,
551
590
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) ,
556
592
}
557
593
}
558
- if written > 0 {
559
- self . buf . drain ( ..written) ;
560
- }
561
- ret
594
+ Ok ( ( ) )
562
595
}
563
596
564
597
/// Buffer some data without flushing it, regardless of the size of the
0 commit comments