use IntoInner;
use io::FileDesc;
use mio::{Evented, Poll, PollOpt, Ready, Token};
use mio::unix::EventedFd;
use std::io::{ErrorKind, Read, Result, Write};
use std::os::unix::io::AsRawFd;
use tokio_core::reactor::{Handle, PollEvented};
#[derive(Debug)]
pub enum MaybeEventedFd {
RegularFile(FileDesc),
Registered(PollEvented<EventedFileDesc>),
}
pub trait FileDescExt {
#[deprecated(note = "does not handle regular files, use `into_evented2` instead")]
fn into_evented(self, handle: &Handle) -> Result<PollEvented<EventedFileDesc>>;
fn into_evented2(self, handle: &Handle) -> Result<MaybeEventedFd> where Self: Sized {
self.into_evented(handle).map(MaybeEventedFd::Registered)
}
fn set_nonblock(&self, set: bool) -> Result<()>;
}
impl FileDescExt for FileDesc {
fn into_evented(self, handle: &Handle) -> Result<PollEvented<EventedFileDesc>> {
try!(self.set_nonblock(true));
PollEvented::new(EventedFileDesc(self), handle)
}
fn into_evented2(self, handle: &Handle) -> Result<MaybeEventedFd> {
let ret = if is_regular_file(&self)? {
MaybeEventedFd::RegularFile(self)
} else {
self.set_nonblock(true)?;
let evented = PollEvented::new(EventedFileDesc(self), handle)?;
MaybeEventedFd::Registered(evented)
};
Ok(ret)
}
fn set_nonblock(&self, set: bool) -> Result<()> {
self.inner().set_nonblock(set)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct EventedFileDesc(FileDesc);
impl Evented for EventedFileDesc {
fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> Result<()> {
match EventedFd(&self.0.as_raw_fd()).register(poll, token, interest, opts) {
ret@Ok(_) => ret,
Err(e) => if e.kind() == ErrorKind::AlreadyExists {
self.reregister(poll, token, interest, opts)
} else {
Err(e)
},
}
}
fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> Result<()> {
EventedFd(&self.0.as_raw_fd()).reregister(poll, token, interest, opts)
}
fn deregister(&self, poll: &Poll) -> Result<()> {
EventedFd(&self.0.as_raw_fd()).deregister(poll)
}
}
impl Read for EventedFileDesc {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
self.0.read(buf)
}
}
impl Write for EventedFileDesc {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.0.write(buf)
}
fn flush(&mut self) -> Result<()> {
self.0.flush()
}
}
fn is_regular_file(fd: &FileDesc) -> Result<bool> {
use libc;
use std::mem;
use sys::cvt_r;
#[cfg(not(linux))]
fn get_mode(fd: &FileDesc) -> Result<libc::mode_t> {
unsafe {
let mut stat: libc::stat = mem::zeroed();
cvt_r(|| libc::fstat(fd.as_raw_fd(), &mut stat))
.map(|_| stat.st_mode)
}
}
#[cfg(linux)]
fn get_mode(fd: &FileDesc) -> Result<libc::mode_t> {
unsafe {
let mut stat: libc::stat64 = mem::zeroed();
cvt_r(|| libc::fstat64(fd.as_raw_fd(), &mut stat))
.map(|_| stat.st_mode)
}
}
get_mode(&fd).map(|mode| mode & libc::S_IFMT == libc::S_IFREG)
}