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 ToSharedFd, impl_raw_fd,
8 op::{
9 AsyncifyFd, BufResultExt, CloseFile, ReadAt, ReadManagedAt, ResultTakeBuffer, Sync, WriteAt,
10 },
11};
12use compio_io::{AsyncReadAt, AsyncReadManagedAt, AsyncWriteAt, util::Splittable};
13use compio_runtime::{Attacher, BorrowedBuffer, BufferPool};
14#[cfg(all(unix, not(solarish)))]
15use {
16 compio_buf::{IoVectoredBuf, IoVectoredBufMut},
17 compio_driver::op::{ReadVectoredAt, WriteVectoredAt},
18};
19
20use crate::{Metadata, OpenOptions, Permissions};
21
22#[derive(Debug, Clone)]
53pub struct File {
54 inner: Attacher<std::fs::File>,
55}
56
57impl File {
58 pub(crate) fn from_std(file: std::fs::File) -> io::Result<Self> {
59 Ok(Self {
60 inner: Attacher::new(file)?,
61 })
62 }
63
64 pub async fn open(path: impl AsRef<Path>) -> io::Result<Self> {
68 OpenOptions::new().read(true).open(path).await
69 }
70
71 pub async fn create(path: impl AsRef<Path>) -> io::Result<Self> {
78 OpenOptions::new()
79 .create(true)
80 .write(true)
81 .truncate(true)
82 .open(path)
83 .await
84 }
85
86 pub fn close(self) -> impl Future<Output = io::Result<()>> {
89 let this = ManuallyDrop::new(self);
93 async move {
94 let fd = ManuallyDrop::into_inner(this)
95 .inner
96 .into_inner()
97 .take()
98 .await;
99 if let Some(fd) = fd {
100 let op = CloseFile::new(fd.into());
101 compio_runtime::submit(op).await.0?;
102 }
103 Ok(())
104 }
105 }
106
107 #[cfg(windows)]
109 pub async fn metadata(&self) -> io::Result<Metadata> {
110 let op = AsyncifyFd::new(self.to_shared_fd(), |file: &std::fs::File| {
111 match file.metadata().map(Metadata::from_std) {
112 Ok(meta) => BufResult(Ok(0), Some(meta)),
113 Err(e) => BufResult(Err(e), None),
114 }
115 });
116 let BufResult(res, meta) = compio_runtime::submit(op).await;
117 res.map(|_| meta.into_inner().expect("metadata should be present"))
118 }
119
120 #[cfg(unix)]
122 pub async fn metadata(&self) -> io::Result<Metadata> {
123 let op = FileStat::new(self.to_shared_fd());
124 let BufResult(res, op) = compio_runtime::submit(op).await;
125 res.map(|_| Metadata::from_stat(op.into_inner()))
126 }
127
128 pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
130 let op = AsyncifyFd::new(self.to_shared_fd(), move |file: &std::fs::File| {
131 BufResult(file.set_permissions(perm.0).map(|_| 0), ())
132 });
133 compio_runtime::submit(op).await.0.map(|_| ())
134 }
135
136 async fn sync_impl(&self, datasync: bool) -> io::Result<()> {
137 let op = Sync::new(self.to_shared_fd(), datasync);
138 compio_runtime::submit(op).await.0?;
139 Ok(())
140 }
141
142 pub async fn sync_all(&self) -> io::Result<()> {
147 self.sync_impl(false).await
148 }
149
150 pub async fn sync_data(&self) -> io::Result<()> {
162 self.sync_impl(true).await
163 }
164}
165
166impl AsyncReadAt for File {
167 async fn read_at<T: IoBufMut>(&self, buffer: T, pos: u64) -> BufResult<usize, T> {
168 let fd = self.inner.to_shared_fd();
169 let op = ReadAt::new(fd, pos, buffer);
170 compio_runtime::submit(op).await.into_inner().map_advanced()
171 }
172
173 #[cfg(all(unix, not(solarish)))]
174 async fn read_vectored_at<T: IoVectoredBufMut>(
175 &self,
176 buffer: T,
177 pos: u64,
178 ) -> BufResult<usize, T> {
179 let fd = self.inner.to_shared_fd();
180 let op = ReadVectoredAt::new(fd, pos, buffer);
181 compio_runtime::submit(op).await.into_inner().map_advanced()
182 }
183}
184
185impl AsyncReadManagedAt for File {
186 type Buffer<'a> = BorrowedBuffer<'a>;
187 type BufferPool = BufferPool;
188
189 async fn read_managed_at<'a>(
190 &self,
191 buffer_pool: &'a Self::BufferPool,
192 len: usize,
193 pos: u64,
194 ) -> io::Result<Self::Buffer<'a>> {
195 let fd = self.inner.to_shared_fd();
196 let buffer_pool = buffer_pool.try_inner()?;
197 let op = ReadManagedAt::new(fd, pos, buffer_pool, len)?;
198 compio_runtime::submit_with_flags(op)
199 .await
200 .take_buffer(buffer_pool)
201 }
202}
203
204impl AsyncWriteAt for File {
205 #[inline]
206 async fn write_at<T: IoBuf>(&mut self, buf: T, pos: u64) -> BufResult<usize, T> {
207 (&*self).write_at(buf, pos).await
208 }
209
210 #[cfg(all(unix, not(solarish)))]
211 #[inline]
212 async fn write_vectored_at<T: IoVectoredBuf>(
213 &mut self,
214 buf: T,
215 pos: u64,
216 ) -> BufResult<usize, T> {
217 (&*self).write_vectored_at(buf, pos).await
218 }
219}
220
221impl AsyncWriteAt for &File {
222 async fn write_at<T: IoBuf>(&mut self, buffer: T, pos: u64) -> BufResult<usize, T> {
223 let fd = self.inner.to_shared_fd();
224 let op = WriteAt::new(fd, pos, buffer);
225 compio_runtime::submit(op).await.into_inner()
226 }
227
228 #[cfg(all(unix, not(solarish)))]
229 async fn write_vectored_at<T: IoVectoredBuf>(
230 &mut self,
231 buffer: T,
232 pos: u64,
233 ) -> BufResult<usize, T> {
234 let fd = self.inner.to_shared_fd();
235 let op = WriteVectoredAt::new(fd, pos, buffer);
236 compio_runtime::submit(op).await.into_inner()
237 }
238}
239
240impl Splittable for File {
241 type ReadHalf = File;
242 type WriteHalf = File;
243
244 fn split(self) -> (Self::ReadHalf, Self::WriteHalf) {
245 (self.clone(), self)
246 }
247}
248
249impl Splittable for &File {
250 type ReadHalf = File;
251 type WriteHalf = File;
252
253 fn split(self) -> (Self::ReadHalf, Self::WriteHalf) {
254 (self.clone(), self.clone())
255 }
256}
257
258impl_raw_fd!(File, std::fs::File, inner, file);