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
12use super::OpenOptions;
13
14#[derive(Debug)]
17#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
18pub struct File {
19 tokio: fs::File,
20 path: PathBuf,
21}
22
23impl File {
24 pub async fn open(path: impl Into<PathBuf>) -> io::Result<File> {
28 let path = path.into();
29 let f = TokioFile::open(&path)
30 .await
31 .map_err(|err| Error::build(err, ErrorKind::OpenFile, &path))?;
32 Ok(File::from_parts(f, path))
33 }
34
35 pub async fn create(path: impl Into<PathBuf>) -> io::Result<File> {
39 let path = path.into();
40 match TokioFile::create(&path).await {
41 Ok(f) => Ok(File::from_parts(f, path)),
42 Err(err) => Err(Error::build(err, ErrorKind::CreateFile, &path)),
43 }
44 }
45
46 pub async fn create_new(path: impl Into<PathBuf>) -> Result<Self, io::Error> {
50 let path = path.into();
51 match fs::File::create_new(&path).await {
52 Ok(file) => Ok(File::from_parts(file, path)),
53 Err(err) => Err(Error::build(err, ErrorKind::CreateFile, path)),
54 }
55 }
56
57 pub fn options() -> OpenOptions {
61 OpenOptions::new()
62 }
63
64 pub fn from_std(std: crate::File) -> File {
68 let (std, path) = std.into_parts();
69 File::from_parts(TokioFile::from_std(std), path)
70 }
71
72 pub async fn sync_all(&self) -> io::Result<()> {
76 self.tokio
77 .sync_all()
78 .await
79 .map_err(|err| self.error(err, ErrorKind::SyncFile))
80 }
81
82 pub async fn sync_data(&self) -> io::Result<()> {
87 self.tokio
88 .sync_data()
89 .await
90 .map_err(|err| self.error(err, ErrorKind::SyncFile))
91 }
92
93 pub async fn set_len(&self, size: u64) -> io::Result<()> {
97 self.tokio
98 .set_len(size)
99 .await
100 .map_err(|err| self.error(err, ErrorKind::SetLen))
101 }
102
103 pub async fn metadata(&self) -> io::Result<Metadata> {
107 self.tokio
108 .metadata()
109 .await
110 .map_err(|err| self.error(err, ErrorKind::Metadata))
111 }
112
113 pub async fn try_clone(&self) -> io::Result<File> {
119 match self.tokio.try_clone().await {
120 Ok(file) => Ok(File::from_parts(file, self.path.clone())),
121 Err(err) => Err(self.error(err, ErrorKind::Clone)),
122 }
123 }
124
125 pub async fn into_std(self) -> crate::File {
130 crate::File::from_parts(self.tokio.into_std().await, self.path)
131 }
132
133 pub fn try_into_std(self) -> Result<crate::File, File> {
137 match self.tokio.try_into_std() {
138 Ok(f) => Ok(crate::File::from_parts(f, self.path)),
139 Err(f) => Err(File::from_parts(f, self.path)),
140 }
141 }
142
143 pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
147 self.tokio
148 .set_permissions(perm)
149 .await
150 .map_err(|err| self.error(err, ErrorKind::SetPermissions))
151 }
152}
153
154impl File {
157 pub fn from_parts<P>(file: TokioFile, path: P) -> Self
159 where
160 P: Into<PathBuf>,
161 {
162 File {
163 tokio: file,
164 path: path.into(),
165 }
166 }
167
168 pub fn into_parts(self) -> (TokioFile, PathBuf) {
170 (self.tokio, self.path)
171 }
172
173 pub fn file(&self) -> &TokioFile {
175 &self.tokio
176 }
177
178 pub fn file_mut(&mut self) -> &mut TokioFile {
180 &mut self.tokio
181 }
182
183 pub fn path(&self) -> &Path {
185 &self.path
186 }
187
188 fn error(&self, source: io::Error, kind: ErrorKind) -> io::Error {
190 Error::build(source, kind, &self.path)
191 }
192}
193
194impl From<crate::File> for File {
195 fn from(f: crate::File) -> Self {
196 let (f, path) = f.into_parts();
197 File::from_parts(f.into(), path)
198 }
199}
200
201impl From<File> for TokioFile {
202 fn from(f: File) -> Self {
203 f.into_parts().0
204 }
205}
206
207#[cfg(unix)]
208impl std::os::unix::io::AsRawFd for File {
209 fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
210 self.tokio.as_raw_fd()
211 }
212}
213
214#[cfg(windows)]
215impl std::os::windows::io::AsRawHandle for File {
216 fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
217 self.tokio.as_raw_handle()
218 }
219}
220
221impl AsyncRead for File {
222 fn poll_read(
223 mut self: Pin<&mut Self>,
224 cx: &mut Context<'_>,
225 buf: &mut ReadBuf<'_>,
226 ) -> Poll<io::Result<()>> {
227 Poll::Ready(
228 ready!(Pin::new(&mut self.tokio).poll_read(cx, buf))
229 .map_err(|err| self.error(err, ErrorKind::Read)),
230 )
231 }
232}
233
234impl AsyncSeek for File {
235 fn start_seek(mut self: Pin<&mut Self>, position: SeekFrom) -> io::Result<()> {
236 Pin::new(&mut self.tokio)
237 .start_seek(position)
238 .map_err(|err| self.error(err, ErrorKind::Seek))
239 }
240
241 fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
242 Poll::Ready(
243 ready!(Pin::new(&mut self.tokio).poll_complete(cx))
244 .map_err(|err| self.error(err, ErrorKind::Seek)),
245 )
246 }
247}
248
249impl AsyncWrite for File {
250 fn poll_write(
251 mut self: Pin<&mut Self>,
252 cx: &mut Context<'_>,
253 buf: &[u8],
254 ) -> Poll<io::Result<usize>> {
255 Poll::Ready(
256 ready!(Pin::new(&mut self.tokio).poll_write(cx, buf))
257 .map_err(|err| self.error(err, ErrorKind::Write)),
258 )
259 }
260
261 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
262 Poll::Ready(
263 ready!(Pin::new(&mut self.tokio).poll_flush(cx))
264 .map_err(|err| self.error(err, ErrorKind::Flush)),
265 )
266 }
267
268 fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
269 Poll::Ready(
270 ready!(Pin::new(&mut self.tokio).poll_shutdown(cx))
271 .map_err(|err| self.error(err, ErrorKind::Flush)),
272 )
273 }
274
275 fn poll_write_vectored(
276 mut self: Pin<&mut Self>,
277 cx: &mut Context<'_>,
278 bufs: &[IoSlice<'_>],
279 ) -> Poll<io::Result<usize>> {
280 Poll::Ready(
281 ready!(Pin::new(&mut self.tokio).poll_write_vectored(cx, bufs))
282 .map_err(|err| self.error(err, ErrorKind::Write)),
283 )
284 }
285
286 fn is_write_vectored(&self) -> bool {
287 self.tokio.is_write_vectored()
288 }
289}