extern crate futures;
extern crate tokio_timer;
use std::any::Any;
use std::rc::Rc;
use std::cell::RefCell;
use std::error::Error;
use std::fmt;
use std::time::Instant;
use futures::{Future, Poll};
mod with_value;
mod with_cancel;
mod with_deadline;
pub use with_value::{WithValue, with_value};
pub use with_cancel::{WithCancel, with_cancel};
pub use with_deadline::{WithDeadline, with_deadline, with_timeout};
pub struct Context(pub Rc<RefCell<Box<InnerContext<Item = (), Error = ContextError>>>>);
impl Context {
pub fn new<C: 'static + InnerContext>(ctx: C) -> Self {
Context(Rc::new(RefCell::new(Box::new(ctx))))
}
pub fn deadline(&self) -> Option<Instant> {
self.0.borrow().deadline()
}
pub fn value<T>(&self) -> Option<T>
where T: Any + Clone
{
let ctx = self.0.borrow();
ctx.value()
.and_then(|val_any| val_any.downcast_ref::<T>())
.map(|v| (*v).clone())
.or_else(|| ctx.parent().and_then(|parent| parent.value()))
}
}
impl Future for Context {
type Item = ();
type Error = ContextError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let mut inner = self.0.borrow_mut();
inner.poll()
}
}
impl Clone for Context {
fn clone(&self) -> Self {
Context(self.0.clone())
}
}
pub trait InnerContext: Future<Item = (), Error = ContextError> {
fn deadline(&self) -> Option<Instant> {
None
}
fn value(&self) -> Option<&Any> {
None
}
fn parent(&self) -> Option<Context> {
None
}
}
#[derive(Debug, PartialEq)]
pub enum ContextError {
Canceled,
DeadlineExceeded,
DeadlineTooLong,
}
impl fmt::Display for ContextError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ContextError: {}", self.description())
}
}
impl Error for ContextError {
fn description(&self) -> &str {
match *self {
ContextError::Canceled => "context has been canceled",
ContextError::DeadlineExceeded => "deadline has been exceeded",
ContextError::DeadlineTooLong => "requested deadline too long",
}
}
}
mod background {
use {InnerContext, ContextError};
use futures::{Future, Poll, Async};
#[derive(Clone)]
pub struct Background {}
impl InnerContext for Background {}
impl Future for Background {
type Item = ();
type Error = ContextError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
Ok(Async::NotReady)
}
}
}
pub fn background() -> Context {
Context::new(background::Background {})
}