use std::path::Path;
#[cfg(unix)]
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, RawHandle};
use crate::{
buf::{BufResult, IoBuf, IoBufMut},
driver::{helpers::attached_handle::AttachedHandle, ops::Op},
fs::{Metadata, OpenOptions, Permissions},
io::{AsyncReadAt, AsyncWriteAt},
};
#[allow(unused_imports)]
use crate::buf::{IoVectoredBuf, IoVectoredBufMut};
#[derive(Debug, Clone)]
pub struct File {
pub(crate) handle: AttachedHandle<std::fs::File>,
}
impl File {
pub fn options() -> OpenOptions {
OpenOptions::new()
}
pub async fn create(path: impl AsRef<Path>) -> std::io::Result<File> {
OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path)
.await
}
pub async fn create_new(path: impl AsRef<Path>) -> std::io::Result<File> {
OpenOptions::new()
.read(true)
.write(true)
.create_new(true)
.open(path)
.await
}
pub async fn open(path: impl AsRef<Path>) -> std::io::Result<File> {
OpenOptions::new().read(true).open(path).await
}
pub async fn close(self) -> std::io::Result<()> {
self.handle.into_inner().close().await
}
pub async fn sync_all(&self) -> std::io::Result<()> {
Op::sync(&self.handle)?.await
}
pub async fn sync_data(&self) -> std::io::Result<()> {
Op::sync_data(&self.handle)?.await
}
pub async fn metadata(&self) -> std::io::Result<Metadata> {
Op::stat(&self.handle)?.await
}
pub async fn set_len(&self, size: u64) -> std::io::Result<()> {
Op::truncate(&self.handle, size)?.await
}
pub async fn set_permissions(&self, perm: Permissions) -> std::io::Result<()> {
#[cfg(target_os = "linux")]
{
use std::os::unix::fs::PermissionsExt;
let file = self.handle.try_clone()?;
let perm = std::fs::Permissions::from_mode(perm.mode());
crate::fs::asyncify(move || file.set_permissions(perm)).await
}
#[cfg(not(target_os = "linux"))]
{
Op::set_permissions(&self.handle, perm)?.await
}
}
pub async fn try_clone(&self) -> std::io::Result<Self> {
Self::from_std(self.handle.try_clone()?)
}
pub async fn into_std(self) -> std::fs::File {
self.handle
.into_inner()
.take()
.await
.expect("file resource was already taken")
}
pub fn try_into_std(self) -> Result<std::fs::File, Self> {
self.handle.try_unwrap().map_err(|handle| Self { handle })
}
}
impl File {
pub fn from_std(file: std::fs::File) -> std::io::Result<Self> {
Ok(Self {
handle: AttachedHandle::new(file)?,
})
}
}
impl From<AttachedHandle<std::fs::File>> for File {
fn from(handle: AttachedHandle<std::fs::File>) -> Self {
Self { handle }
}
}
impl AsyncReadAt for File {
async fn read_at<B: IoBufMut>(&self, buf: B, pos: u64) -> BufResult<usize, B> {
Op::read_at(&self.handle, buf, pos)
.expect("Failed to submit read operation (no runtime or driver error)")
.await
}
#[cfg(not(windows))]
async fn read_vectored_at<V: IoVectoredBufMut>(&self, bufs: V, pos: u64) -> BufResult<usize, V> {
Op::readv(&self.handle, bufs, pos)
.expect("Failed to submit readv operation (no runtime or driver error)")
.await
}
}
impl AsyncWriteAt for File {
async fn write_at<B: IoBuf>(&mut self, buf: B, pos: u64) -> BufResult<usize, B> {
Op::write_at(&self.handle, buf, pos)
.expect("Failed to submit write operation (no runtime or driver error)")
.await
}
#[cfg(not(windows))]
async fn write_vectored_at<V: IoVectoredBuf>(&mut self, bufs: V, pos: u64) -> BufResult<usize, V> {
Op::writev(&self.handle, bufs, pos)
.expect("Failed to submit writev operation (no runtime or driver error)")
.await
}
}
impl AsyncWriteAt for &File {
async fn write_at<B: IoBuf>(&mut self, buf: B, pos: u64) -> BufResult<usize, B> {
Op::write_at(&self.handle, buf, pos)
.expect("Failed to submit write operation (no runtime or driver error)")
.await
}
#[cfg(not(windows))]
async fn write_vectored_at<V: IoVectoredBuf>(&mut self, bufs: V, pos: u64) -> BufResult<usize, V> {
Op::writev(&self.handle, bufs, pos)
.expect("Failed to submit writev operation (no runtime or driver error)")
.await
}
}
#[cfg(unix)]
impl AsRawFd for File {
fn as_raw_fd(&self) -> RawFd {
self.handle.as_raw_fd()
}
}
#[cfg(unix)]
impl AsFd for File {
fn as_fd(&self) -> BorrowedFd<'_> {
self.handle.as_fd()
}
}
#[cfg(windows)]
impl AsRawHandle for File {
fn as_raw_handle(&self) -> RawHandle {
self.handle.as_raw_handle()
}
}
#[cfg(windows)]
impl AsHandle for File {
fn as_handle(&self) -> BorrowedHandle<'_> {
unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
}
}