1use std::{future::Future, io, mem::ManuallyDrop, path::Path};
2
3use compio_buf::{BufResult, IntoInner, IoBuf, IoBufMut};
4#[cfg(unix)]
5use compio_driver::op::FileStat;
6use compio_driver::{
7 BufferRef, ResultTakeBuffer, ToSharedFd, impl_raw_fd,
8 op::{BufResultExt, CloseFile, ReadAt, ReadManagedAt, Sync, WriteAt},
9};
10use compio_io::{AsyncReadAt, AsyncReadManagedAt, AsyncWriteAt, util::Splittable};
11use compio_runtime::{Runtime, fd::AsyncFd};
12#[cfg(all(unix, not(solarish)))]
13use {
14 compio_buf::{IoVectoredBuf, IoVectoredBufMut},
15 compio_driver::op::{ReadVectoredAt, WriteVectoredAt},
16};
17
18use crate::{Metadata, OpenOptions, Permissions};
19
20#[derive(Debug, Clone)]
51pub struct File {
52 pub(crate) inner: AsyncFd<std::fs::File>,
53}
54
55impl File {
56 pub(crate) fn from_std(file: std::fs::File) -> io::Result<Self> {
57 Ok(Self {
58 inner: AsyncFd::new(file)?,
59 })
60 }
61
62 pub async fn open(path: impl AsRef<Path>) -> io::Result<Self> {
66 OpenOptions::new().read(true).open(path).await
67 }
68
69 pub async fn create(path: impl AsRef<Path>) -> io::Result<Self> {
76 OpenOptions::new()
77 .create(true)
78 .write(true)
79 .truncate(true)
80 .open(path)
81 .await
82 }
83
84 pub fn close(self) -> impl Future<Output = io::Result<()>> {
95 let this = ManuallyDrop::new(self);
99 async move {
100 let fd = ManuallyDrop::into_inner(this)
101 .inner
102 .into_inner()
103 .take()
104 .await;
105 if let Some(fd) = fd {
106 let op = CloseFile::new(fd.into());
107 compio_runtime::submit(op).await.0?;
108 }
109 Ok(())
110 }
111 }
112
113 #[cfg(windows)]
115 pub async fn metadata(&self) -> io::Result<Metadata> {
116 crate::spawn_blocking_with(self.to_shared_fd(), |file| {
117 file.metadata().map(Metadata::from_std)
118 })
119 .await
120 }
121
122 #[cfg(windows)]
123 pub async fn set_len(&self, size: u64) -> io::Result<()> {
126 crate::spawn_blocking_with(self.to_shared_fd(), move |file| file.set_len(size)).await
127 }
128
129 #[cfg(unix)]
130 pub async fn set_len(&self, size: u64) -> io::Result<()> {
136 use compio_driver::op::TruncateFile;
137
138 let op = TruncateFile::new(self.to_shared_fd(), size);
139 compio_runtime::submit(op).await.0.map(|_| ())
140 }
141
142 #[cfg(unix)]
144 pub async fn metadata(&self) -> io::Result<Metadata> {
145 let op = FileStat::new(self.to_shared_fd());
146 let BufResult(res, op) = compio_runtime::submit(op).await;
147 res.map(|_| Metadata::from_stat(op.into_inner()))
148 }
149
150 #[cfg(windows)]
152 pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
153 crate::spawn_blocking_with(self.to_shared_fd(), move |file| {
154 if let Some(p) = perm.0.original {
155 file.set_permissions(p)
156 } else {
157 let mut p = file.metadata()?.permissions();
158 p.set_readonly(perm.readonly());
159 file.set_permissions(p)
160 }
161 })
162 .await
163 }
164
165 #[cfg(unix)]
167 pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
168 crate::spawn_blocking_with(self.to_shared_fd(), |file| file.set_permissions(perm.0)).await
169 }
170
171 async fn sync_impl(&self, datasync: bool) -> io::Result<()> {
172 let op = Sync::new(self.to_shared_fd(), datasync);
173 compio_runtime::submit(op).await.0?;
174 Ok(())
175 }
176
177 pub async fn sync_all(&self) -> io::Result<()> {
182 self.sync_impl(false).await
183 }
184
185 pub async fn sync_data(&self) -> io::Result<()> {
197 self.sync_impl(true).await
198 }
199}
200
201impl AsyncReadAt for File {
202 async fn read_at<T: IoBufMut>(&self, buffer: T, pos: u64) -> BufResult<usize, T> {
203 let fd = self.inner.to_shared_fd();
204 let op = ReadAt::new(fd, pos, buffer);
205 let res = compio_runtime::submit(op).await.into_inner();
206 unsafe { res.map_advanced() }
207 }
208
209 #[cfg(all(unix, not(solarish)))]
210 async fn read_vectored_at<T: IoVectoredBufMut>(
211 &self,
212 buffer: T,
213 pos: u64,
214 ) -> BufResult<usize, T> {
215 use compio_driver::op::VecBufResultExt;
216
217 let fd = self.inner.to_shared_fd();
218 let op = ReadVectoredAt::new(fd, pos, buffer);
219 let res = compio_runtime::submit(op).await.into_inner();
220 unsafe { res.map_vec_advanced() }
221 }
222}
223
224impl AsyncReadManagedAt for File {
225 type Buffer = BufferRef;
226
227 async fn read_managed_at(&self, len: usize, pos: u64) -> io::Result<Option<Self::Buffer>> {
228 let fd = self.inner.to_shared_fd();
229 let res = Runtime::with_current(|rt| {
230 let buffer_pool = rt.buffer_pool()?;
231 let op = ReadManagedAt::new(fd, pos, &buffer_pool, len)?;
232 io::Result::Ok(rt.submit(op))
233 })?
234 .await;
235 unsafe { res.take_buffer() }
236 }
237}
238
239impl AsyncWriteAt for File {
240 #[inline]
241 async fn write_at<T: IoBuf>(&mut self, buf: T, pos: u64) -> BufResult<usize, T> {
242 (&*self).write_at(buf, pos).await
243 }
244
245 #[cfg(all(unix, not(solarish)))]
246 #[inline]
247 async fn write_vectored_at<T: IoVectoredBuf>(
248 &mut self,
249 buf: T,
250 pos: u64,
251 ) -> BufResult<usize, T> {
252 (&*self).write_vectored_at(buf, pos).await
253 }
254}
255
256impl AsyncWriteAt for &File {
257 async fn write_at<T: IoBuf>(&mut self, buffer: T, pos: u64) -> BufResult<usize, T> {
258 let fd = self.inner.to_shared_fd();
259 let op = WriteAt::new(fd, pos, buffer);
260 compio_runtime::submit(op).await.into_inner()
261 }
262
263 #[cfg(all(unix, not(solarish)))]
264 async fn write_vectored_at<T: IoVectoredBuf>(
265 &mut self,
266 buffer: T,
267 pos: u64,
268 ) -> BufResult<usize, T> {
269 let fd = self.inner.to_shared_fd();
270 let op = WriteVectoredAt::new(fd, pos, buffer);
271 compio_runtime::submit(op).await.into_inner()
272 }
273}
274
275impl Splittable for File {
276 type ReadHalf = File;
277 type WriteHalf = File;
278
279 fn split(self) -> (Self::ReadHalf, Self::WriteHalf) {
280 (self.clone(), self)
281 }
282}
283
284impl Splittable for &File {
285 type ReadHalf = File;
286 type WriteHalf = File;
287
288 fn split(self) -> (Self::ReadHalf, Self::WriteHalf) {
289 (self.clone(), self.clone())
290 }
291}
292
293impl Splittable for &mut File {
294 type ReadHalf = File;
295 type WriteHalf = File;
296
297 fn split(self) -> (Self::ReadHalf, Self::WriteHalf) {
298 (self.clone(), self.clone())
299 }
300}
301
302impl_raw_fd!(File, std::fs::File, inner, file);