@@ -20,13 +20,19 @@ pub struct Buffer {
2020 // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are
2121 // initialized with bytes from a read.
2222 filled : usize ,
23+ // This is the max number of bytes returned across all `fill_buf` calls. We track this so that we
24+ // can accurately tell `read_buf` how many bytes of buf are initialized, to bypass as much of its
25+ // defensive initialization as possible. Note that while this often the same as `filled`, it
26+ // doesn't need to be. Calls to `fill_buf` are not required to actually fill the buffer, and
27+ // omitting this is a huge perf regression for `Read` impls that do not.
28+ initialized : usize ,
2329}
2430
2531impl Buffer {
2632 #[ inline]
2733 pub fn with_capacity ( capacity : usize ) -> Self {
2834 let buf = Box :: new_uninit_slice ( capacity) ;
29- Self { buf, pos : 0 , filled : 0 }
35+ Self { buf, pos : 0 , filled : 0 , initialized : 0 }
3036 }
3137
3238 #[ inline]
@@ -51,6 +57,12 @@ impl Buffer {
5157 self . pos
5258 }
5359
60+ // This is only used by a test which asserts that the initialization-tracking is correct.
61+ #[ cfg( test) ]
62+ pub fn initialized ( & self ) -> usize {
63+ self . initialized
64+ }
65+
5466 #[ inline]
5567 pub fn discard_buffer ( & mut self ) {
5668 self . pos = 0 ;
@@ -96,13 +108,14 @@ impl Buffer {
96108 let mut buf = BorrowedBuf :: from ( & mut * self . buf ) ;
97109 // SAFETY: `self.filled` bytes will always have been initialized.
98110 unsafe {
99- buf. set_init ( self . filled ) ;
111+ buf. set_init ( self . initialized ) ;
100112 }
101113
102114 reader. read_buf ( buf. unfilled ( ) ) ?;
103115
104- self . filled = buf. len ( ) ;
105116 self . pos = 0 ;
117+ self . filled = buf. len ( ) ;
118+ self . initialized = buf. init_len ( ) ;
106119 }
107120 Ok ( self . buffer ( ) )
108121 }
0 commit comments