completion_io/
seek.rs

1use std::future::{self, Future};
2use std::io::{Cursor, Empty, Result, SeekFrom};
3use std::marker::PhantomData;
4use std::pin::Pin;
5use std::task::{Context, Poll};
6
7use completion_core::CompletionFuture;
8
9/// A cursor which can be moved within a stream of bytes.
10///
11/// This is an asynchronous version of [`std::io::Seek`].
12///
13/// You should not implement this trait manually, instead implement [`AsyncSeekWith`].
14pub trait AsyncSeek: for<'a> AsyncSeekWith<'a> {}
15impl<T: for<'a> AsyncSeekWith<'a> + ?Sized> AsyncSeek for T {}
16
17/// A cursor which can be moved within a stream of bytes with a specific lifetime.
18pub trait AsyncSeekWith<'a> {
19    /// Future that seeks to an offset a stream. If successful, resolves to the new position from
20    /// the start of the stream.
21    type SeekFuture: CompletionFuture<Output = Result<u64>>;
22
23    /// Seek to an offset in bytes in a stream.
24    fn seek(&'a mut self, pos: SeekFrom) -> Self::SeekFuture;
25}
26
27impl<'a, S: AsyncSeekWith<'a> + ?Sized> AsyncSeekWith<'a> for &mut S {
28    type SeekFuture = S::SeekFuture;
29
30    #[inline]
31    fn seek(&'a mut self, pos: SeekFrom) -> Self::SeekFuture {
32        (**self).seek(pos)
33    }
34}
35
36impl<'a, S: AsyncSeekWith<'a> + ?Sized> AsyncSeekWith<'a> for Box<S> {
37    type SeekFuture = S::SeekFuture;
38
39    #[inline]
40    fn seek(&'a mut self, pos: SeekFrom) -> Self::SeekFuture {
41        (**self).seek(pos)
42    }
43}
44
45impl<'a> AsyncSeekWith<'a> for Empty {
46    type SeekFuture = future::Ready<Result<u64>>;
47
48    fn seek(&'a mut self, _pos: SeekFrom) -> Self::SeekFuture {
49        future::ready(Ok(0))
50    }
51}
52
53impl<'a, T: AsRef<[u8]>> AsyncSeekWith<'a> for Cursor<T> {
54    type SeekFuture = SeekCursor<'a, T>;
55
56    #[inline]
57    fn seek(&'a mut self, pos: SeekFrom) -> Self::SeekFuture {
58        SeekCursor {
59            cursor: self,
60            pos,
61            _lifetime: PhantomData,
62        }
63    }
64}
65
66/// Future for [`seek`](AsyncSeekWith::seek) on a [`Cursor`].
67#[derive(Debug)]
68pub struct SeekCursor<'a, T> {
69    // This is conceptually an &'a mut Cursor<T>. However, that would add the implicit bound T: 'a
70    // which is incompatible with AsyncReadWith.
71    cursor: *mut Cursor<T>,
72    pos: SeekFrom,
73    _lifetime: PhantomData<&'a ()>,
74}
75// SeekFrom is always Send+Sync, and we hold a mutable reference to Cursor.
76unsafe impl<T: Send> Send for SeekCursor<'_, T> {}
77unsafe impl<T: Sync> Sync for SeekCursor<'_, T> {}
78
79impl<T: AsRef<[u8]>> Future for SeekCursor<'_, T> {
80    type Output = Result<u64>;
81
82    fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
83        let this = &mut *self;
84        Poll::Ready(std::io::Seek::seek(unsafe { &mut *this.cursor }, this.pos))
85    }
86}
87impl<T: AsRef<[u8]>> CompletionFuture for SeekCursor<'_, T> {
88    type Output = Result<u64>;
89
90    unsafe fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
91        Future::poll(self, cx)
92    }
93    unsafe fn poll_cancel(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
94        Poll::Ready(())
95    }
96}
97
98#[cfg(test)]
99#[allow(dead_code, clippy::extra_unused_lifetimes)]
100fn test_impls_traits<'a>() {
101    fn assert_impls<R: AsyncSeek>() {}
102
103    assert_impls::<Cursor<&'a [u8]>>();
104    assert_impls::<Cursor<Vec<u8>>>();
105    assert_impls::<&'a mut Cursor<&'a [u8]>>();
106    assert_impls::<&'a mut Cursor<Vec<u8>>>();
107    assert_impls::<Box<Cursor<&'a [u8]>>>();
108    assert_impls::<Box<Cursor<Vec<u8>>>>();
109}