diff options
| author | Lukas Kalbertodt <lukas.kalbertodt@gmail.com> | 2019-02-13 12:19:58 +0100 |
|---|---|---|
| committer | Lukas Kalbertodt <lukas.kalbertodt@gmail.com> | 2019-03-10 18:06:49 +0100 |
| commit | e8ee00a6493b8cde09f5497f430d46a978ae865f (patch) | |
| tree | 007e8431f6ade1eaf27f5915e7ae14924d98a11e /src/libstd/io | |
| parent | 913ad6d1f092c70049934ba538d342d295d35997 (diff) | |
| download | rust-e8ee00a6493b8cde09f5497f430d46a978ae865f.tar.gz rust-e8ee00a6493b8cde09f5497f430d46a978ae865f.zip | |
Add provided methods `Seek::{stream_len, stream_position}`
These two methods are defined in terms of `Seek::seek` and are added for convenience. Tests are included.
Diffstat (limited to 'src/libstd/io')
| -rw-r--r-- | src/libstd/io/mod.rs | 121 |
1 files changed, 119 insertions, 2 deletions
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index e3e2754a7aa..99bb24f54dd 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -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. @@ -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)] @@ -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(()) + } } |
