@@ -989,6 +989,68 @@ impl<W: Write> Write for LineWriter<W> {
989
989
}
990
990
}
991
991
992
+ // Vectored writes are very similar to the writes above, but adjusted for
993
+ // the list of buffers that we have to write.
994
+ fn write_vectored ( & mut self , bufs : & [ IoSlice < ' _ > ] ) -> io:: Result < usize > {
995
+ if self . need_flush {
996
+ self . flush ( ) ?;
997
+ }
998
+
999
+ // Find the last newline, and failing that write the whole buffer
1000
+ let last_newline = bufs
1001
+ . iter ( )
1002
+ . enumerate ( )
1003
+ . rev ( )
1004
+ . filter_map ( |( i, buf) | {
1005
+ let pos = memchr:: memrchr ( b'\n' , buf) ?;
1006
+ Some ( ( i, pos) )
1007
+ } )
1008
+ . next ( ) ;
1009
+ let ( i, j) = match last_newline {
1010
+ Some ( pair) => pair,
1011
+ None => return self . inner . write_vectored ( bufs) ,
1012
+ } ;
1013
+ let ( prefix, suffix) = bufs. split_at ( i) ;
1014
+ let ( buf, suffix) = suffix. split_at ( 1 ) ;
1015
+ let buf = & buf[ 0 ] ;
1016
+
1017
+ // Write everything up to the last newline, flushing afterwards. Note
1018
+ // that only if we finished our entire `write_vectored` do we try the
1019
+ // subsequent
1020
+ // `write`
1021
+ let mut n = 0 ;
1022
+ let prefix_amt = prefix. iter ( ) . map ( |i| i. len ( ) ) . sum ( ) ;
1023
+ if prefix_amt > 0 {
1024
+ n += self . inner . write_vectored ( prefix) ?;
1025
+ self . need_flush = true ;
1026
+ }
1027
+ if n == prefix_amt {
1028
+ match self . inner . write ( & buf[ ..=j] ) {
1029
+ Ok ( m) => n += m,
1030
+ Err ( e) if n == 0 => return Err ( e) ,
1031
+ Err ( _) => return Ok ( n) ,
1032
+ }
1033
+ self . need_flush = true ;
1034
+ }
1035
+ if self . flush ( ) . is_err ( ) || n != j + 1 + prefix_amt {
1036
+ return Ok ( n) ;
1037
+ }
1038
+
1039
+ // ... and now write out everything remaining
1040
+ match self . inner . write ( & buf[ j + 1 ..] ) {
1041
+ Ok ( i) => n += i,
1042
+ Err ( _) => return Ok ( n) ,
1043
+ }
1044
+
1045
+ if suffix. iter ( ) . map ( |s| s. len ( ) ) . sum :: < usize > ( ) == 0 {
1046
+ return Ok ( n)
1047
+ }
1048
+ match self . inner . write_vectored ( suffix) {
1049
+ Ok ( i) => Ok ( n + i) ,
1050
+ Err ( _) => Ok ( n) ,
1051
+ }
1052
+ }
1053
+
992
1054
fn flush ( & mut self ) -> io:: Result < ( ) > {
993
1055
self . inner . flush ( ) ?;
994
1056
self . need_flush = false ;
@@ -1015,7 +1077,7 @@ where
1015
1077
#[ cfg( test) ]
1016
1078
mod tests {
1017
1079
use crate :: io:: prelude:: * ;
1018
- use crate :: io:: { self , BufReader , BufWriter , LineWriter , SeekFrom } ;
1080
+ use crate :: io:: { self , BufReader , BufWriter , LineWriter , SeekFrom , IoSlice } ;
1019
1081
use crate :: sync:: atomic:: { AtomicUsize , Ordering } ;
1020
1082
use crate :: thread;
1021
1083
@@ -1483,4 +1545,112 @@ mod tests {
1483
1545
1484
1546
assert_eq ! ( l. write( b"a" ) . unwrap_err( ) . kind( ) , io:: ErrorKind :: Other )
1485
1547
}
1548
+
1549
+ #[ test]
1550
+ fn line_vectored ( ) {
1551
+ let mut a = LineWriter :: new ( Vec :: new ( ) ) ;
1552
+ assert_eq ! (
1553
+ a. write_vectored( & [
1554
+ IoSlice :: new( & [ ] ) ,
1555
+ IoSlice :: new( b"\n " ) ,
1556
+ IoSlice :: new( & [ ] ) ,
1557
+ IoSlice :: new( b"a" ) ,
1558
+ ] )
1559
+ . unwrap( ) ,
1560
+ 2 ,
1561
+ ) ;
1562
+ assert_eq ! ( a. get_ref( ) , b"\n " ) ;
1563
+
1564
+ assert_eq ! (
1565
+ a. write_vectored( & [
1566
+ IoSlice :: new( & [ ] ) ,
1567
+ IoSlice :: new( b"b" ) ,
1568
+ IoSlice :: new( & [ ] ) ,
1569
+ IoSlice :: new( b"a" ) ,
1570
+ IoSlice :: new( & [ ] ) ,
1571
+ IoSlice :: new( b"c" ) ,
1572
+ ] )
1573
+ . unwrap( ) ,
1574
+ 3 ,
1575
+ ) ;
1576
+ assert_eq ! ( a. get_ref( ) , b"\n " ) ;
1577
+ a. flush ( ) . unwrap ( ) ;
1578
+ assert_eq ! ( a. get_ref( ) , b"\n abac" ) ;
1579
+ assert_eq ! ( a. write_vectored( & [ ] ) . unwrap( ) , 0 ) ;
1580
+ assert_eq ! (
1581
+ a. write_vectored( & [
1582
+ IoSlice :: new( & [ ] ) ,
1583
+ IoSlice :: new( & [ ] ) ,
1584
+ IoSlice :: new( & [ ] ) ,
1585
+ IoSlice :: new( & [ ] ) ,
1586
+ ] )
1587
+ . unwrap( ) ,
1588
+ 0 ,
1589
+ ) ;
1590
+ assert_eq ! ( a. write_vectored( & [ IoSlice :: new( b"a\n b" ) , ] ) . unwrap( ) , 3 ) ;
1591
+ assert_eq ! ( a. get_ref( ) , b"\n abaca\n " ) ;
1592
+ }
1593
+
1594
+ #[ test]
1595
+ fn line_vectored_partial_and_errors ( ) {
1596
+ enum Call {
1597
+ Write { inputs : Vec < & ' static [ u8 ] > , output : io:: Result < usize > } ,
1598
+ Flush { output : io:: Result < ( ) > } ,
1599
+ }
1600
+ struct Writer {
1601
+ calls : Vec < Call > ,
1602
+ }
1603
+
1604
+ impl Write for Writer {
1605
+ fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
1606
+ self . write_vectored ( & [ IoSlice :: new ( buf) ] )
1607
+ }
1608
+
1609
+ fn write_vectored ( & mut self , buf : & [ IoSlice < ' _ > ] ) -> io:: Result < usize > {
1610
+ match self . calls . pop ( ) . unwrap ( ) {
1611
+ Call :: Write { inputs, output } => {
1612
+ assert_eq ! ( inputs, buf. iter( ) . map( |b| & * * b) . collect:: <Vec <_>>( ) ) ;
1613
+ output
1614
+ }
1615
+ _ => panic ! ( "unexpected call to write" ) ,
1616
+ }
1617
+ }
1618
+
1619
+ fn flush ( & mut self ) -> io:: Result < ( ) > {
1620
+ match self . calls . pop ( ) . unwrap ( ) {
1621
+ Call :: Flush { output } => output,
1622
+ _ => panic ! ( "unexpected call to flush" ) ,
1623
+ }
1624
+ }
1625
+ }
1626
+
1627
+ impl Drop for Writer {
1628
+ fn drop ( & mut self ) {
1629
+ if !thread:: panicking ( ) {
1630
+ assert_eq ! ( self . calls. len( ) , 0 ) ;
1631
+ }
1632
+ }
1633
+ }
1634
+
1635
+ // partial writes keep going
1636
+ let mut a = LineWriter :: new ( Writer { calls : Vec :: new ( ) } ) ;
1637
+ a. write_vectored ( & [ IoSlice :: new ( & [ ] ) , IoSlice :: new ( b"abc" ) ] ) . unwrap ( ) ;
1638
+ a. get_mut ( ) . calls . push ( Call :: Flush { output : Ok ( ( ) ) } ) ;
1639
+ a. get_mut ( ) . calls . push ( Call :: Write { inputs : vec ! [ b"bcx\n " ] , output : Ok ( 4 ) } ) ;
1640
+ a. get_mut ( ) . calls . push ( Call :: Write { inputs : vec ! [ b"abcx\n " ] , output : Ok ( 1 ) } ) ;
1641
+ a. write_vectored ( & [ IoSlice :: new ( b"x" ) , IoSlice :: new ( b"\n " ) ] ) . unwrap ( ) ;
1642
+ a. get_mut ( ) . calls . push ( Call :: Flush { output : Ok ( ( ) ) } ) ;
1643
+ a. flush ( ) . unwrap ( ) ;
1644
+
1645
+ // erroneous writes stop and don't write more
1646
+ a. get_mut ( ) . calls . push ( Call :: Write { inputs : vec ! [ b"x\n " ] , output : Err ( err ( ) ) } ) ;
1647
+ assert_eq ! ( a. write_vectored( & [ IoSlice :: new( b"x" ) , IoSlice :: new( b"\n a" ) ] ) . unwrap( ) , 2 ) ;
1648
+ a. get_mut ( ) . calls . push ( Call :: Flush { output : Ok ( ( ) ) } ) ;
1649
+ a. get_mut ( ) . calls . push ( Call :: Write { inputs : vec ! [ b"x\n " ] , output : Ok ( 2 ) } ) ;
1650
+ a. flush ( ) . unwrap ( ) ;
1651
+
1652
+ fn err ( ) -> io:: Error {
1653
+ io:: Error :: new ( io:: ErrorKind :: Other , "x" )
1654
+ }
1655
+ }
1486
1656
}
0 commit comments