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