@@ -194,6 +194,31 @@ impl<R: Read> BufReader<R> {
194
194
pub fn into_inner ( self ) -> R { self . inner }
195
195
}
196
196
197
+ impl < R : Seek > BufReader < R > {
198
+ /// Seeks relative to the current position. If the new position lies within the buffer,
199
+ /// the buffer will not be flushed, allowing for more efficient seeks.
200
+ /// This method does not return the location of the underlying reader, so the caller
201
+ /// must track this information themselves if it is required.
202
+ #[ unstable( feature = "bufreader_seek_relative" , issue = "31100" ) ]
203
+ pub fn seek_relative ( & mut self , offset : i64 ) -> io:: Result < ( ) > {
204
+ let pos = self . pos as u64 ;
205
+ if offset < 0 {
206
+ if let Some ( new_pos) = pos. checked_sub ( ( -offset) as u64 ) {
207
+ self . pos = new_pos as usize ;
208
+ return Ok ( ( ) )
209
+ }
210
+ } else {
211
+ if let Some ( new_pos) = pos. checked_add ( offset as u64 ) {
212
+ if new_pos <= self . cap as u64 {
213
+ self . pos = new_pos as usize ;
214
+ return Ok ( ( ) )
215
+ }
216
+ }
217
+ }
218
+ self . seek ( SeekFrom :: Current ( offset) ) . map ( |_|( ) )
219
+ }
220
+ }
221
+
197
222
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
198
223
impl < R : Read > Read for BufReader < R > {
199
224
fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
@@ -260,13 +285,17 @@ impl<R: Seek> Seek for BufReader<R> {
260
285
/// `.into_inner()` immediately after a seek yields the underlying reader
261
286
/// at the same position.
262
287
///
288
+ /// To seek without discarding the internal buffer, use [`seek_relative`].
289
+ ///
263
290
/// See `std::io::Seek` for more details.
264
291
///
265
292
/// Note: In the edge case where you're seeking with `SeekFrom::Current(n)`
266
293
/// where `n` minus the internal buffer length overflows an `i64`, two
267
294
/// seeks will be performed instead of one. If the second seek returns
268
295
/// `Err`, the underlying reader will be left at the same position it would
269
296
/// have if you seeked to `SeekFrom::Current(0)`.
297
+ ///
298
+ /// [`seek_relative`]: #method.seek_relative
270
299
fn seek ( & mut self , pos : SeekFrom ) -> io:: Result < u64 > {
271
300
let result: u64 ;
272
301
if let SeekFrom :: Current ( n) = pos {
@@ -953,6 +982,23 @@ mod tests {
953
982
assert_eq ! ( reader. seek( SeekFrom :: Current ( -2 ) ) . ok( ) , Some ( 3 ) ) ;
954
983
}
955
984
985
+ #[ test]
986
+ fn test_buffered_reader_seek_relative ( ) {
987
+ let inner: & [ u8 ] = & [ 5 , 6 , 7 , 0 , 1 , 2 , 3 , 4 ] ;
988
+ let mut reader = BufReader :: with_capacity ( 2 , io:: Cursor :: new ( inner) ) ;
989
+
990
+ assert ! ( reader. seek_relative( 3 ) . is_ok( ) ) ;
991
+ assert_eq ! ( reader. fill_buf( ) . ok( ) , Some ( & [ 0 , 1 ] [ ..] ) ) ;
992
+ assert ! ( reader. seek_relative( 0 ) . is_ok( ) ) ;
993
+ assert_eq ! ( reader. fill_buf( ) . ok( ) , Some ( & [ 0 , 1 ] [ ..] ) ) ;
994
+ assert ! ( reader. seek_relative( 1 ) . is_ok( ) ) ;
995
+ assert_eq ! ( reader. fill_buf( ) . ok( ) , Some ( & [ 1 ] [ ..] ) ) ;
996
+ assert ! ( reader. seek_relative( -1 ) . is_ok( ) ) ;
997
+ assert_eq ! ( reader. fill_buf( ) . ok( ) , Some ( & [ 0 , 1 ] [ ..] ) ) ;
998
+ assert ! ( reader. seek_relative( 2 ) . is_ok( ) ) ;
999
+ assert_eq ! ( reader. fill_buf( ) . ok( ) , Some ( & [ 2 , 3 ] [ ..] ) ) ;
1000
+ }
1001
+
956
1002
#[ test]
957
1003
fn test_buffered_reader_seek_underflow ( ) {
958
1004
// gimmick reader that yields its position modulo 256 for each byte
0 commit comments