#[cfg(unix)]
use crate::io;
#[cfg(windows)]
use std::fs::File as StdFile;
#[cfg(unix)]
use std::fs::File as StdFile;
#[cfg(windows)]
use std::io::{self, Read, Result, Write};
#[cfg(unix)]
use std::io::{Read, Result, Write};
#[cfg(unix)]
use std::os::fd::{AsRawFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawHandle, RawHandle};
#[cfg(windows)]
use std::panic;
#[cfg(unix)]
use std::path::Path;
#[cfg(windows)]
use std::path::Path;
pub struct File {
inner: StdFile,
}
impl File {
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
Ok(Self {
inner: StdFile::open(path)?,
})
}
pub fn create<P: AsRef<Path>>(path: P) -> Result<Self> {
Ok(Self {
inner: StdFile::create(path)?,
})
}
pub fn from_std(inner: StdFile) -> Self {
Self { inner }
}
pub fn into_std(self) -> StdFile {
self.inner
}
}
#[cfg(unix)]
impl Read for File {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
io::read(self.inner.as_raw_fd(), buf)
}
}
#[cfg(windows)]
impl Read for File {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let mut file = self.inner.try_clone()?;
let len = buf.len();
let (n, tmp) = blocking_io(move || {
let mut tmp = vec![0u8; len];
let n = file.read(&mut tmp)?;
Ok((n, tmp))
})?;
buf[..n].copy_from_slice(&tmp[..n]);
Ok(n)
}
}
#[cfg(unix)]
impl Write for File {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
io::write(self.inner.as_raw_fd(), buf)
}
fn flush(&mut self) -> Result<()> {
self.inner.flush()
}
}
#[cfg(windows)]
impl Write for File {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
let mut file = self.inner.try_clone()?;
let bytes = buf.to_vec();
blocking_io(move || file.write(&bytes))
}
fn flush(&mut self) -> Result<()> {
self.inner.flush()
}
}
#[cfg(unix)]
impl AsRawFd for File {
fn as_raw_fd(&self) -> RawFd {
self.inner.as_raw_fd()
}
}
#[cfg(windows)]
impl AsRawHandle for File {
fn as_raw_handle(&self) -> RawHandle {
self.inner.as_raw_handle()
}
}
#[cfg(windows)]
fn blocking_io<T, F>(f: F) -> Result<T>
where
T: Send + 'static,
F: FnOnce() -> Result<T> + Send + 'static,
{
match crate::blocking::call(f).map_err(io::Error::from)? {
Ok(result) => result,
Err(payload) => panic::resume_unwind(payload),
}
}