1 use std::io::{self, SeekFrom};
2 use std::ops::DerefMut;
3 use std::pin::Pin;
4 use std::task::{Context, Poll};
5 
6 /// Seek bytes asynchronously.
7 ///
8 /// This trait is analogous to the [`std::io::Seek`] trait, but integrates
9 /// with the asynchronous task system. In particular, the `start_seek`
10 /// method, unlike [`Seek::seek`], will not block the calling thread.
11 ///
12 /// Utilities for working with `AsyncSeek` values are provided by
13 /// [`AsyncSeekExt`].
14 ///
15 /// [`std::io::Seek`]: std::io::Seek
16 /// [`Seek::seek`]: std::io::Seek::seek()
17 /// [`AsyncSeekExt`]: crate::io::AsyncSeekExt
18 pub trait AsyncSeek {
19     /// Attempts to seek to an offset, in bytes, in a stream.
20     ///
21     /// A seek beyond the end of a stream is allowed, but behavior is defined
22     /// by the implementation.
23     ///
24     /// If this function returns successfully, then the job has been submitted.
25     /// To find out when it completes, call `poll_complete`.
26     ///
27     /// # Errors
28     ///
29     /// This function can return [`io::ErrorKind::Other`] in case there is
30     /// another seek in progress. To avoid this, it is advisable that any call
31     /// to `start_seek` is preceded by a call to `poll_complete` to ensure all
32     /// pending seeks have completed.
start_seek(self: Pin<&mut Self>, position: SeekFrom) -> io::Result<()>33     fn start_seek(self: Pin<&mut Self>, position: SeekFrom) -> io::Result<()>;
34 
35     /// Waits for a seek operation to complete.
36     ///
37     /// If the seek operation completed successfully,
38     /// this method returns the new position from the start of the stream.
39     /// That position can be used later with [`SeekFrom::Start`]. Repeatedly
40     /// calling this function without calling `start_seek` might return the
41     /// same result.
42     ///
43     /// # Errors
44     ///
45     /// Seeking to a negative offset is considered an error.
poll_complete(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>>46     fn poll_complete(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>>;
47 }
48 
49 macro_rules! deref_async_seek {
50     () => {
51         fn start_seek(mut self: Pin<&mut Self>, pos: SeekFrom) -> io::Result<()> {
52             Pin::new(&mut **self).start_seek(pos)
53         }
54 
55         fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
56             Pin::new(&mut **self).poll_complete(cx)
57         }
58     };
59 }
60 
61 impl<T: ?Sized + AsyncSeek + Unpin> AsyncSeek for Box<T> {
62     deref_async_seek!();
63 }
64 
65 impl<T: ?Sized + AsyncSeek + Unpin> AsyncSeek for &mut T {
66     deref_async_seek!();
67 }
68 
69 impl<P> AsyncSeek for Pin<P>
70 where
71     P: DerefMut + Unpin,
72     P::Target: AsyncSeek,
73 {
start_seek(self: Pin<&mut Self>, pos: SeekFrom) -> io::Result<()>74     fn start_seek(self: Pin<&mut Self>, pos: SeekFrom) -> io::Result<()> {
75         self.get_mut().as_mut().start_seek(pos)
76     }
77 
poll_complete(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>>78     fn poll_complete(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
79         self.get_mut().as_mut().poll_complete(cx)
80     }
81 }
82 
83 impl<T: AsRef<[u8]> + Unpin> AsyncSeek for io::Cursor<T> {
start_seek(mut self: Pin<&mut Self>, pos: SeekFrom) -> io::Result<()>84     fn start_seek(mut self: Pin<&mut Self>, pos: SeekFrom) -> io::Result<()> {
85         io::Seek::seek(&mut *self, pos).map(drop)
86     }
poll_complete(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<u64>>87     fn poll_complete(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<u64>> {
88         Poll::Ready(Ok(self.get_mut().position()))
89     }
90 }
91