use std::os::unix::io::{IntoRawFd,AsRawFd,FromRawFd,RawFd};
use std::mem::{forget, transmute};
use std::io;
use std::borrow::{Borrow,ToOwned};
use std::ops::{Deref};
extern crate libc;
unsafe fn dup(i: RawFd) -> io::Result<RawFd> {
let v = libc::dup(i);
if v < 0 {
Err(io::Error::last_os_error())
} else {
Ok(v)
}
}
pub struct OwnedFd {
inner: RawFd,
}
impl OwnedFd {
pub unsafe fn from_unowned_raw(i : RawFd) -> io::Result<OwnedFd> {
Ok(OwnedFd { inner: try!(dup(i)) })
}
pub fn dup(&self) -> io::Result<OwnedFd> {
unsafe { OwnedFd::from_unowned_raw(self.as_raw_fd()) }
}
pub fn from<T: IntoRawFd>(i: T) -> Self {
OwnedFd { inner: i.into_raw_fd() }
}
}
impl AsRawFd for OwnedFd {
fn as_raw_fd(&self) -> RawFd {
self.inner
}
}
impl IntoRawFd for OwnedFd {
fn into_raw_fd(self) -> RawFd {
let v = self.inner;
forget(self);
v
}
}
impl FromRawFd for OwnedFd {
unsafe fn from_raw_fd(fd: RawFd) -> OwnedFd {
OwnedFd { inner: fd }
}
}
impl Drop for OwnedFd {
fn drop(&mut self) {
unsafe { libc::close(self.inner) };
}
}
impl Clone for OwnedFd {
fn clone(&self) -> Self {
self.dup().unwrap()
}
}
impl Borrow<FdRef> for OwnedFd {
fn borrow(&self) -> &FdRef {
unsafe { FdRef::from_unowned_raw(self.as_raw_fd()) }
}
}
impl Deref for OwnedFd {
type Target = FdRef;
fn deref(&self) -> &Self::Target {
self.borrow()
}
}
pub struct FdRef {
#[doc(hidden)]
__nothing: ()
}
impl FdRef {
pub unsafe fn from_unowned_raw<'a>(i: RawFd) -> &'a FdRef{
transmute(i as isize)
}
}
impl AsRawFd for FdRef {
fn as_raw_fd(&self) -> RawFd {
let i : isize = unsafe { transmute(self) };
i as RawFd
}
}
impl ToOwned for FdRef {
type Owned = OwnedFd;
fn to_owned(&self) -> Self::Owned {
unsafe { OwnedFd::from_unowned_raw(self.as_raw_fd()).unwrap() }
}
}
#[cfg(test)]
mod tests {
extern crate tempfile;
use super::{OwnedFd,FdRef};
use std::borrow::Borrow;
use std::os::unix::io::{AsRawFd};
#[test]
fn it_works() {
let t = tempfile::tempfile().unwrap();
let fd = OwnedFd::from(t);
let r : &FdRef = fd.borrow();
assert!(r.to_owned().as_raw_fd() != fd.as_raw_fd());
}
}