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 fn stream_position(&mut self) -> Result<u64> {
146 self.seek(SeekFrom::Current(0))
147 }
148
149 /// Seeks relative to the current position.
150 ///
151 /// This is equivalent to `self.seek(SeekFrom::Current(offset))` but
152 /// doesn't return the new position which can allow some implementations
153 /// such as `BufReader` to perform more efficient seeks.
154 ///
155 /// # Example
156 ///
157 /// ```no_run
158 /// use std::{
159 /// io::{self, Seek},
160 /// fs::File,
161 /// };
162 ///
163 /// fn main() -> io::Result<()> {
164 /// let mut f = File::open("foo.txt")?;
165 /// f.seek_relative(10)?;
166 /// assert_eq!(f.stream_position()?, 10);
167 /// Ok(())
168 /// }
169 /// ```
170 #[stable(feature = "seek_seek_relative", since = "1.80.0")]
171 fn seek_relative(&mut self, offset: i64) -> Result<()> {
172 self.seek(SeekFrom::Current(offset))?;
173 Ok(())
174 }
175}
176
177/// The default implementation of [`Seek::stream_len`].
178/// This may be desirable in `libstd` where the default implementation is desirable,
179/// but additional work needs to be done before or after.
180#[doc(hidden)]
181#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
182pub fn stream_len_default<T: Seek + ?Sized>(self_: &mut T) -> Result<u64> {
183 let old_pos = self_.stream_position()?;
184 let len = self_.seek(SeekFrom::End(0))?;
185
186 // Avoid seeking a third time when we were already at the end of the
187 // stream. The branch is usually way cheaper than a seek operation.
188 if old_pos != len {
189 self_.seek(SeekFrom::Start(old_pos))?;
190 }
191
192 Ok(len)
193}
194
195/// Enumeration of possible methods to seek within an I/O object.
196///
197/// It is used by the [`Seek`] trait.
198#[derive(Copy, PartialEq, Eq, Clone, Debug)]
199#[stable(feature = "rust1", since = "1.0.0")]
200#[cfg_attr(not(test), rustc_diagnostic_item = "SeekFrom")]
201pub enum SeekFrom {
202 /// Sets the offset to the provided number of bytes.
203 #[stable(feature = "rust1", since = "1.0.0")]
204 Start(#[stable(feature = "rust1", since = "1.0.0")] u64),
205
206 /// Sets the offset to the size of this object plus the specified number of
207 /// bytes.
208 ///
209 /// It is possible to seek beyond the end of an object, but it's an error to
210 /// seek before byte 0.
211 #[stable(feature = "rust1", since = "1.0.0")]
212 End(#[stable(feature = "rust1", since = "1.0.0")] i64),
213
214 /// Sets the offset to the current position plus the specified number of
215 /// bytes.
216 ///
217 /// It is possible to seek beyond the end of an object, but it's an error to
218 /// seek before byte 0.
219 #[stable(feature = "rust1", since = "1.0.0")]
220 Current(#[stable(feature = "rust1", since = "1.0.0")] i64),
221}