use std::io;
use std::os::unix::io::AsRawFd;
use std::os::unix::io::RawFd;
use std::sync::Arc;
pub trait ManagedFD
where
Self: AsRawFd + Clone,
{
fn wrap(fd: RawFd) -> Self;
fn dup_wrap(fd: RawFd) -> io::Result<Self>;
fn dup(&self) -> io::Result<Self>;
}
struct AutoClosingFD(RawFd);
impl AutoClosingFD{
#[inline]
fn wrap(fd: RawFd) -> Self {
AutoClosingFD(fd)
}
#[inline]
fn dup_wrap(fd: RawFd) -> io::Result<Self> {
let new_handle = unsafe { libc::dup(fd) };
if new_handle == -1 {
Err(io::Error::last_os_error())
} else {
Ok(Self::wrap(new_handle))
}
}
}
impl Drop for AutoClosingFD{
fn drop(&mut self) {
if self.0 >= 0 {
unsafe { libc::close(self.0) };
self.0 = -1;
}
}
}
impl AsRawFd for AutoClosingFD {
fn as_raw_fd(&self) -> RawFd {
self.0
}
}
pub struct DuplicatingFD(AutoClosingFD);
impl ManagedFD for DuplicatingFD {
fn wrap(fd: RawFd) -> Self {
DuplicatingFD(AutoClosingFD::wrap(fd))
}
fn dup_wrap(fd: RawFd) -> io::Result<Self> {
Ok(DuplicatingFD(AutoClosingFD::dup_wrap(fd)?))
}
fn dup(&self) -> io::Result<Self> {
let new_handle = unsafe { libc::dup(self.as_raw_fd()) };
if new_handle == -1 {
Err(io::Error::last_os_error())
} else {
Ok(Self::wrap(new_handle))
}
}
}
impl Clone for DuplicatingFD {
fn clone(&self) -> Self {
self.dup().unwrap()
}
fn clone_from(&mut self, source: &Self) {
assert!(source.as_raw_fd()>=0);
assert!(self.as_raw_fd()>=0);
if source.as_raw_fd() != self.as_raw_fd() {
unsafe { libc::close(self.as_raw_fd()) };
let rc = unsafe { libc::dup2(source.as_raw_fd(), self.as_raw_fd()) };
if rc == -1 {
panic!(io::Error::last_os_error());
}
}
}
}
impl AsRawFd for DuplicatingFD {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
pub struct SharedFD(Arc<AutoClosingFD>);
impl ManagedFD for SharedFD {
fn wrap(fd: RawFd) -> Self {
SharedFD(Arc::new(AutoClosingFD::wrap(fd)))
}
fn dup_wrap(fd: RawFd) -> io::Result<Self> {
Ok(SharedFD(Arc::new(AutoClosingFD::dup_wrap(fd)?)))
}
fn dup(&self) -> io::Result<Self> {
Ok(SharedFD(self.0.clone()))
}
}
impl AsRawFd for SharedFD {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
impl Clone for SharedFD {
fn clone(&self) -> Self {
self.dup().unwrap()
}
}