Skip to main content

core/io/
seek.rs

1use crate::io::Result;
2
3/// The `Seek` trait provides a cursor which can be moved within a stream of
4/// bytes.
5///
6/// The stream typically has a fixed size, allowing seeking relative to either
7/// end or the current offset.
8///
9/// # Examples
10///
11/// `File`s implement `Seek`:
12///
13/// ```no_run
14/// use std::io;
15/// use std::io::prelude::*;
16/// use std::fs::File;
17/// use std::io::SeekFrom;
18///
19/// fn main() -> io::Result<()> {
20///     let mut f = File::open("foo.txt")?;
21///
22///     // move the cursor 42 bytes from the start of the file
23///     f.seek(SeekFrom::Start(42))?;
24///     Ok(())
25/// }
26/// ```
27#[stable(feature = "rust1", since = "1.0.0")]
28#[cfg_attr(not(test), rustc_diagnostic_item = "IoSeek")]
29pub trait Seek {
30    /// Seek to an offset, in bytes, in a stream.
31    ///
32    /// A seek beyond the end of a stream is allowed, but behavior is defined
33    /// by the implementation.
34    ///
35    /// If the seek operation completed successfully,
36    /// this method returns the new position from the start of the stream.
37    /// That position can be used later with [`SeekFrom::Start`].
38    ///
39    /// # Errors
40    ///
41    /// Seeking can fail, for example because it might involve flushing a buffer.
42    ///
43    /// Seeking to a negative offset is considered an error.
44    #[stable(feature = "rust1", since = "1.0.0")]
45    fn seek(&mut self, pos: SeekFrom) -> Result<u64>;
46
47    /// Rewind to the beginning of a stream.
48    ///
49    /// This is a convenience method, equivalent to `seek(SeekFrom::Start(0))`.
50    ///
51    /// # Errors
52    ///
53    /// Rewinding can fail, for example because it might involve flushing a buffer.
54    ///
55    /// # Example
56    ///
57    /// ```no_run
58    /// use std::io::{Read, Seek, Write};
59    /// use std::fs::OpenOptions;
60    ///
61    /// let mut f = OpenOptions::new()
62    ///     .write(true)
63    ///     .read(true)
64    ///     .create(true)
65    ///     .open("foo.txt")?;
66    ///
67    /// let hello = "Hello!\n";
68    /// write!(f, "{hello}")?;
69    /// f.rewind()?;
70    ///
71    /// let mut buf = String::new();
72    /// f.read_to_string(&mut buf)?;
73    /// assert_eq!(&buf, hello);
74    /// # std::io::Result::Ok(())
75    /// ```
76    #[stable(feature = "seek_rewind", since = "1.55.0")]
77    fn rewind(&mut self) -> Result<()> {
78        self.seek(SeekFrom::Start(0))?;
79        Ok(())
80    }
81
82    /// Returns the length of this stream (in bytes).
83    ///
84    /// The default implementation uses up to three seek operations. If this
85    /// method returns successfully, the seek position is unchanged (i.e. the
86    /// position before calling this method is the same as afterwards).
87    /// However, if this method returns an error, the seek position is
88    /// unspecified.
89    ///
90    /// If you need to obtain the length of *many* streams and you don't care
91    /// about the seek position afterwards, you can reduce the number of seek
92    /// operations by simply calling `seek(SeekFrom::End(0))` and using its
93    /// return value (it is also the stream length).
94    ///
95    /// Note that length of a stream can change over time (for example, when
96    /// data is appended to a file). So calling this method multiple times does
97    /// not necessarily return the same length each time.
98    ///
99    /// # Example
100    ///
101    /// ```no_run
102    /// #![feature(seek_stream_len)]
103    /// use std::{
104    ///     io::{self, Seek},
105    ///     fs::File,
106    /// };
107    ///
108    /// fn main() -> io::Result<()> {
109    ///     let mut f = File::open("foo.txt")?;
110    ///
111    ///     let len = f.stream_len()?;
112    ///     println!("The file is currently {len} bytes long");
113    ///     Ok(())
114    /// }
115    /// ```
116    #[unstable(feature = "seek_stream_len", issue = "59359")]
117    fn stream_len(&mut self) -> Result<u64> {
118        stream_len_default(self)
119    }
120
121    /// Returns the current seek position from the start of the stream.
122    ///
123    /// This is equivalent to `self.seek(SeekFrom::Current(0))`.
124    ///
125    /// # Example
126    ///
127    /// ```no_run
128    /// use std::{
129    ///     io::{self, BufRead, BufReader, Seek},
130    ///     fs::File,
131    /// };
132    ///
133    /// fn main() -> io::Result<()> {
134    ///     let mut f = BufReader::new(File::open("foo.txt")?);
135    ///
136    ///     let before = f.stream_position()?;
137    ///     f.read_line(&mut String::new())?;
138    ///     let after = f.stream_position()?;
139    ///
140    ///     println!("The first line was {} bytes long", after - before);
141    ///     Ok(())
142    /// }
143    /// ```
144    #[stable(feature = "seek_convenience", since = "1.51.0")]
145    #[expect(clippy::seek_from_current, reason = "implements stream_position")]
146    fn stream_position(&mut self) -> Result<u64> {
147        self.seek(SeekFrom::Current(0))
148    }
149
150    /// Seeks relative to the current position.
151    ///
152    /// This is equivalent to `self.seek(SeekFrom::Current(offset))` but
153    /// doesn't return the new position which can allow some implementations
154    /// such as `BufReader` to perform more efficient seeks.
155    ///
156    /// # Example
157    ///
158    /// ```no_run
159    /// use std::{
160    ///     io::{self, Seek},
161    ///     fs::File,
162    /// };
163    ///
164    /// fn main() -> io::Result<()> {
165    ///     let mut f = File::open("foo.txt")?;
166    ///     f.seek_relative(10)?;
167    ///     assert_eq!(f.stream_position()?, 10);
168    ///     Ok(())
169    /// }
170    /// ```
171    #[stable(feature = "seek_seek_relative", since = "1.80.0")]
172    fn seek_relative(&mut self, offset: i64) -> Result<()> {
173        self.seek(SeekFrom::Current(offset))?;
174        Ok(())
175    }
176}
177
178/// The default implementation of [`Seek::stream_len`].
179/// This may be desirable in `libstd` where the default implementation is desirable,
180/// but additional work needs to be done before or after.
181#[doc(hidden)]
182#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
183pub fn stream_len_default<T: Seek + ?Sized>(self_: &mut T) -> Result<u64> {
184    let old_pos = self_.stream_position()?;
185    let len = self_.seek(SeekFrom::End(0))?;
186
187    // Avoid seeking a third time when we were already at the end of the
188    // stream. The branch is usually way cheaper than a seek operation.
189    if old_pos != len {
190        self_.seek(SeekFrom::Start(old_pos))?;
191    }
192
193    Ok(len)
194}
195
196/// Enumeration of possible methods to seek within an I/O object.
197///
198/// It is used by the [`Seek`] trait.
199#[derive(#[automatically_derived]
#[stable(feature = "rust1", since = "1.0.0")]
impl crate::marker::Copy for SeekFrom { }Copy, #[automatically_derived]
#[stable(feature = "rust1", since = "1.0.0")]
impl crate::marker::StructuralPartialEq for SeekFrom { }
#[automatically_derived]
#[stable(feature = "rust1", since = "1.0.0")]
impl crate::cmp::PartialEq for SeekFrom {
    #[inline]
    fn eq(&self, other: &SeekFrom) -> bool {
        let __self_discr = crate::intrinsics::discriminant_value(self);
        let __arg1_discr = crate::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (SeekFrom::Start(__self_0), SeekFrom::Start(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (SeekFrom::End(__self_0), SeekFrom::End(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (SeekFrom::Current(__self_0), SeekFrom::Current(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => unsafe { crate::intrinsics::unreachable() }
            }
    }
}PartialEq, #[automatically_derived]
#[stable(feature = "rust1", since = "1.0.0")]
impl crate::cmp::Eq for SeekFrom {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: crate::cmp::AssertParamIsEq<u64>;
        let _: crate::cmp::AssertParamIsEq<i64>;
    }
}Eq, #[automatically_derived]
#[doc(hidden)]
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl crate::clone::TrivialClone for SeekFrom { }
#[automatically_derived]
#[stable(feature = "rust1", since = "1.0.0")]
impl crate::clone::Clone for SeekFrom {
    #[inline]
    fn clone(&self) -> SeekFrom {
        let _: crate::clone::AssertParamIsClone<u64>;
        let _: crate::clone::AssertParamIsClone<i64>;
        *self
    }
}Clone, #[automatically_derived]
#[stable(feature = "rust1", since = "1.0.0")]
impl crate::fmt::Debug for SeekFrom {
    #[inline]
    fn fmt(&self, f: &mut crate::fmt::Formatter) -> crate::fmt::Result {
        match self {
            SeekFrom::Start(__self_0) =>
                crate::fmt::Formatter::debug_tuple_field1_finish(f, "Start",
                    &__self_0),
            SeekFrom::End(__self_0) =>
                crate::fmt::Formatter::debug_tuple_field1_finish(f, "End",
                    &__self_0),
            SeekFrom::Current(__self_0) =>
                crate::fmt::Formatter::debug_tuple_field1_finish(f, "Current",
                    &__self_0),
        }
    }
}Debug)]
200#[stable(feature = "rust1", since = "1.0.0")]
201#[cfg_attr(not(test), rustc_diagnostic_item = "SeekFrom")]
202pub enum SeekFrom {
203    /// Sets the offset to the provided number of bytes.
204    #[stable(feature = "rust1", since = "1.0.0")]
205    Start(#[stable(feature = "rust1", since = "1.0.0")] u64),
206
207    /// Sets the offset to the size of this object plus the specified number of
208    /// bytes.
209    ///
210    /// It is possible to seek beyond the end of an object, but it's an error to
211    /// seek before byte 0.
212    #[stable(feature = "rust1", since = "1.0.0")]
213    End(#[stable(feature = "rust1", since = "1.0.0")] i64),
214
215    /// Sets the offset to the current position plus the specified number of
216    /// bytes.
217    ///
218    /// It is possible to seek beyond the end of an object, but it's an error to
219    /// seek before byte 0.
220    #[stable(feature = "rust1", since = "1.0.0")]
221    Current(#[stable(feature = "rust1", since = "1.0.0")] i64),
222}