66
77use std:: io;
88use std:: io:: IoSlice ;
9+ use std:: mem:: MaybeUninit ;
910use std:: pin:: Pin ;
1011use std:: task:: { Context , Poll , ready} ;
1112
@@ -20,7 +21,7 @@ pin_project! {
2021 pub struct FlexBufReader <R > {
2122 #[ pin]
2223 inner: R ,
23- buf: Box <[ u8 ] >,
24+ buf: Box <[ MaybeUninit < u8 > ] >,
2425 pos: usize ,
2526 cap: usize ,
2627 }
@@ -35,7 +36,12 @@ impl<R> FlexBufReader<R> {
3536
3637 /// Creates a new `BufReader` with the specified buffer capacity.
3738 pub fn with_capacity ( capacity : usize , inner : R ) -> Self {
38- Self :: with_buffer ( vec ! [ 0 ; capacity] , 0 , inner)
39+ Self {
40+ inner,
41+ buf : Box :: new_uninit_slice ( capacity) ,
42+ pos : 0 ,
43+ cap : 0 ,
44+ }
3945 }
4046
4147 /// Creates a new `BufReader` with BytesMut
@@ -45,15 +51,27 @@ impl<R> FlexBufReader<R> {
4551 Self :: with_buffer ( vec, len, inner)
4652 }
4753
48- /// Creates a new `BufReader` with a existed buffer
49- pub fn with_buffer ( mut buffer : Vec < u8 > , len : usize , inner : R ) -> Self {
50- unsafe {
51- // safe here as we didn't use the uninitialized data
52- buffer. set_len ( buffer. capacity ( ) )
54+ /// Creates a new `BufReader` with an existing buffer.
55+ ///
56+ /// The first `len` bytes of `buffer` are treated as initialized; any spare
57+ /// capacity becomes uninitialized space for later reads via [`ReadBuf::uninit`].
58+ pub fn with_buffer ( buffer : Vec < u8 > , len : usize , inner : R ) -> Self {
59+ let len = len. min ( buffer. len ( ) ) ;
60+ let mut buffer = buffer;
61+ buffer. truncate ( len) ;
62+ let ( ptr, init_len, capacity) = buffer. into_raw_parts ( ) ;
63+ debug_assert_eq ! ( init_len, len) ;
64+ // SAFETY: `into_raw_parts` yields `init_len` initialized bytes and spare
65+ // capacity that we expose as `MaybeUninit`. Ownership moves into `Box`.
66+ let buf = unsafe {
67+ Box :: from_raw ( std:: ptr:: slice_from_raw_parts_mut (
68+ ptr as * mut MaybeUninit < u8 > ,
69+ capacity,
70+ ) )
5371 } ;
5472 Self {
5573 inner,
56- buf : buffer . into_boxed_slice ( ) ,
74+ buf,
5775 pos : 0 ,
5876 cap : len,
5977 }
@@ -86,8 +104,14 @@ impl<R> FlexBufReader<R> {
86104
87105 pub fn into_parts ( self ) -> ( Bytes , R ) {
88106 if self . pos < self . cap {
89- let mut bytes = Bytes :: from ( self . buf ) ;
90- let _ = bytes. split_off ( self . cap ) ;
107+ // SAFETY: `buf[..cap]` was initialized by `with_buffer` and/or
108+ // `ReadBuf::uninit` fills; spare capacity beyond `cap` stays unused.
109+ let vec = unsafe {
110+ let capacity = self . buf . len ( ) ;
111+ let ptr = Box :: into_raw ( self . buf ) as * mut u8 ;
112+ Vec :: from_raw_parts ( ptr, self . cap , capacity)
113+ } ;
114+ let mut bytes = Bytes :: from ( vec) ;
91115 bytes. advance ( self . pos ) ;
92116 ( bytes, self . inner )
93117 } else {
@@ -99,7 +123,8 @@ impl<R> FlexBufReader<R> {
99123 ///
100124 /// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty.
101125 pub fn buffer ( & self ) -> & [ u8 ] {
102- & self . buf [ self . pos ..self . cap ]
126+ // SAFETY: `pos..cap` is always initialized (constructor or last fill).
127+ unsafe { self . buf [ self . pos ..self . cap ] . assume_init_ref ( ) }
103128 }
104129
105130 /// Invalidates all data in the internal buffer.
@@ -143,12 +168,13 @@ impl<R: AsyncRead> AsyncBufRead for FlexBufReader<R> {
143168 // to tell the compiler that the pos..cap slice is always valid.
144169 if * me. pos >= * me. cap {
145170 debug_assert ! ( * me. pos == * me. cap) ;
146- let mut buf = ReadBuf :: new ( me. buf ) ;
171+ let mut buf = ReadBuf :: uninit ( me. buf ) ;
147172 ready ! ( me. inner. poll_read( cx, & mut buf) ) ?;
148173 * me. cap = buf. filled ( ) . len ( ) ;
149174 * me. pos = 0 ;
150175 }
151- Poll :: Ready ( Ok ( & me. buf [ * me. pos ..* me. cap ] ) )
176+ // SAFETY: `pos..cap` is initialized by the fill above or by construction.
177+ Poll :: Ready ( Ok ( unsafe { me. buf [ * me. pos ..* me. cap ] . assume_init_ref ( ) } ) )
152178 }
153179
154180 fn consume ( self : Pin < & mut Self > , amt : usize ) {
@@ -257,4 +283,14 @@ mod tests {
257283 restored. read_to_end ( & mut out) . await . unwrap ( ) ;
258284 assert_eq ! ( out, b"prefrest" ) ;
259285 }
286+
287+ #[ tokio:: test]
288+ async fn with_capacity_reads_without_prior_zeroing ( ) {
289+ let content = b"hello uninit" ;
290+ let stream = tokio_test:: io:: Builder :: new ( ) . read ( content) . build ( ) ;
291+ let mut v = FlexBufReader :: with_capacity ( 64 , stream) ;
292+ let mut out = Vec :: new ( ) ;
293+ v. read_to_end ( & mut out) . await . unwrap ( ) ;
294+ assert_eq ! ( out, content) ;
295+ }
260296}
0 commit comments