Skip to content

Commit e8ee00a

Browse files
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.
1 parent 913ad6d commit e8ee00a

File tree

1 file changed

+119
-2
lines changed

1 file changed

+119
-2
lines changed

src/libstd/io/mod.rs

+119-2
Original file line numberDiff line numberDiff line change
@@ -1329,6 +1329,78 @@ pub trait Seek {
13291329
/// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start
13301330
#[stable(feature = "rust1", since = "1.0.0")]
13311331
fn seek(&mut self, pos: SeekFrom) -> Result<u64>;
1332+
1333+
/// Returns the length of this stream (in bytes).
1334+
///
1335+
/// This method is implemented using three seek operations. If this method
1336+
/// returns successfully, the seek position is unchanged (i.e. the position
1337+
/// before calling this method is the same as afterwards). However, if this
1338+
/// method returns an error, the seek position is undefined.
1339+
///
1340+
/// If you need to obtain the length of *many* streams and you don't care
1341+
/// about the seek position afterwards, you can reduce the number of seek
1342+
/// operations by simply calling `seek(SeekFrom::End(0))` and use its
1343+
/// return value (it is also the stream length).
1344+
///
1345+
/// Note that length of a stream can change over time (for example, when
1346+
/// data is appended to a file). So calling this method multiply times does
1347+
/// not necessarily return the same length each time.
1348+
///
1349+
///
1350+
/// # Example
1351+
///
1352+
/// ```no_run
1353+
/// #![feature(seek_convenience)]
1354+
/// use std::{
1355+
/// io::{self, Seek},
1356+
/// fs::File,
1357+
/// };
1358+
///
1359+
/// fn main() -> io::Result<()> {
1360+
/// let mut f = File::open("foo.txt")?;
1361+
///
1362+
/// let len = f.stream_len()?;
1363+
/// println!("The file is currently {} bytes long", len);
1364+
/// Ok(())
1365+
/// }
1366+
/// ```
1367+
#[unstable(feature = "seek_convenience", issue = "0")]
1368+
fn stream_len(&mut self) -> Result<u64> {
1369+
let old_pos = self.stream_position()?;
1370+
let len = self.seek(SeekFrom::End(0))?;
1371+
self.seek(SeekFrom::Start(old_pos))?;
1372+
Ok(len)
1373+
}
1374+
1375+
/// Returns the current seek position from the start of the stream.
1376+
///
1377+
/// This is equivalent to `self.seek(SeekFrom::Current(0))`.
1378+
///
1379+
///
1380+
/// # Example
1381+
///
1382+
/// ```no_run
1383+
/// #![feature(seek_convenience)]
1384+
/// use std::{
1385+
/// io::{self, BufRead, BufReader, Seek},
1386+
/// fs::File,
1387+
/// };
1388+
///
1389+
/// fn main() -> io::Result<()> {
1390+
/// let mut f = BufReader::new(File::open("foo.txt")?);
1391+
///
1392+
/// let before = f.stream_position()?;
1393+
/// f.read_line(&mut String::new())?;
1394+
/// let after = f.stream_position()?;
1395+
///
1396+
/// println!("The first line was {} bytes long", after - before);
1397+
/// Ok(())
1398+
/// }
1399+
/// ```
1400+
#[unstable(feature = "seek_convenience", issue = "0")]
1401+
fn stream_position(&mut self) -> Result<u64> {
1402+
self.seek(SeekFrom::Current(0))
1403+
}
13321404
}
13331405

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

21632234
#[test]
21642235
#[cfg_attr(target_os = "emscripten", ignore)]
@@ -2380,4 +2451,50 @@ mod tests {
23802451
super::read_to_end(&mut lr, &mut vec)
23812452
});
23822453
}
2454+
2455+
#[test]
2456+
fn seek_len() -> io::Result<()> {
2457+
let mut c = Cursor::new(vec![0; 15]);
2458+
assert_eq!(c.stream_len()?, 15);
2459+
2460+
c.seek(SeekFrom::End(0))?;
2461+
let old_pos = c.stream_position()?;
2462+
assert_eq!(c.stream_len()?, 15);
2463+
assert_eq!(c.stream_position()?, old_pos);
2464+
2465+
c.seek(SeekFrom::Start(7))?;
2466+
c.seek(SeekFrom::Current(2))?;
2467+
let old_pos = c.stream_position()?;
2468+
assert_eq!(c.stream_len()?, 15);
2469+
assert_eq!(c.stream_position()?, old_pos);
2470+
2471+
Ok(())
2472+
}
2473+
2474+
#[test]
2475+
fn seek_position() -> io::Result<()> {
2476+
// All `asserts` are duplicated here to make sure the method does not
2477+
// change anything about the seek state.
2478+
let mut c = Cursor::new(vec![0; 15]);
2479+
assert_eq!(c.stream_position()?, 0);
2480+
assert_eq!(c.stream_position()?, 0);
2481+
2482+
c.seek(SeekFrom::End(0))?;
2483+
assert_eq!(c.stream_position()?, 15);
2484+
assert_eq!(c.stream_position()?, 15);
2485+
2486+
2487+
c.seek(SeekFrom::Start(7))?;
2488+
c.seek(SeekFrom::Current(2))?;
2489+
assert_eq!(c.stream_position()?, 9);
2490+
assert_eq!(c.stream_position()?, 9);
2491+
2492+
c.seek(SeekFrom::End(-3))?;
2493+
c.seek(SeekFrom::Current(1))?;
2494+
c.seek(SeekFrom::Current(-5))?;
2495+
assert_eq!(c.stream_position()?, 8);
2496+
assert_eq!(c.stream_position()?, 8);
2497+
2498+
Ok(())
2499+
}
23832500
}

0 commit comments

Comments
 (0)