Skip to main content

ax_io/seek/
mod.rs

1use crate::Result;
2
3mod impls;
4
5/// Enumeration of possible methods to seek within an I/O object.
6///
7/// It is used by the [`Seek`] trait.
8#[derive(Copy, PartialEq, Eq, Clone, Debug)]
9pub enum SeekFrom {
10    /// Sets the offset to the provided number of bytes.
11    Start(u64),
12
13    /// Sets the offset to the size of this object plus the specified number of
14    /// bytes.
15    ///
16    /// It is possible to seek beyond the end of an object, but it's an error to
17    /// seek before byte 0.
18    End(i64),
19
20    /// Sets the offset to the current position plus the specified number of
21    /// bytes.
22    ///
23    /// It is possible to seek beyond the end of an object, but it's an error to
24    /// seek before byte 0.
25    Current(i64),
26}
27
28/// Default [`Seek::stream_len`] implementation.
29pub fn default_stream_len<T: Seek + ?Sized>(this: &mut T) -> Result<u64> {
30    let old_pos = this.stream_position()?;
31    let len = this.seek(SeekFrom::End(0))?;
32
33    // Avoid seeking a third time when we were already at the end of the
34    // stream. The branch is usually way cheaper than a seek operation.
35    if old_pos != len {
36        this.seek(SeekFrom::Start(old_pos))?;
37    }
38
39    Ok(len)
40}
41
42/// The `Seek` trait provides a cursor which can be moved within a stream of
43/// bytes.
44///
45/// See [`std::io::Seek`] for more details.
46pub trait Seek {
47    /// Seek to an offset, in bytes, in a stream.
48    ///
49    /// A seek beyond the end of a stream is allowed, but behavior is defined
50    /// by the implementation.
51    ///
52    /// If the seek operation completed successfully,
53    /// this method returns the new position from the start of the stream.
54    /// That position can be used later with [`SeekFrom::Start`].
55    fn seek(&mut self, pos: SeekFrom) -> Result<u64>;
56
57    /// Rewind to the beginning of a stream.
58    ///
59    /// This is a convenience method, equivalent to `seek(SeekFrom::Start(0))`.
60    fn rewind(&mut self) -> Result<()> {
61        self.seek(SeekFrom::Start(0))?;
62        Ok(())
63    }
64
65    /// Returns the current seek position from the start of the stream.
66    ///
67    /// This is equivalent to `self.seek(SeekFrom::Current(0))`.
68    fn stream_position(&mut self) -> Result<u64> {
69        self.seek(SeekFrom::Current(0))
70    }
71
72    /// Returns the length of this stream (in bytes).
73    fn stream_len(&mut self) -> Result<u64> {
74        default_stream_len(self)
75    }
76
77    /// Seeks relative to the current position.
78    fn seek_relative(&mut self, offset: i64) -> Result<()> {
79        self.seek(SeekFrom::Current(offset))?;
80        Ok(())
81    }
82}