@@ -1923,6 +1923,28 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) -> R
19231923 }
19241924}
19251925
1926+ fn skip_until < R : BufRead + ?Sized > ( r : & mut R , delim : u8 ) -> Result < usize > {
1927+ let mut read = 0 ;
1928+ loop {
1929+ let ( done, used) = {
1930+ let available = match r. fill_buf ( ) {
1931+ Ok ( n) => n,
1932+ Err ( ref e) if e. kind ( ) == ErrorKind :: Interrupted => continue ,
1933+ Err ( e) => return Err ( e) ,
1934+ } ;
1935+ match memchr:: memchr ( delim, available) {
1936+ Some ( i) => ( true , i + 1 ) ,
1937+ None => ( false , available. len ( ) ) ,
1938+ }
1939+ } ;
1940+ r. consume ( used) ;
1941+ read += used;
1942+ if done || used == 0 {
1943+ return Ok ( read) ;
1944+ }
1945+ }
1946+ }
1947+
19261948/// A `BufRead` is a type of `Read`er which has an internal buffer, allowing it
19271949/// to perform extra ways of reading.
19281950///
@@ -2126,6 +2148,68 @@ pub trait BufRead: Read {
21262148 read_until ( self , byte, buf)
21272149 }
21282150
2151+ /// Skip all bytes until the delimiter `byte` or EOF is reached.
2152+ ///
2153+ /// This function will read (and discard) bytes from the underlying stream until the
2154+ /// delimiter or EOF is found.
2155+ ///
2156+ /// If successful, this function will return the total number of bytes read,
2157+ /// including the delimiter byte.
2158+ ///
2159+ /// This is useful for efficiently skipping data such as NUL-terminated strings
2160+ /// in binary file formats without buffering.
2161+ ///
2162+ /// This function is blocking and should be used carefully: it is possible for
2163+ /// an attacker to continuously send bytes without ever sending the delimiter
2164+ /// or EOF.
2165+ ///
2166+ /// # Errors
2167+ ///
2168+ /// This function will ignore all instances of [`ErrorKind::Interrupted`] and
2169+ /// will otherwise return any errors returned by [`fill_buf`].
2170+ ///
2171+ /// If an I/O error is encountered then all bytes read so far will be
2172+ /// present in `buf` and its length will have been adjusted appropriately.
2173+ ///
2174+ /// [`fill_buf`]: BufRead::fill_buf
2175+ ///
2176+ /// # Examples
2177+ ///
2178+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
2179+ /// this example, we use [`Cursor`] to read some NUL-terminated information
2180+ /// about Ferris from a binary string, skipping the fun fact:
2181+ ///
2182+ /// ```
2183+ /// #![feature(bufread_skip_until)]
2184+ ///
2185+ /// use std::io::{self, BufRead};
2186+ ///
2187+ /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0");
2188+ ///
2189+ /// // read name
2190+ /// let mut name = Vec::new();
2191+ /// let num_bytes = cursor.read_until(b'\0', &mut name)
2192+ /// .expect("reading from cursor won't fail");
2193+ /// assert_eq!(num_bytes, 7);
2194+ /// assert_eq!(name, b"Ferris\0");
2195+ ///
2196+ /// // skip fun fact
2197+ /// let num_bytes = cursor.skip_until(b'\0')
2198+ /// .expect("reading from cursor won't fail");
2199+ /// assert_eq!(num_bytes, 30);
2200+ ///
2201+ /// // read animal type
2202+ /// let mut animal = Vec::new();
2203+ /// let num_bytes = cursor.read_until(b'\0', &mut animal)
2204+ /// .expect("reading from cursor won't fail");
2205+ /// assert_eq!(num_bytes, 11);
2206+ /// assert_eq!(animal, b"Crustacean\0");
2207+ /// ```
2208+ #[ unstable( feature = "bufread_skip_until" , issue = "none" ) ]
2209+ fn skip_until ( & mut self , byte : u8 ) -> Result < usize > {
2210+ skip_until ( self , byte)
2211+ }
2212+
21292213 /// Read all bytes until a newline (the `0xA` byte) is reached, and append
21302214 /// them to the provided buffer. You do not need to clear the buffer before
21312215 /// appending.
0 commit comments