use crate::{
result::{Result},
util::{
error::{Errno},
retry::{retry},
io::{Read, Write},
data::{d8},
},
};
use crate::kty::{c_int, FD_CLOEXEC, O_CLOEXEC};
use crate::syscall::{
writev, readv, read, write, fcntl_getfd, fcntl_setfd, fcntl_getfl, fcntl_setfl,
fcntl_dupfd_cloexec, dup3,
};
use self::flags::{DescriptionFlags};
pub mod flags;
pub const STDIN: FdIo = FdIo(0);
pub const STDOUT: FdIo = FdIo(1);
pub const STDERR: FdIo = FdIo(2);
#[derive(Pod, Copy, Clone, PartialEq, Eq)]
pub struct FdIo(pub c_int);
pub trait FdContainer: Into<c_int> {
fn is_owned(&self) -> bool;
fn borrow(&self) -> c_int;
fn from_owned(fd: c_int) -> Self;
fn from_borrowed(fd: c_int) -> Self;
fn as_fdio(&self) -> FdIo {
FdIo(self.borrow())
}
fn is_close_on_exec(&self) -> Result<bool> {
let ret = fcntl_getfd(self.borrow());
if ret < 0 {
Err(Errno(-ret as c_int))
} else {
Ok(ret & FD_CLOEXEC != 0)
}
}
fn set_close_on_exec(&self, val: bool) -> Result {
let mut ret = fcntl_getfd(self.borrow());
if ret >= 0 {
ret = (ret & !FD_CLOEXEC) | (FD_CLOEXEC * val as c_int);
ret = fcntl_setfd(self.borrow(), ret);
}
rv!(ret)
}
fn description_flags(&self) -> Result<DescriptionFlags> {
let ret = fcntl_getfl(self.borrow());
if ret < 0 {
Err(Errno(-ret as c_int))
} else {
Ok(DescriptionFlags(ret))
}
}
fn set_description_flags(&self, flags: DescriptionFlags) -> Result {
let ret = fcntl_setfl(self.borrow(), flags.0);
rv!(ret)
}
fn duplicate(&self) -> Result<Self>
where Self: Sized
{
self.duplicate_min(0)
}
fn duplicate_min(&self, min: c_int) -> Result<Self>
where Self: Sized
{
let new = rv!(fcntl_dupfd_cloexec(self.borrow(), min), -> c_int)?;
Ok(Self::from_owned(new))
}
fn duplicate_as(&self, new: c_int) -> Result<Self>
where Self: Sized
{
let new = rv!(dup3(self.borrow(), new, O_CLOEXEC), -> c_int)?;
Ok(Self::from_owned(new))
}
}
impl Into<c_int> for FdIo {
fn into(self) -> c_int {
self.0
}
}
impl FdContainer for FdIo {
fn is_owned(&self) -> bool { false }
fn borrow(&self) -> c_int { self.0 }
fn from_owned(fd: c_int) -> FdIo { FdIo(fd) }
fn from_borrowed(fd: c_int) -> FdIo { FdIo(fd) }
}
impl FdContainer for c_int {
fn is_owned(&self) -> bool { false }
fn borrow(&self) -> c_int { *self }
fn from_owned(fd: c_int) -> c_int { fd }
fn from_borrowed(fd: c_int) -> c_int { fd }
}
macro_rules! impl_read {
($ty:ty) => {
impl Read for $ty {
fn scatter_read(&mut self, bufs: &mut [&mut [d8]]) -> Result<usize> {
retry(|| readv(self.borrow(), bufs)).map(|r| r as usize)
}
fn read(&mut self, buf: &mut [d8]) -> Result<usize> {
retry(|| read(self.borrow(), buf)).map(|r| r as usize)
}
}
}
}
impl_read!(FdIo);
impl_read!(&FdIo);
impl_std_read!(FdIo);
impl_std_read!(&FdIo);
macro_rules! impl_write {
($ty:ty) => {
impl Write for $ty {
fn gather_write(&mut self, bufs: &[&[u8]]) -> Result<usize> {
retry(|| writev(self.borrow(), d8::from_byte_slice_slice(bufs))).map(|r| r as usize)
}
fn write(&mut self, buf: &[u8]) -> Result<usize> {
retry(|| write(self.borrow(), d8::from_byte_slice(buf))).map(|r| r as usize)
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
}
}
impl_write!(FdIo);
impl_write!(&FdIo);
impl_std_write!(FdIo);
impl_std_write!(&FdIo);
impl Read for c_int {
fn scatter_read(&mut self, bufs: &mut [&mut [d8]]) -> Result<usize> {
retry(|| readv(*self, bufs)).map(|r| r as usize)
}
fn read(&mut self, buf: &mut [d8]) -> Result<usize> {
retry(|| read(*self, buf)).map(|r| r as usize)
}
}
impl Write for c_int {
fn gather_write(&mut self, bufs: &[&[u8]]) -> Result<usize> {
retry(|| writev(*self, d8::from_byte_slice_slice(bufs))).map(|r| r as usize)
}
fn write(&mut self, buf: &[u8]) -> Result<usize> {
retry(|| write(*self, d8::from_byte_slice(buf))).map(|r| r as usize)
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}