1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::io;
15 use std::io::SeekFrom;
16 use std::ops::DerefMut;
17 use std::pin::Pin;
18 use std::task::{Context, Poll};
19 
20 use crate::io::seek_task::SeekTask;
21 
22 /// An asynchronous version of [`std::io::Seek`].
23 ///
24 /// The `AsyncSeek` trait provides a cursor which can be moved within a stream
25 /// of bytes asynchronously.
26 ///
27 /// The stream typically has a fixed size, allowing seeking relative to either
28 /// end or the current offset.
29 pub trait AsyncSeek {
30     /// Attempts to seek to a position in an I/O source.
31     ///
32     /// If succeeds, this method will return `Poll::Ready(Ok(n))` where `n`
33     /// indicates the current position in the I/O source.
34     ///
35     /// If `Poll::Pending` is returned, it means that the input source is
36     /// currently not ready for seeking. In this case, this task will be put
37     /// to sleep until the underlying stream becomes readable or closed.
poll_seek( self: Pin<&mut Self>, cx: &mut Context<'_>, pos: SeekFrom, ) -> Poll<io::Result<u64>>38     fn poll_seek(
39         self: Pin<&mut Self>,
40         cx: &mut Context<'_>,
41         pos: SeekFrom,
42     ) -> Poll<io::Result<u64>>;
43 }
44 
45 impl<T> AsyncSeek for Pin<T>
46 where
47     T: DerefMut<Target = dyn AsyncSeek> + Unpin,
48 {
poll_seek( self: Pin<&mut Self>, cx: &mut Context<'_>, pos: SeekFrom, ) -> Poll<io::Result<u64>>49     fn poll_seek(
50         self: Pin<&mut Self>,
51         cx: &mut Context<'_>,
52         pos: SeekFrom,
53     ) -> Poll<io::Result<u64>> {
54         self.get_mut().as_mut().poll_seek(cx, pos)
55     }
56 }
57 
58 impl<T: AsyncSeek + Unpin + ?Sized> AsyncSeek for Box<T> {
poll_seek( mut self: Pin<&mut Self>, cx: &mut Context<'_>, pos: SeekFrom, ) -> Poll<io::Result<u64>>59     fn poll_seek(
60         mut self: Pin<&mut Self>,
61         cx: &mut Context<'_>,
62         pos: SeekFrom,
63     ) -> Poll<io::Result<u64>> {
64         Pin::new(&mut **self).poll_seek(cx, pos)
65     }
66 }
67 
68 impl<T: AsyncSeek + Unpin + ?Sized> AsyncSeek for &mut T {
poll_seek( mut self: Pin<&mut Self>, cx: &mut Context<'_>, pos: SeekFrom, ) -> Poll<io::Result<u64>>69     fn poll_seek(
70         mut self: Pin<&mut Self>,
71         cx: &mut Context<'_>,
72         pos: SeekFrom,
73     ) -> Poll<io::Result<u64>> {
74         Pin::new(&mut **self).poll_seek(cx, pos)
75     }
76 }
77 
78 impl<T: AsyncSeek + ?Sized> AsyncSeekExt for T {}
79 
80 /// An external trait that is automatically implemented for any object that has
81 /// the AsyncSeek trait. Provides std-like `seek` method.
82 /// `Seek` method in this trait returns a future object. Awaits on the future
83 /// will complete the task, but it doesn't guarantee whether the task will
84 /// finished immediately or asynchronously.
85 pub trait AsyncSeekExt: AsyncSeek {
86     /// Asynchronously seek to an offset, in bytes, in a stream.
87     ///
88     /// A seek beyond the end of a stream is allowed, but the behavior is
89     /// defined by the implementation.
90     ///
91     /// If the seek operation completed successfully,
92     /// this method returns the new position from the start of the stream.
93     ///
94     /// # Errors
95     ///
96     /// Seeking can fail, for example because it might involve flushing a
97     /// buffer.
98     ///
99     /// Seeking to a negative offset is considered an error.
seek(&mut self, pos: SeekFrom) -> SeekTask<Self> where Self: Unpin,100     fn seek(&mut self, pos: SeekFrom) -> SeekTask<Self>
101     where
102         Self: Unpin,
103     {
104         SeekTask::new(self, pos)
105     }
106 
107     /// Rewinds to the beginning of a stream.
108     ///
109     /// This is a convenience method, equivalent to seek(SeekFrom::Start(0)).
110     ///
111     /// # Errors
112     ///
113     /// Rewinding can fail, for example because it might involve flushing a
114     /// buffer.
115     ///
116     /// # Example
117     ///
118     /// ```no run
119     /// use std::io;
120     ///
121     /// use ylong_runtime::fs::OpenOptions;
122     /// use ylong_runtime::io::AsyncSeekExt;
123     ///
124     /// async fn async_io() -> io::Result<()> {
125     ///     let mut f = OpenOptions::new()
126     ///         .write(true)
127     ///         .read(true)
128     ///         .create(true)
129     ///         .open("foo.txt")
130     ///         .await
131     ///         .unwrap();
132     ///
133     ///     let hello = "Hello!\n";
134     ///     f.rewind().await.unwrap();
135     ///     Ok(())
136     /// }
137     /// ```
rewind(&mut self) -> SeekTask<'_, Self> where Self: Unpin,138     fn rewind(&mut self) -> SeekTask<'_, Self>
139     where
140         Self: Unpin,
141     {
142         self.seek(SeekFrom::Start(0))
143     }
144 
145     /// Returns the current seek position from the start of the stream.
146     ///
147     /// This is a convenience method, equivalent to
148     /// `self.seek(SeekFrom::Current(0))`.
149     ///
150     /// # Example
151     ///
152     /// ```no run
153     /// use std::io;
154     ///
155     /// use ylong_runtime::fs::{File, OpenOptions};
156     /// use ylong_runtime::io::{AsyncBufReadExt, AsyncBufReader, AsyncSeekExt};
157     ///
158     /// async fn async_io() -> io::Result<()> {
159     ///     let mut f = AsyncBufReader::new(File::open("foo.txt").await?);
160     ///
161     ///     let before = f.stream_position().await?;
162     ///     f.read_line(&mut String::new()).await?;
163     ///     let after = f.stream_position().await?;
164     ///
165     ///     println!("The first line was {} bytes long", after - before);
166     ///     Ok(())
167     /// }
168     /// ```
stream_position(&mut self) -> SeekTask<'_, Self> where Self: Unpin,169     fn stream_position(&mut self) -> SeekTask<'_, Self>
170     where
171         Self: Unpin,
172     {
173         self.seek(SeekFrom::Current(0))
174     }
175 }
176