about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorDiggory Blake <diggsey@googlemail.com>2018-01-11 22:18:16 +0000
committerDiggory Blake <diggsey@googlemail.com>2018-01-13 18:39:37 +0000
commit562ba04e454e86bfedb332d5c7194449113bc5cb (patch)
tree407fe357a3716ebc9eae7399ce29da6393ea974f /src/libstd
parenta18dea908ca2a89cc1c7f4b0416924382ca145e6 (diff)
downloadrust-562ba04e454e86bfedb332d5c7194449113bc5cb.tar.gz
rust-562ba04e454e86bfedb332d5c7194449113bc5cb.zip
Implement "seek_relative"
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/io/buffered.rs42
1 files changed, 42 insertions, 0 deletions
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 8308ab48d9c..df1609ace87 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -194,6 +194,31 @@ impl<R: Read> BufReader<R> {
     pub fn into_inner(self) -> R { self.inner }
 }
 
+impl<R: Seek> BufReader<R> {
+    /// Seeks relative to the current position. If the new position lies within the buffer,
+    /// the buffer will not be flushed, allowing for more efficient seeks.
+    /// This method does not return the location of the underlying reader, so the caller
+    /// must track this information themselves if it is required.
+    #[unstable(feature = "bufreader_seek_relative", issue = "31100")]
+    pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
+        let pos = self.pos as u64;
+        if offset < 0 {
+            if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
+                self.pos = new_pos as usize;
+                return Ok(())
+            }
+        } else {
+            if let Some(new_pos) = pos.checked_add(offset as u64) {
+                if new_pos <= self.cap as u64 {
+                    self.pos = new_pos as usize;
+                    return Ok(())
+                }
+            }
+        }
+        self.seek(SeekFrom::Current(offset)).map(|_|())
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<R: Read> Read for BufReader<R> {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
@@ -943,6 +968,23 @@ mod tests {
     }
 
     #[test]
+    fn test_buffered_reader_seek_relative() {
+        let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+        let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
+
+        assert!(reader.seek_relative(3).is_ok());
+        assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+        assert!(reader.seek_relative(0).is_ok());
+        assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+        assert!(reader.seek_relative(1).is_ok());
+        assert_eq!(reader.fill_buf().ok(), Some(&[1][..]));
+        assert!(reader.seek_relative(-1).is_ok());
+        assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+        assert!(reader.seek_relative(2).is_ok());
+        assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..]));
+    }
+
+    #[test]
     fn test_buffered_reader_seek_underflow() {
         // gimmick reader that yields its position modulo 256 for each byte
         struct PositionReader {