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#[allow(unused_imports)]
15use crate as fs_err; #[derive(Debug)]
20#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
21pub struct File {
22 tokio: fs::File,
23 path: PathBuf,
24}
25
26impl File {
27 pub async fn open(path: impl Into<PathBuf>) -> io::Result<File> {
31 let path = path.into();
32 let f = TokioFile::open(&path)
33 .await
34 .map_err(|err| Error::build(err, ErrorKind::OpenFile, &path))?;
35 Ok(File::from_parts(f, path))
36 }
37
38 pub async fn create(path: impl Into<PathBuf>) -> io::Result<File> {
42 let path = path.into();
43 match TokioFile::create(&path).await {
44 Ok(f) => Ok(File::from_parts(f, path)),
45 Err(err) => Err(Error::build(err, ErrorKind::CreateFile, &path)),
46 }
47 }
48
49 pub async fn create_new(path: impl Into<PathBuf>) -> Result<Self, io::Error> {
53 let path = path.into();
54 match fs::File::create_new(&path).await {
55 Ok(file) => Ok(File::from_parts(file, path)),
56 Err(err) => Err(Error::build(err, ErrorKind::CreateFile, path)),
57 }
58 }
59
60 pub fn options() -> OpenOptions {
64 OpenOptions::new()
65 }
66
67 pub fn from_std(std: crate::File) -> File {
71 let (std, path) = std.into_parts();
72 File::from_parts(TokioFile::from_std(std), path)
73 }
74
75 pub async fn sync_all(&self) -> io::Result<()> {
79 self.tokio
80 .sync_all()
81 .await
82 .map_err(|err| self.error(err, ErrorKind::SyncFile))
83 }
84
85 pub async fn sync_data(&self) -> io::Result<()> {
90 self.tokio
91 .sync_data()
92 .await
93 .map_err(|err| self.error(err, ErrorKind::SyncFile))
94 }
95
96 pub async fn set_len(&self, size: u64) -> io::Result<()> {
100 self.tokio
101 .set_len(size)
102 .await
103 .map_err(|err| self.error(err, ErrorKind::SetLen))
104 }
105
106 pub async fn metadata(&self) -> io::Result<Metadata> {
110 self.tokio
111 .metadata()
112 .await
113 .map_err(|err| self.error(err, ErrorKind::Metadata))
114 }
115
116 pub async fn try_clone(&self) -> io::Result<File> {
122 match self.tokio.try_clone().await {
123 Ok(file) => Ok(File::from_parts(file, self.path.clone())),
124 Err(err) => Err(self.error(err, ErrorKind::Clone)),
125 }
126 }
127
128 pub async fn into_std(self) -> crate::File {
133 crate::File::from_parts(self.tokio.into_std().await, self.path)
134 }
135
136 pub fn try_into_std(self) -> Result<crate::File, File> {
140 match self.tokio.try_into_std() {
141 Ok(f) => Ok(crate::File::from_parts(f, self.path)),
142 Err(f) => Err(File::from_parts(f, self.path)),
143 }
144 }
145
146 pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
150 self.tokio
151 .set_permissions(perm)
152 .await
153 .map_err(|err| self.error(err, ErrorKind::SetPermissions))
154 }
155}
156
157impl File {
159 pub fn from_parts<P>(file: TokioFile, path: P) -> Self
161 where
162 P: Into<PathBuf>,
163 {
164 File {
165 tokio: file,
166 path: path.into(),
167 }
168 }
169
170 pub fn into_parts(self) -> (TokioFile, PathBuf) {
172 (self.tokio, self.path)
173 }
174
175 pub fn file(&self) -> &TokioFile {
177 &self.tokio
178 }
179
180 pub fn file_mut(&mut self) -> &mut TokioFile {
182 &mut self.tokio
183 }
184
185 pub fn path(&self) -> &Path {
187 &self.path
188 }
189
190 fn error(&self, source: io::Error, kind: ErrorKind) -> io::Error {
192 Error::build(source, kind, &self.path)
193 }
194}
195
196impl From<crate::File> for File {
197 fn from(f: crate::File) -> Self {
198 let (f, path) = f.into_parts();
199 File::from_parts(f.into(), path)
200 }
201}
202
203impl From<File> for TokioFile {
204 fn from(f: File) -> Self {
205 f.into_parts().0
206 }
207}
208
209#[cfg(unix)]
210impl std::os::unix::io::AsRawFd for File {
211 fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
212 self.tokio.as_raw_fd()
213 }
214}
215
216#[cfg(windows)]
217impl std::os::windows::io::AsRawHandle for File {
218 fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
219 self.tokio.as_raw_handle()
220 }
221}
222
223impl AsyncRead for File {
224 fn poll_read(
225 mut self: Pin<&mut Self>,
226 cx: &mut Context<'_>,
227 buf: &mut ReadBuf<'_>,
228 ) -> Poll<io::Result<()>> {
229 Poll::Ready(
230 ready!(Pin::new(&mut self.tokio).poll_read(cx, buf))
231 .map_err(|err| self.error(err, ErrorKind::Read)),
232 )
233 }
234}
235
236impl AsyncSeek for File {
237 fn start_seek(mut self: Pin<&mut Self>, position: SeekFrom) -> io::Result<()> {
238 Pin::new(&mut self.tokio)
239 .start_seek(position)
240 .map_err(|err| self.error(err, ErrorKind::Seek))
241 }
242
243 fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
244 Poll::Ready(
245 ready!(Pin::new(&mut self.tokio).poll_complete(cx))
246 .map_err(|err| self.error(err, ErrorKind::Seek)),
247 )
248 }
249}
250
251impl AsyncWrite for File {
252 fn poll_write(
253 mut self: Pin<&mut Self>,
254 cx: &mut Context<'_>,
255 buf: &[u8],
256 ) -> Poll<io::Result<usize>> {
257 Poll::Ready(
258 ready!(Pin::new(&mut self.tokio).poll_write(cx, buf))
259 .map_err(|err| self.error(err, ErrorKind::Write)),
260 )
261 }
262
263 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
264 Poll::Ready(
265 ready!(Pin::new(&mut self.tokio).poll_flush(cx))
266 .map_err(|err| self.error(err, ErrorKind::Flush)),
267 )
268 }
269
270 fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
271 Poll::Ready(
272 ready!(Pin::new(&mut self.tokio).poll_shutdown(cx))
273 .map_err(|err| self.error(err, ErrorKind::Flush)),
274 )
275 }
276
277 fn poll_write_vectored(
278 mut self: Pin<&mut Self>,
279 cx: &mut Context<'_>,
280 bufs: &[IoSlice<'_>],
281 ) -> Poll<io::Result<usize>> {
282 Poll::Ready(
283 ready!(Pin::new(&mut self.tokio).poll_write_vectored(cx, bufs))
284 .map_err(|err| self.error(err, ErrorKind::Write)),
285 )
286 }
287
288 fn is_write_vectored(&self) -> bool {
289 self.tokio.is_write_vectored()
290 }
291}