33#![ cfg_attr( not( doc) , no_std) ]
44#![ feature( doc_cfg) ]
55#![ feature( core_io_borrowed_buf) ]
6+ #![ cfg_attr( not( borrowedbuf_init) , feature( maybe_uninit_fill) ) ]
67
78#[ cfg( feature = "alloc" ) ]
89extern crate alloc;
@@ -67,6 +68,11 @@ pub fn default_read_to_end<R: Read + ?Sized>(
6768 }
6869 }
6970
71+ #[ cfg( borrowedbuf_init) ]
72+ let mut initialized = 0 ; // Extra initialized bytes from previous loop iteration
73+ #[ cfg( borrowedbuf_init) ]
74+ let mut consecutive_short_reads = 0 ;
75+
7076 loop {
7177 if buf. len ( ) == buf. capacity ( ) && buf. capacity ( ) == start_cap {
7278 // The buffer might be an exact fit. Let's read into a probe buffer
@@ -92,15 +98,35 @@ pub fn default_read_to_end<R: Read + ?Sized>(
9298 spare = & mut spare[ ..buf_len] ;
9399 let mut read_buf: BorrowedBuf < ' _ > = spare. into ( ) ;
94100
101+ #[ cfg( borrowedbuf_init) ]
102+ // SAFETY: These bytes were initialized but not filled in the previous loop
103+ unsafe {
104+ read_buf. set_init ( initialized) ;
105+ }
106+
95107 let mut cursor = read_buf. unfilled ( ) ;
96108 // Difference from `std`: We don't have a `read_buf` method that returns both data and an error, so we return early on error.
97- let n = r . read ( unsafe { cursor . as_mut ( ) . assume_init_mut ( ) } ) ? ;
98- assert ! ( n <= cursor . capacity ( ) ) ;
99- unsafe {
109+ # [ cfg ( borrowedbuf_init ) ]
110+ {
111+ let n = r . read ( cursor . ensure_init ( ) . init_mut ( ) ) ? ;
100112 cursor. advance ( n) ;
101113 }
114+ #[ cfg( not( borrowedbuf_init) ) ]
115+ {
116+ // SAFETY: We do not uninitialize any part of the buffer.
117+ let n = r. read ( unsafe { cursor. as_mut ( ) . write_filled ( 0 ) } ) ?;
118+ assert ! ( n <= cursor. capacity( ) ) ;
119+ // SAFETY: We've initialized the entire buffer, and `read` can't make it uninitialized.
120+ unsafe {
121+ cursor. advance ( n) ;
122+ }
123+ }
102124
125+ #[ cfg( borrowedbuf_init) ]
126+ let unfilled_but_initialized = cursor. init_mut ( ) . len ( ) ;
103127 let bytes_read = cursor. written ( ) ;
128+ #[ cfg( borrowedbuf_init) ]
129+ let was_fully_initialized = read_buf. init_len ( ) == buf_len;
104130
105131 // SAFETY: BorrowedBuf's invariants mean this much memory is initialized.
106132 unsafe {
@@ -112,8 +138,32 @@ pub fn default_read_to_end<R: Read + ?Sized>(
112138 return Ok ( buf. len ( ) - start_len) ;
113139 }
114140
141+ #[ cfg( borrowedbuf_init) ]
142+ if bytes_read < buf_len {
143+ consecutive_short_reads += 1 ;
144+ } else {
145+ consecutive_short_reads = 0 ;
146+ }
147+
148+ #[ cfg( borrowedbuf_init) ]
149+ {
150+ // store how much was initialized but not filled
151+ initialized = unfilled_but_initialized;
152+ }
153+
115154 // Use heuristics to determine the max read size if no initial size hint was provided
116155 if size_hint. is_none ( ) {
156+ #[ cfg( borrowedbuf_init) ]
157+ // The reader is returning short reads but it doesn't call ensure_init().
158+ // In that case we no longer need to restrict read sizes to avoid
159+ // initialization costs.
160+ // When reading from disk we usually don't get any short reads except at EOF.
161+ // So we wait for at least 2 short reads before uncapping the read buffer;
162+ // this helps with the Windows issue.
163+ if !was_fully_initialized && consecutive_short_reads > 1 {
164+ max_read_size = usize:: MAX ;
165+ }
166+
117167 // we have passed a larger buffer than previously and the
118168 // reader still hasn't returned a short read
119169 if buf_len >= max_read_size && bytes_read == buf_len {
0 commit comments