| use crate::io::Result; | |
| /// The `Seek` trait provides a cursor which can be moved within a stream of | |
| /// bytes. | |
| /// | |
| /// The stream typically has a fixed size, allowing seeking relative to either | |
| /// end or the current offset. | |
| /// | |
| /// # Examples | |
| /// | |
| /// `File`s implement `Seek`: | |
| /// | |
| /// ```no_run | |
| /// use std::io; | |
| /// use std::io::prelude::*; | |
| /// use std::fs::File; | |
| /// use std::io::SeekFrom; | |
| /// | |
| /// fn main() -> io::Result<()> { | |
| /// let mut f = File::open("foo.txt")?; | |
| /// | |
| /// // move the cursor 42 bytes from the start of the file | |
| /// f.seek(SeekFrom::Start(42))?; | |
| /// Ok(()) | |
| /// } | |
| /// ``` | |
| #[stable(feature = "rust1", since = "1.0.0")] | |
| #[cfg_attr(not(test), rustc_diagnostic_item = "IoSeek")] | |
| pub trait Seek { | |
| /// Seek to an offset, in bytes, in a stream. | |
| /// | |
| /// A seek beyond the end of a stream is allowed, but behavior is defined | |
| /// by the implementation. | |
| /// | |
| /// If the seek operation completed successfully, | |
| /// this method returns the new position from the start of the stream. | |
| /// That position can be used later with [`SeekFrom::Start`]. | |
| /// | |
| /// # Errors | |
| /// | |
| /// Seeking can fail, for example because it might involve flushing a buffer. | |
| /// | |
| /// Seeking to a negative offset is considered an error. | |
| #[stable(feature = "rust1", since = "1.0.0")] | |
| fn seek(&mut self, pos: SeekFrom) -> Result<u64>; | |
| /// Rewind to the beginning of a stream. | |
| /// | |
| /// This is a convenience method, equivalent to `seek(SeekFrom::Start(0))`. | |
| /// | |
| /// # Errors | |
| /// | |
| /// Rewinding can fail, for example because it might involve flushing a buffer. | |
| /// | |
| /// # Example | |
| /// | |
| /// ```no_run | |
| /// use std::io::{Read, Seek, Write}; | |
| /// use std::fs::OpenOptions; | |
| /// | |
| /// let mut f = OpenOptions::new() | |
| /// .write(true) | |
| /// .read(true) | |
| /// .create(true) | |
| /// .open("foo.txt")?; | |
| /// | |
| /// let hello = "Hello!\n"; | |
| /// write!(f, "{hello}")?; | |
| /// f.rewind()?; | |
| /// | |
| /// let mut buf = String::new(); | |
| /// f.read_to_string(&mut buf)?; | |
| /// assert_eq!(&buf, hello); | |
| /// # std::io::Result::Ok(()) | |
| /// ``` | |
| #[stable(feature = "seek_rewind", since = "1.55.0")] | |
| fn rewind(&mut self) -> Result<()> { | |
| self.seek(SeekFrom::Start(0))?; | |
| Ok(()) | |
| } | |
| /// Returns the length of this stream (in bytes). | |
| /// | |
| /// The default implementation uses up to 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 | |
| /// unspecified. | |
| /// | |
| /// 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 using 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 multiple times does | |
| /// not necessarily return the same length each time. | |
| /// | |
| /// # Example | |
| /// | |
| /// ```no_run | |
| /// #![feature(seek_stream_len)] | |
| /// 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 {len} bytes long"); | |
| /// Ok(()) | |
| /// } | |
| /// ``` | |
| #[unstable(feature = "seek_stream_len", issue = "59359")] | |
| fn stream_len(&mut self) -> Result<u64> { | |
| stream_len_default(self) | |
| } | |
| /// Returns the current seek position from the start of the stream. | |
| /// | |
| /// This is equivalent to `self.seek(SeekFrom::Current(0))`. | |
| /// | |
| /// # Example | |
| /// | |
| /// ```no_run | |
| /// 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(()) | |
| /// } | |
| /// ``` | |
| #[stable(feature = "seek_convenience", since = "1.51.0")] | |
| fn stream_position(&mut self) -> Result<u64> { | |
| self.seek(SeekFrom::Current(0)) | |
| } | |
| /// Seeks relative to the current position. | |
| /// | |
| /// This is equivalent to `self.seek(SeekFrom::Current(offset))` but | |
| /// doesn't return the new position which can allow some implementations | |
| /// such as `BufReader` to perform more efficient seeks. | |
| /// | |
| /// # Example | |
| /// | |
| /// ```no_run | |
| /// use std::{ | |
| /// io::{self, Seek}, | |
| /// fs::File, | |
| /// }; | |
| /// | |
| /// fn main() -> io::Result<()> { | |
| /// let mut f = File::open("foo.txt")?; | |
| /// f.seek_relative(10)?; | |
| /// assert_eq!(f.stream_position()?, 10); | |
| /// Ok(()) | |
| /// } | |
| /// ``` | |
| #[stable(feature = "seek_seek_relative", since = "1.80.0")] | |
| fn seek_relative(&mut self, offset: i64) -> Result<()> { | |
| self.seek(SeekFrom::Current(offset))?; | |
| Ok(()) | |
| } | |
| } | |
| /// The default implementation of [`Seek::stream_len`]. | |
| /// This may be desirable in `libstd` where the default implementation is desirable, | |
| /// but additional work needs to be done before or after. | |
| #[doc(hidden)] | |
| #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| pub fn stream_len_default<T: Seek + ?Sized>(self_: &mut T) -> Result<u64> { | |
| let old_pos = self_.stream_position()?; | |
| let len = self_.seek(SeekFrom::End(0))?; | |
| // Avoid seeking a third time when we were already at the end of the | |
| // stream. The branch is usually way cheaper than a seek operation. | |
| if old_pos != len { | |
| self_.seek(SeekFrom::Start(old_pos))?; | |
| } | |
| Ok(len) | |
| } | |
| /// Enumeration of possible methods to seek within an I/O object. | |
| /// | |
| /// It is used by the [`Seek`] trait. | |
| #[derive(Copy, PartialEq, Eq, Clone, Debug)] | |
| #[stable(feature = "rust1", since = "1.0.0")] | |
| #[cfg_attr(not(test), rustc_diagnostic_item = "SeekFrom")] | |
| pub enum SeekFrom { | |
| /// Sets the offset to the provided number of bytes. | |
| #[stable(feature = "rust1", since = "1.0.0")] | |
| Start(#[stable(feature = "rust1", since = "1.0.0")] u64), | |
| /// Sets the offset to the size of this object plus the specified number of | |
| /// bytes. | |
| /// | |
| /// It is possible to seek beyond the end of an object, but it's an error to | |
| /// seek before byte 0. | |
| #[stable(feature = "rust1", since = "1.0.0")] | |
| End(#[stable(feature = "rust1", since = "1.0.0")] i64), | |
| /// Sets the offset to the current position plus the specified number of | |
| /// bytes. | |
| /// | |
| /// It is possible to seek beyond the end of an object, but it's an error to | |
| /// seek before byte 0. | |
| #[stable(feature = "rust1", since = "1.0.0")] | |
| Current(#[stable(feature = "rust1", since = "1.0.0")] i64), | |
| } |