use tokio::reactor::{Handle, Registration};
use futures::{task, Async, Poll};
use mio;
use mio::event::Evented;
use tokio_io::{AsyncRead, AsyncWrite};
use std::fmt;
use std::io::{self, Read, Write};
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::Relaxed;
pub struct PollEvented<E: Evented> {
io: Option<E>,
inner: Inner,
}
struct Inner {
registration: Registration,
read_readiness: AtomicUsize,
write_readiness: AtomicUsize,
}
macro_rules! poll_ready {
($me:expr, $mask:expr, $cache:ident, $poll:ident, $take:ident) => {{
$me.register()?;
let mut cached = $me.inner.$cache.load(Relaxed);
let mask = $mask | platform::hup();
let mut ret = mio::Ready::from_usize(cached) & $mask;
if ret.is_empty() {
loop {
let ready = try_ready!($me.inner.registration.$poll());
cached |= ready.as_usize();
$me.inner.$cache.store(cached, Relaxed);
ret |= ready & mask;
if !ret.is_empty() {
return Ok(ret.into());
}
}
} else {
if let Some(ready) = $me.inner.registration.$take()? {
cached |= ready.as_usize();
$me.inner.$cache.store(cached, Relaxed);
}
Ok(mio::Ready::from_usize(cached).into())
}
}}
}
impl<E> PollEvented<E>
where E: Evented
{
pub fn new(io: E) -> PollEvented<E> {
PollEvented {
io: Some(io),
inner: Inner {
registration: Registration::new(),
read_readiness: AtomicUsize::new(0),
write_readiness: AtomicUsize::new(0),
}
}
}
pub fn new_with_handle(io: E, handle: &Handle) -> io::Result<Self> {
let ret = PollEvented::new(io);
ret.inner.registration.register_with(ret.io.as_ref().unwrap(), handle)?;
Ok(ret)
}
pub fn get_ref(&self) -> &E {
self.io.as_ref().unwrap()
}
pub fn get_mut(&mut self) -> &mut E {
self.io.as_mut().unwrap()
}
pub fn into_inner(mut self) -> io::Result<E> {
let io = self.io.take().unwrap();
self.inner.registration.deregister(&io)?;
Ok(io)
}
pub fn poll_read_ready(&self, mask: mio::Ready) -> Poll<mio::Ready, io::Error> {
assert!(!mask.is_writable(), "cannot poll for write readiness");
poll_ready!(self, mask, read_readiness, poll_read_ready, take_read_ready)
}
pub fn clear_read_ready(&self, ready: mio::Ready) -> io::Result<()> {
assert!(!ready.is_writable(), "cannot clear write readiness");
assert!(!platform::is_hup(&ready), "cannot clear HUP readiness");
self.inner.read_readiness.fetch_and(!ready.as_usize(), Relaxed);
if self.poll_read_ready(ready)?.is_ready() {
task::current().notify();
}
Ok(())
}
pub fn poll_write_ready(&self) -> Poll<mio::Ready, io::Error> {
poll_ready!(self,
mio::Ready::writable(),
write_readiness,
poll_write_ready,
take_write_ready)
}
pub fn clear_write_ready(&self) -> io::Result<()> {
let ready = mio::Ready::writable();
self.inner.write_readiness.fetch_and(!ready.as_usize(), Relaxed);
if self.poll_write_ready()?.is_ready() {
task::current().notify();
}
Ok(())
}
fn register(&self) -> io::Result<()> {
self.inner.registration.register(self.io.as_ref().unwrap())?;
Ok(())
}
}
impl<E> Read for PollEvented<E>
where E: Evented + Read,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if let Async::NotReady = self.poll_read_ready(mio::Ready::readable())? {
return Err(io::ErrorKind::WouldBlock.into())
}
let r = self.get_mut().read(buf);
if is_wouldblock(&r) {
self.clear_read_ready(mio::Ready::readable())?;
}
return r
}
}
impl<E> Write for PollEvented<E>
where E: Evented + Write,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if let Async::NotReady = self.poll_write_ready()? {
return Err(io::ErrorKind::WouldBlock.into())
}
let r = self.get_mut().write(buf);
if is_wouldblock(&r) {
self.clear_write_ready()?;
}
return r
}
fn flush(&mut self) -> io::Result<()> {
if let Async::NotReady = self.poll_write_ready()? {
return Err(io::ErrorKind::WouldBlock.into())
}
let r = self.get_mut().flush();
if is_wouldblock(&r) {
self.clear_write_ready()?;
}
return r
}
}
impl<E> AsyncRead for PollEvented<E>
where E: Evented + Read,
{
}
impl<E> AsyncWrite for PollEvented<E>
where E: Evented + Write,
{
fn shutdown(&mut self) -> Poll<(), io::Error> {
Ok(().into())
}
}
impl<'a, E> Read for &'a PollEvented<E>
where E: Evented, &'a E: Read,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if let Async::NotReady = self.poll_read_ready(mio::Ready::readable())? {
return Err(io::ErrorKind::WouldBlock.into())
}
let r = self.get_ref().read(buf);
if is_wouldblock(&r) {
self.clear_read_ready(mio::Ready::readable())?;
}
return r
}
}
impl<'a, E> Write for &'a PollEvented<E>
where E: Evented, &'a E: Write,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if let Async::NotReady = self.poll_write_ready()? {
return Err(io::ErrorKind::WouldBlock.into())
}
let r = self.get_ref().write(buf);
if is_wouldblock(&r) {
self.clear_write_ready()?;
}
return r
}
fn flush(&mut self) -> io::Result<()> {
if let Async::NotReady = self.poll_write_ready()? {
return Err(io::ErrorKind::WouldBlock.into())
}
let r = self.get_ref().flush();
if is_wouldblock(&r) {
self.clear_write_ready()?;
}
return r
}
}
impl<'a, E> AsyncRead for &'a PollEvented<E>
where E: Evented, &'a E: Read,
{
}
impl<'a, E> AsyncWrite for &'a PollEvented<E>
where E: Evented, &'a E: Write,
{
fn shutdown(&mut self) -> Poll<(), io::Error> {
Ok(().into())
}
}
fn is_wouldblock<T>(r: &io::Result<T>) -> bool {
match *r {
Ok(_) => false,
Err(ref e) => e.kind() == io::ErrorKind::WouldBlock,
}
}
impl<E: Evented + fmt::Debug> fmt::Debug for PollEvented<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("PollEvented")
.field("io", &self.io)
.finish()
}
}
impl<E: Evented> Drop for PollEvented<E> {
fn drop(&mut self) {
if let Some(io) = self.io.as_ref() {
let _ = self.inner.registration.deregister(io);
}
}
}
#[cfg(all(unix, not(target_os = "fuchsia")))]
mod platform {
use mio::Ready;
use mio::unix::UnixReady;
pub fn hup() -> Ready {
UnixReady::hup().into()
}
pub fn is_hup(ready: &Ready) -> bool {
UnixReady::from(*ready).is_hup()
}
}
#[cfg(any(windows, target_os = "fuchsia"))]
mod platform {
use mio::Ready;
pub fn hup() -> Ready {
Ready::empty()
}
pub fn is_hup(_: &Ready) -> bool {
false
}
}