File tree 3 files changed +47
-17
lines changed
3 files changed +47
-17
lines changed Original file line number Diff line number Diff line change @@ -271,6 +271,20 @@ impl<R: Read> Read for BufReader<R> {
271
271
Ok ( nread)
272
272
}
273
273
274
+ // Small read_exacts from a BufReader are extremely common when used with a deserializer.
275
+ // The default implementation calls read in a loop, which results in surprisingly poor code
276
+ // generation for the common path where the buffer has enough bytes to fill the passed-in
277
+ // buffer.
278
+ fn read_exact ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < ( ) > {
279
+ if self . buffer ( ) . len ( ) >= buf. len ( ) {
280
+ buf. copy_from_slice ( & self . buffer ( ) [ ..buf. len ( ) ] ) ;
281
+ self . consume ( buf. len ( ) ) ;
282
+ return Ok ( ( ) ) ;
283
+ }
284
+
285
+ crate :: io:: default_read_exact ( self , buf)
286
+ }
287
+
274
288
fn read_vectored ( & mut self , bufs : & mut [ IoSliceMut < ' _ > ] ) -> io:: Result < usize > {
275
289
let total_len = bufs. iter ( ) . map ( |b| b. len ( ) ) . sum :: < usize > ( ) ;
276
290
if self . pos == self . cap && total_len >= self . buf . len ( ) {
Original file line number Diff line number Diff line change @@ -443,6 +443,18 @@ fn bench_buffered_reader(b: &mut test::Bencher) {
443
443
b. iter ( || BufReader :: new ( io:: empty ( ) ) ) ;
444
444
}
445
445
446
+ #[ bench]
447
+ fn bench_buffered_reader_small_reads ( b : & mut test:: Bencher ) {
448
+ let data = ( 0 ..u8:: MAX ) . cycle ( ) . take ( 1024 * 4 ) . collect :: < Vec < _ > > ( ) ;
449
+ b. iter ( || {
450
+ let mut reader = BufReader :: new ( & data[ ..] ) ;
451
+ let mut buf = [ 0u8 ; 4 ] ;
452
+ for _ in 0 ..1024 {
453
+ reader. read_exact ( & mut buf) . unwrap ( ) ;
454
+ }
455
+ } ) ;
456
+ }
457
+
446
458
#[ bench]
447
459
fn bench_buffered_writer ( b : & mut test:: Bencher ) {
448
460
b. iter ( || BufWriter :: new ( io:: sink ( ) ) ) ;
Original file line number Diff line number Diff line change @@ -416,6 +416,25 @@ where
416
416
write ( buf)
417
417
}
418
418
419
+ pub ( crate ) fn default_read_exact < R : Read + ?Sized > ( this : & mut R , mut buf : & mut [ u8 ] ) -> Result < ( ) > {
420
+ while !buf. is_empty ( ) {
421
+ match this. read ( buf) {
422
+ Ok ( 0 ) => break ,
423
+ Ok ( n) => {
424
+ let tmp = buf;
425
+ buf = & mut tmp[ n..] ;
426
+ }
427
+ Err ( ref e) if e. kind ( ) == ErrorKind :: Interrupted => { }
428
+ Err ( e) => return Err ( e) ,
429
+ }
430
+ }
431
+ if !buf. is_empty ( ) {
432
+ Err ( Error :: new ( ErrorKind :: UnexpectedEof , "failed to fill whole buffer" ) )
433
+ } else {
434
+ Ok ( ( ) )
435
+ }
436
+ }
437
+
419
438
/// The `Read` trait allows for reading bytes from a source.
420
439
///
421
440
/// Implementors of the `Read` trait are called 'readers'.
@@ -766,23 +785,8 @@ pub trait Read {
766
785
/// }
767
786
/// ```
768
787
#[ stable( feature = "read_exact" , since = "1.6.0" ) ]
769
- fn read_exact ( & mut self , mut buf : & mut [ u8 ] ) -> Result < ( ) > {
770
- while !buf. is_empty ( ) {
771
- match self . read ( buf) {
772
- Ok ( 0 ) => break ,
773
- Ok ( n) => {
774
- let tmp = buf;
775
- buf = & mut tmp[ n..] ;
776
- }
777
- Err ( ref e) if e. kind ( ) == ErrorKind :: Interrupted => { }
778
- Err ( e) => return Err ( e) ,
779
- }
780
- }
781
- if !buf. is_empty ( ) {
782
- Err ( Error :: new ( ErrorKind :: UnexpectedEof , "failed to fill whole buffer" ) )
783
- } else {
784
- Ok ( ( ) )
785
- }
788
+ fn read_exact ( & mut self , buf : & mut [ u8 ] ) -> Result < ( ) > {
789
+ default_read_exact ( self , buf)
786
790
}
787
791
788
792
/// Creates a "by reference" adaptor for this instance of `Read`.
You can’t perform that action at this time.
0 commit comments