1use crate::errors::{Error, ErrorKind};
2use std::fs::{Metadata, Permissions};
3use std::io;
4use std::io::{IoSlice, SeekFrom};
5use std::path::{Path, PathBuf};
6use std::pin::Pin;
7use std::task::{ready, Context, Poll};
8use tokio::fs;
9use tokio::fs::File as TokioFile;
10use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite, ReadBuf};
11
12#[derive(Debug)]
15#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
16pub struct File {
17 tokio: fs::File,
18 path: PathBuf,
19}
20
21impl File {
22 pub async fn open(path: impl Into<PathBuf>) -> io::Result<File> {
26 let path = path.into();
27 let f = TokioFile::open(&path)
28 .await
29 .map_err(|err| Error::build(err, ErrorKind::OpenFile, &path))?;
30 Ok(File::from_parts(f, path))
31 }
32
33 pub async fn create(path: impl Into<PathBuf>) -> io::Result<File> {
37 let path = path.into();
38 match TokioFile::create(&path).await {
39 Ok(f) => Ok(File::from_parts(f, path)),
40 Err(err) => Err(Error::build(err, ErrorKind::CreateFile, &path)),
41 }
42 }
43
44 pub fn from_std(std: crate::File) -> File {
48 let (std, path) = std.into_parts();
49 File::from_parts(TokioFile::from_std(std), path)
50 }
51
52 pub async fn sync_all(&self) -> io::Result<()> {
56 self.tokio
57 .sync_all()
58 .await
59 .map_err(|err| self.error(err, ErrorKind::SyncFile))
60 }
61
62 pub async fn sync_data(&self) -> io::Result<()> {
67 self.tokio
68 .sync_data()
69 .await
70 .map_err(|err| self.error(err, ErrorKind::SyncFile))
71 }
72
73 pub async fn set_len(&self, size: u64) -> io::Result<()> {
77 self.tokio
78 .set_len(size)
79 .await
80 .map_err(|err| self.error(err, ErrorKind::SetLen))
81 }
82
83 pub async fn metadata(&self) -> io::Result<Metadata> {
87 self.tokio
88 .metadata()
89 .await
90 .map_err(|err| self.error(err, ErrorKind::Metadata))
91 }
92
93 pub async fn try_clone(&self) -> io::Result<File> {
99 match self.tokio.try_clone().await {
100 Ok(file) => Ok(File::from_parts(file, self.path.clone())),
101 Err(err) => Err(self.error(err, ErrorKind::Clone)),
102 }
103 }
104
105 pub async fn into_std(self) -> crate::File {
110 crate::File::from_parts(self.tokio.into_std().await, self.path)
111 }
112
113 pub fn try_into_std(self) -> Result<crate::File, File> {
117 match self.tokio.try_into_std() {
118 Ok(f) => Ok(crate::File::from_parts(f, self.path)),
119 Err(f) => Err(File::from_parts(f, self.path)),
120 }
121 }
122
123 pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
127 self.tokio
128 .set_permissions(perm)
129 .await
130 .map_err(|err| self.error(err, ErrorKind::SetPermissions))
131 }
132}
133
134impl File {
137 pub fn from_parts<P>(file: TokioFile, path: P) -> Self
139 where
140 P: Into<PathBuf>,
141 {
142 File {
143 tokio: file,
144 path: path.into(),
145 }
146 }
147
148 pub fn into_parts(self) -> (TokioFile, PathBuf) {
150 (self.tokio, self.path)
151 }
152
153 pub fn file(&self) -> &TokioFile {
155 &self.tokio
156 }
157
158 pub fn file_mut(&mut self) -> &mut TokioFile {
160 &mut self.tokio
161 }
162
163 pub fn path(&self) -> &Path {
165 &self.path
166 }
167
168 fn error(&self, source: io::Error, kind: ErrorKind) -> io::Error {
170 Error::build(source, kind, &self.path)
171 }
172}
173
174impl From<crate::File> for File {
175 fn from(f: crate::File) -> Self {
176 let (f, path) = f.into_parts();
177 File::from_parts(f.into(), path)
178 }
179}
180
181impl From<File> for TokioFile {
182 fn from(f: File) -> Self {
183 f.into_parts().0
184 }
185}
186
187#[cfg(unix)]
188impl std::os::unix::io::AsRawFd for File {
189 fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
190 self.tokio.as_raw_fd()
191 }
192}
193
194#[cfg(windows)]
195impl std::os::windows::io::AsRawHandle for File {
196 fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
197 self.tokio.as_raw_handle()
198 }
199}
200
201impl AsyncRead for File {
202 fn poll_read(
203 mut self: Pin<&mut Self>,
204 cx: &mut Context<'_>,
205 buf: &mut ReadBuf<'_>,
206 ) -> Poll<io::Result<()>> {
207 Poll::Ready(
208 ready!(Pin::new(&mut self.tokio).poll_read(cx, buf))
209 .map_err(|err| self.error(err, ErrorKind::Read)),
210 )
211 }
212}
213
214impl AsyncSeek for File {
215 fn start_seek(mut self: Pin<&mut Self>, position: SeekFrom) -> io::Result<()> {
216 Pin::new(&mut self.tokio)
217 .start_seek(position)
218 .map_err(|err| self.error(err, ErrorKind::Seek))
219 }
220
221 fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
222 Poll::Ready(
223 ready!(Pin::new(&mut self.tokio).poll_complete(cx))
224 .map_err(|err| self.error(err, ErrorKind::Seek)),
225 )
226 }
227}
228
229impl AsyncWrite for File {
230 fn poll_write(
231 mut self: Pin<&mut Self>,
232 cx: &mut Context<'_>,
233 buf: &[u8],
234 ) -> Poll<io::Result<usize>> {
235 Poll::Ready(
236 ready!(Pin::new(&mut self.tokio).poll_write(cx, buf))
237 .map_err(|err| self.error(err, ErrorKind::Write)),
238 )
239 }
240
241 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
242 Poll::Ready(
243 ready!(Pin::new(&mut self.tokio).poll_flush(cx))
244 .map_err(|err| self.error(err, ErrorKind::Flush)),
245 )
246 }
247
248 fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
249 Poll::Ready(
250 ready!(Pin::new(&mut self.tokio).poll_shutdown(cx))
251 .map_err(|err| self.error(err, ErrorKind::Flush)),
252 )
253 }
254
255 fn poll_write_vectored(
256 mut self: Pin<&mut Self>,
257 cx: &mut Context<'_>,
258 bufs: &[IoSlice<'_>],
259 ) -> Poll<io::Result<usize>> {
260 Poll::Ready(
261 ready!(Pin::new(&mut self.tokio).poll_write_vectored(cx, bufs))
262 .map_err(|err| self.error(err, ErrorKind::Write)),
263 )
264 }
265
266 fn is_write_vectored(&self) -> bool {
267 self.tokio.is_write_vectored()
268 }
269}