use std::{
fmt,
io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write},
path::Path,
pin::Pin,
task::{Context, Poll, ready},
};
#[cfg(any(unix, target_os = "wasi"))]
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, OwnedHandle, RawHandle};
use futures_io::{AsyncRead, AsyncSeek, AsyncWrite};
use super::{Metadata, Permissions, inline};
use crate::coop;
pub struct File(std::fs::File);
impl File {
pub async fn open<P>(path: P) -> io::Result<File>
where
P: AsRef<Path>,
{
let file = inline(|| std::fs::File::open(path)).await?;
Ok(File::from(file))
}
pub async fn create<P>(path: P) -> io::Result<File>
where
P: AsRef<Path>,
{
let file = inline(|| std::fs::File::create(path)).await?;
Ok(File::from(file))
}
pub async fn sync_all(&self) -> io::Result<()> {
inline(|| self.0.sync_all()).await
}
pub async fn sync_data(&self) -> io::Result<()> {
inline(|| self.0.sync_data()).await
}
pub async fn set_len(&self, size: u64) -> io::Result<()> {
inline(|| self.0.set_len(size)).await
}
pub async fn metadata(&self) -> io::Result<Metadata> {
inline(|| self.0.metadata()).await
}
pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
inline(|| self.0.set_permissions(perm)).await
}
}
impl fmt::Debug for File {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl From<std::fs::File> for File {
fn from(file: std::fs::File) -> Self {
Self(file)
}
}
#[cfg(any(unix, target_os = "wasi"))]
impl From<OwnedFd> for File {
fn from(fd: OwnedFd) -> Self {
Self::from(std::fs::File::from(fd))
}
}
#[cfg(windows)]
impl From<OwnedHandle> for File {
fn from(handle: OwnedHandle) -> Self {
Self::from(std::fs::File::from(handle))
}
}
#[cfg(any(unix, target_os = "wasi"))]
impl AsFd for File {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
#[cfg(any(unix, target_os = "wasi"))]
impl AsRawFd for File {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
#[cfg(windows)]
impl AsHandle for File {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.0.as_handle()
}
}
#[cfg(windows)]
impl AsRawHandle for File {
fn as_raw_handle(&self) -> RawHandle {
self.0.as_raw_handle()
}
}
impl AsyncRead for File {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
poll_inline(cx, || (&self.0).read(buf))
}
fn poll_read_vectored(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &mut [IoSliceMut<'_>],
) -> Poll<io::Result<usize>> {
poll_inline(cx, || (&self.0).read_vectored(bufs))
}
}
impl AsyncWrite for File {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
poll_inline(cx, || (&self.0).write(buf))
}
fn poll_write_vectored(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &[IoSlice<'_>],
) -> Poll<io::Result<usize>> {
poll_inline(cx, || (&self.0).write_vectored(bufs))
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
poll_inline(cx, || (&self.0).flush())
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.poll_flush(cx)
}
}
impl AsyncSeek for File {
fn poll_seek(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
pos: SeekFrom,
) -> Poll<io::Result<u64>> {
poll_inline(cx, || (&self.0).seek(pos))
}
}
fn poll_inline<T, F>(cx: &mut Context<'_>, mut operation: F) -> Poll<io::Result<T>>
where
F: FnMut() -> io::Result<T>,
{
ready!(coop::poll_proceed(cx));
let result = loop {
match operation() {
Err(error) if error.kind() == io::ErrorKind::Interrupted => continue,
result => break result,
}
};
coop::spend();
Poll::Ready(result)
}