Files
tokio/src/readiness_stream.rs
T

111 lines
3.5 KiB
Rust
Raw Normal View History

2016-07-30 17:53:12 -07:00
use std::io;
2016-08-17 09:29:05 -07:00
use std::sync::atomic::{AtomicUsize, Ordering};
2016-07-30 17:53:12 -07:00
2016-08-17 09:29:05 -07:00
use futures::{Future, Poll};
2016-07-30 17:53:12 -07:00
use event_loop::{IoSource, LoopHandle, AddSource};
2016-07-30 17:53:12 -07:00
2016-08-01 17:41:58 -07:00
/// A concrete implementation of a stream of readiness notifications for I/O
/// objects that originates from an event loop.
///
/// Created by the `ReadinessStream::new` method, each `ReadinessStream` is
/// associated with a specific event loop and source of events that will be
/// registered with an event loop.
///
/// Currently readiness streams have "edge" semantics. That is, if a stream
/// receives a readable notification it will not receive another readable
/// notification until all bytes have been read from the stream.
///
/// Note that the precise semantics of when notifications are received will
/// likely be configurable in the future.
2016-07-30 17:53:12 -07:00
pub struct ReadinessStream {
io_token: usize,
loop_handle: LoopHandle,
source: IoSource,
2016-08-17 09:29:05 -07:00
readiness: AtomicUsize,
2016-07-30 17:53:12 -07:00
}
pub struct ReadinessStreamNew {
inner: AddSource,
handle: Option<LoopHandle>,
source: Option<IoSource>,
}
2016-07-30 17:53:12 -07:00
impl ReadinessStream {
2016-08-01 17:41:58 -07:00
/// Creates a new readiness stream associated with the provided
/// `loop_handle` and for the given `source`.
///
/// This method returns a future which will resolve to the readiness stream
/// when it's ready.
2016-07-30 17:53:12 -07:00
pub fn new(loop_handle: LoopHandle, source: IoSource)
-> ReadinessStreamNew {
ReadinessStreamNew {
inner: loop_handle.add_source(source.clone()),
source: Some(source),
handle: Some(loop_handle),
}
}
2016-08-17 09:29:05 -07:00
/// Tests to see if this source is ready to be read from or not.
pub fn poll_read(&self) -> Poll<(), io::Error> {
if self.readiness.load(Ordering::SeqCst) & 1 != 0 {
return Poll::Ok(())
}
self.readiness.fetch_or(self.source.take_readiness(), Ordering::SeqCst);
if self.readiness.load(Ordering::SeqCst) & 1 != 0 {
Poll::Ok(())
} else {
self.loop_handle.schedule_read(self.io_token);
Poll::NotReady
}
}
/// Tests to see if this source is ready to be written to or not.
pub fn poll_write(&self) -> Poll<(), io::Error> {
if self.readiness.load(Ordering::SeqCst) & 2 != 0 {
return Poll::Ok(())
}
self.readiness.fetch_or(self.source.take_readiness(), Ordering::SeqCst);
if self.readiness.load(Ordering::SeqCst) & 2 != 0 {
Poll::Ok(())
} else {
self.loop_handle.schedule_write(self.io_token);
Poll::NotReady
}
}
/// Tests to see if this source is ready to be read from or not.
pub fn need_read(&self) {
self.readiness.fetch_and(!1, Ordering::SeqCst);
self.loop_handle.schedule_read(self.io_token);
}
/// Tests to see if this source is ready to be written to or not.
pub fn need_write(&self) {
self.readiness.fetch_and(!2, Ordering::SeqCst);
self.loop_handle.schedule_write(self.io_token);
}
}
impl Future for ReadinessStreamNew {
type Item = ReadinessStream;
type Error = io::Error;
2016-08-17 09:29:05 -07:00
fn poll(&mut self) -> Poll<ReadinessStream, io::Error> {
self.inner.poll().map(|token| {
2016-07-30 17:53:12 -07:00
ReadinessStream {
io_token: token,
source: self.source.take().unwrap(),
loop_handle: self.handle.take().unwrap(),
2016-08-17 09:29:05 -07:00
readiness: AtomicUsize::new(0),
2016-07-30 17:53:12 -07:00
}
})
}
2016-07-30 17:53:12 -07:00
}
impl Drop for ReadinessStream {
fn drop(&mut self) {
2016-08-02 10:37:32 -07:00
self.loop_handle.drop_source(self.io_token)
2016-07-30 17:53:12 -07:00
}
}