llam 0.1.4

Safe, Go-style Rust bindings for the LLAM runtime
#[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),
    }
}