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.
This commit is contained in:
parent
913ad6d1f0
commit
e8ee00a649
1 changed files with 119 additions and 2 deletions
|
@ -1329,6 +1329,78 @@ pub trait Seek {
|
||||||
/// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start
|
/// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
fn seek(&mut self, pos: SeekFrom) -> Result<u64>;
|
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.
|
/// Enumeration of possible methods to seek within an I/O object.
|
||||||
|
@ -2157,8 +2229,7 @@ impl<B: BufRead> Iterator for Lines<B> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::io::prelude::*;
|
use crate::io::prelude::*;
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use super::Cursor;
|
use super::{Cursor, SeekFrom, repeat};
|
||||||
use super::repeat;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||||
|
@ -2380,4 +2451,50 @@ mod tests {
|
||||||
super::read_to_end(&mut lr, &mut vec)
|
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(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue