Skip to content

Commit

Permalink
Add provided methods Seek::{stream_len, stream_position}
Browse files Browse the repository at this point in the history
These two methods are defined in terms of `Seek::seek` and are
added for convenience. Tests are included.
  • Loading branch information
LukasKalbertodt committed Mar 10, 2019
1 parent 913ad6d commit e8ee00a
Showing 1 changed file with 119 additions and 2 deletions.
121 changes: 119 additions & 2 deletions src/libstd/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,78 @@ pub trait Seek {
/// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start
#[stable(feature = "rust1", since = "1.0.0")]
fn seek(&mut self, pos: SeekFrom) -> Result<u64>;

/// Returns the length of this stream (in bytes).
///
/// This method is implemented using three seek operations. If this method
/// returns successfully, the seek position is unchanged (i.e. the position
/// before calling this method is the same as afterwards). However, if this
/// method returns an error, the seek position is undefined.
///
/// If you need to obtain the length of *many* streams and you don't care
/// about the seek position afterwards, you can reduce the number of seek
/// operations by simply calling `seek(SeekFrom::End(0))` and use its
/// return value (it is also the stream length).
///
/// Note that length of a stream can change over time (for example, when
/// data is appended to a file). So calling this method multiply times does
/// not necessarily return the same length each time.
///
///
/// # Example
///
/// ```no_run
/// #![feature(seek_convenience)]
/// use std::{
/// io::{self, Seek},
/// fs::File,
/// };
///
/// fn main() -> io::Result<()> {
/// let mut f = File::open("foo.txt")?;
///
/// let len = f.stream_len()?;
/// println!("The file is currently {} bytes long", len);
/// Ok(())
/// }
/// ```
#[unstable(feature = "seek_convenience", issue = "0")]
fn stream_len(&mut self) -> Result<u64> {
let old_pos = self.stream_position()?;
let len = self.seek(SeekFrom::End(0))?;
self.seek(SeekFrom::Start(old_pos))?;
Ok(len)
}

/// Returns the current seek position from the start of the stream.
///
/// This is equivalent to `self.seek(SeekFrom::Current(0))`.
///
///
/// # Example
///
/// ```no_run
/// #![feature(seek_convenience)]
/// use std::{
/// io::{self, BufRead, BufReader, Seek},
/// fs::File,
/// };
///
/// fn main() -> io::Result<()> {
/// let mut f = BufReader::new(File::open("foo.txt")?);
///
/// let before = f.stream_position()?;
/// f.read_line(&mut String::new())?;
/// let after = f.stream_position()?;
///
/// println!("The first line was {} bytes long", after - before);
/// Ok(())
/// }
/// ```
#[unstable(feature = "seek_convenience", issue = "0")]
fn stream_position(&mut self) -> Result<u64> {
self.seek(SeekFrom::Current(0))
}
}

/// Enumeration of possible methods to seek within an I/O object.
Expand Down Expand Up @@ -2157,8 +2229,7 @@ impl<B: BufRead> Iterator for Lines<B> {
mod tests {
use crate::io::prelude::*;
use crate::io;
use super::Cursor;
use super::repeat;
use super::{Cursor, SeekFrom, repeat};

#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
Expand Down Expand Up @@ -2380,4 +2451,50 @@ mod tests {
super::read_to_end(&mut lr, &mut vec)
});
}

#[test]
fn seek_len() -> io::Result<()> {
let mut c = Cursor::new(vec![0; 15]);
assert_eq!(c.stream_len()?, 15);

c.seek(SeekFrom::End(0))?;
let old_pos = c.stream_position()?;
assert_eq!(c.stream_len()?, 15);
assert_eq!(c.stream_position()?, old_pos);

c.seek(SeekFrom::Start(7))?;
c.seek(SeekFrom::Current(2))?;
let old_pos = c.stream_position()?;
assert_eq!(c.stream_len()?, 15);
assert_eq!(c.stream_position()?, old_pos);

Ok(())
}

#[test]
fn seek_position() -> io::Result<()> {
// All `asserts` are duplicated here to make sure the method does not
// change anything about the seek state.
let mut c = Cursor::new(vec![0; 15]);
assert_eq!(c.stream_position()?, 0);
assert_eq!(c.stream_position()?, 0);

c.seek(SeekFrom::End(0))?;
assert_eq!(c.stream_position()?, 15);
assert_eq!(c.stream_position()?, 15);


c.seek(SeekFrom::Start(7))?;
c.seek(SeekFrom::Current(2))?;
assert_eq!(c.stream_position()?, 9);
assert_eq!(c.stream_position()?, 9);

c.seek(SeekFrom::End(-3))?;
c.seek(SeekFrom::Current(1))?;
c.seek(SeekFrom::Current(-5))?;
assert_eq!(c.stream_position()?, 8);
assert_eq!(c.stream_position()?, 8);

Ok(())
}
}

0 comments on commit e8ee00a

Please sign in to comment.