1+ ///! An encapsulation of `BufReader`'s buffer management logic.
2+ ///
3+ /// This module factors out the basic functionality of `BufReader` in order to protect two core
4+ /// invariants:
5+ /// * `filled` bytes of `buf` are always initialized
6+ /// * `pos` is always <= `filled`
7+ /// Since this module encapsulates the buffer management logic, we can ensure that the range
8+ /// `pos..filled` is always a valid index into the initialized region of the buffer. This means
9+ /// that user code which wants to do reads from a `BufReader` via `buffer` + `consume` can do so
10+ /// without encountering any runtime bounds checks.
111use crate :: cmp;
212use crate :: io:: { self , Read , ReadBuf } ;
313use crate :: mem:: MaybeUninit ;
414
515pub struct Buffer {
16+ // The buffer.
617 buf : Box < [ MaybeUninit < u8 > ] > ,
18+ // The current seek offset into `buf`, must always be <= `filled`.
719 pos : usize ,
8- cap : usize ,
9- init : usize ,
20+ // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are
21+ // initialized with bytes from a read.
22+ filled : usize ,
1023}
1124
1225impl Buffer {
1326 #[ inline]
1427 pub fn with_capacity ( capacity : usize ) -> Self {
1528 let buf = Box :: new_uninit_slice ( capacity) ;
16- Self { buf, pos : 0 , cap : 0 , init : 0 }
29+ Self { buf, pos : 0 , filled : 0 }
1730 }
1831
1932 #[ inline]
2033 pub fn buffer ( & self ) -> & [ u8 ] {
21- // SAFETY: self.cap is always <= self.init, so self.buf[self.pos..self.cap] is always init
22- // Additionally, both self.pos and self.cap are valid and and self.cap => self.pos, and
34+ // SAFETY: self.pos and self.cap are valid, and self.cap => self.pos, and
2335 // that region is initialized because those are all invariants of this type.
24- unsafe { MaybeUninit :: slice_assume_init_ref ( & self . buf . get_unchecked ( self . pos ..self . cap ) ) }
36+ unsafe { MaybeUninit :: slice_assume_init_ref ( self . buf . get_unchecked ( self . pos ..self . filled ) ) }
2537 }
2638
2739 #[ inline]
@@ -30,8 +42,8 @@ impl Buffer {
3042 }
3143
3244 #[ inline]
33- pub fn cap ( & self ) -> usize {
34- self . cap
45+ pub fn filled ( & self ) -> usize {
46+ self . filled
3547 }
3648
3749 #[ inline]
@@ -42,12 +54,12 @@ impl Buffer {
4254 #[ inline]
4355 pub fn discard_buffer ( & mut self ) {
4456 self . pos = 0 ;
45- self . cap = 0 ;
57+ self . filled = 0 ;
4658 }
4759
4860 #[ inline]
4961 pub fn consume ( & mut self , amt : usize ) {
50- self . pos = cmp:: min ( self . pos + amt, self . cap ) ;
62+ self . pos = cmp:: min ( self . pos + amt, self . filled ) ;
5163 }
5264
5365 #[ inline]
@@ -58,25 +70,17 @@ impl Buffer {
5870 #[ inline]
5971 pub fn fill_buf ( & mut self , mut reader : impl Read ) -> io:: Result < & [ u8 ] > {
6072 // If we've reached the end of our internal buffer then we need to fetch
61- // some more data from the underlying reader.
73+ // some more data from the reader.
6274 // Branch using `>=` instead of the more correct `==`
6375 // to tell the compiler that the pos..cap slice is always valid.
64- if self . pos >= self . cap {
65- debug_assert ! ( self . pos == self . cap ) ;
76+ if self . pos >= self . filled {
77+ debug_assert ! ( self . pos == self . filled ) ;
6678
6779 let mut readbuf = ReadBuf :: uninit ( & mut self . buf ) ;
6880
69- // SAFETY: `self.init` is either 0 or set to `readbuf.initialized_len()`
70- // from the last time this function was called
71- unsafe {
72- readbuf. assume_init ( self . init ) ;
73- }
74-
7581 reader. read_buf ( & mut readbuf) ?;
7682
77- self . cap = readbuf. filled_len ( ) ;
78- self . init = readbuf. initialized_len ( ) ;
79-
83+ self . filled = readbuf. filled_len ( ) ;
8084 self . pos = 0 ;
8185 }
8286 Ok ( self . buffer ( ) )
0 commit comments