use crate::fs::{Metadata, Permissions};
#[cfg(unix)]
use async_std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
#[cfg(target_os = "wasi")]
use async_std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use async_std::{
fs,
io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write},
task::{Context, Poll},
};
use cap_primitives::fs::is_file_read_write;
use std::{fmt, pin::Pin};
use unsafe_io::{AsUnsafeFile, OwnsRaw};
#[cfg(windows)]
use {
async_std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle},
unsafe_io::os::windows::{AsRawHandleOrSocket, IntoRawHandleOrSocket, RawHandleOrSocket},
};
pub struct File {
pub(crate) std: fs::File,
}
impl File {
#[inline]
pub unsafe fn from_std(std: fs::File) -> Self {
Self { std }
}
#[inline]
pub fn into_std(self) -> fs::File {
self.std
}
#[inline]
pub async fn sync_all(&self) -> io::Result<()> {
self.std.sync_all().await
}
#[inline]
pub async fn sync_data(&self) -> io::Result<()> {
self.std.sync_data().await
}
#[inline]
pub async fn set_len(&self, size: u64) -> io::Result<()> {
self.std.set_len(size).await
}
#[inline]
pub fn metadata(&self) -> io::Result<Metadata> {
let sync = self.std.as_file_view();
metadata_from(&*sync)
}
#[inline]
pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
let sync = self.std.as_file_view();
self.std
.set_permissions(permissions_into_std(&sync, perm)?)
.await
}
}
#[cfg(not(target_os = "wasi"))]
#[inline]
fn metadata_from(file: &std::fs::File) -> io::Result<Metadata> {
Metadata::from_file(file)
}
#[cfg(target_os = "wasi")]
#[inline]
fn metadata_from(file: &std::fs::File) -> io::Result<Metadata> {
file.metadata()
}
#[cfg(not(target_os = "wasi"))]
#[inline]
fn permissions_into_std(
file: &std::fs::File,
permissions: Permissions,
) -> io::Result<fs::Permissions> {
permissions.into_std(file)
}
#[cfg(target_os = "wasi")]
#[inline]
fn permissions_into_std(
_file: &std::fs::File,
permissions: Permissions,
) -> io::Result<fs::Permissions> {
permissions
}
#[cfg(not(windows))]
impl FromRawFd for File {
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self::from_std(fs::File::from_raw_fd(fd))
}
}
#[cfg(windows)]
impl FromRawHandle for File {
#[inline]
unsafe fn from_raw_handle(handle: RawHandle) -> Self {
Self::from_std(fs::File::from_raw_handle(handle))
}
}
#[cfg(not(windows))]
impl AsRawFd for File {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.std.as_raw_fd()
}
}
#[cfg(windows)]
impl AsRawHandle for File {
#[inline]
fn as_raw_handle(&self) -> RawHandle {
self.std.as_raw_handle()
}
}
#[cfg(windows)]
impl AsRawHandleOrSocket for File {
#[inline]
fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
self.std.as_raw_handle_or_socket()
}
}
#[cfg(not(windows))]
impl IntoRawFd for File {
#[inline]
fn into_raw_fd(self) -> RawFd {
self.std.into_raw_fd()
}
}
#[cfg(windows)]
impl IntoRawHandle for File {
#[inline]
fn into_raw_handle(self) -> RawHandle {
self.std.into_raw_handle()
}
}
#[cfg(windows)]
impl IntoRawHandleOrSocket for File {
#[inline]
fn into_raw_handle_or_socket(self) -> RawHandleOrSocket {
self.std.into_raw_handle_or_socket()
}
}
unsafe impl OwnsRaw for File {}
impl Read for File {
#[inline]
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Read::poll_read(Pin::new(&mut self.std), cx, buf)
}
#[inline]
fn poll_read_vectored(
mut self: Pin<&mut Self>,
cx: &mut Context,
bufs: &mut [IoSliceMut],
) -> Poll<io::Result<usize>> {
Read::poll_read_vectored(Pin::new(&mut self.std), cx, bufs)
}
}
impl Read for &File {
#[inline]
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Read::poll_read(Pin::new(&mut &self.std), cx, buf)
}
#[inline]
fn poll_read_vectored(
self: Pin<&mut Self>,
cx: &mut Context,
bufs: &mut [IoSliceMut],
) -> Poll<io::Result<usize>> {
Read::poll_read_vectored(Pin::new(&mut &self.std), cx, bufs)
}
}
impl Write for File {
#[inline]
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Write::poll_write(Pin::new(&mut self.std), cx, buf)
}
#[inline]
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
Write::poll_flush(Pin::new(&mut self.std), cx)
}
#[inline]
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
Write::poll_close(Pin::new(&mut self.std), cx)
}
#[inline]
fn poll_write_vectored(
mut self: Pin<&mut Self>,
cx: &mut Context,
bufs: &[IoSlice],
) -> Poll<io::Result<usize>> {
Write::poll_write_vectored(Pin::new(&mut self.std), cx, bufs)
}
}
impl Write for &File {
#[inline]
fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<io::Result<usize>> {
Write::poll_write(Pin::new(&mut &self.std), cx, buf)
}
#[inline]
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
Write::poll_flush(Pin::new(&mut &self.std), cx)
}
#[inline]
fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
Write::poll_close(Pin::new(&mut &self.std), cx)
}
#[inline]
fn poll_write_vectored(
self: Pin<&mut Self>,
cx: &mut Context,
bufs: &[IoSlice],
) -> Poll<io::Result<usize>> {
Write::poll_write_vectored(Pin::new(&mut &self.std), cx, bufs)
}
}
impl Seek for File {
#[inline]
fn poll_seek(
mut self: Pin<&mut Self>,
cx: &mut Context,
pos: SeekFrom,
) -> Poll<io::Result<u64>> {
Seek::poll_seek(Pin::new(&mut self.std), cx, pos)
}
}
impl Seek for &File {
#[inline]
fn poll_seek(self: Pin<&mut Self>, cx: &mut Context, pos: SeekFrom) -> Poll<io::Result<u64>> {
Seek::poll_seek(Pin::new(&mut &self.std), cx, pos)
}
}
impl fmt::Debug for File {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut b = f.debug_struct("File");
let file = self.std.as_file_view();
#[cfg(not(windows))]
b.field("fd", &file.as_raw_fd());
#[cfg(windows)]
b.field("handle", &file.as_raw_handle());
if let Ok((read, write)) = is_file_read_write(&file) {
b.field("read", &read).field("write", &write);
}
b.finish()
}
}