1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! This crate provides an abstraction over the [tokio] [CurrentThread] runtime
//! which allows for simulating applications.
//! 
//! The [Environment] trait provides an abstraction over [Delay] and [Timeout].
//! This allows for applications to be generic over [DeterministicRuntime] or 
//! [SingleThreadedRuntime].
//! 
//! [DeterministicRuntime] will automatically advance a mocked clock if there is
//! no more work to do, up until the next timeout. This results in applications which 
//! can be decoupled from time, facilitating fast integration/simulation tests.
//! 
//! ```rust
//! use std::time;
//! use simulation::{DeterministicRuntime, Environment};
//! 
//! async fn delayed<E>(handle: E) where E: Environment {
//!    let start_time = handle.now();
//!    handle.delay_from(time::Duration::from_secs(30)).await;
//!    println!("that was fast!");
//!    assert_eq!(handle.now(), start_time + time::Duration::from_secs(30));
//! }
//! 
//! #[test]
//! fn time() {
//!     let mut runtime = DeterministicRuntime::new();
//!     let handle = runtime.handle();
//!     runtime.block_on(async move {
//!         delayed(handle).await;
//!     });
//! }
//! ```
//! 
//! [tokio]: https://github.com/tokio-rs
//! [CurrentThread]:[tokio_executor::current_thread::CurrentThread]
//! [Delay]:[tokio_timer::Delay]
//! [Timeout]:[tokio_timer::Timeout]

use futures::{Future, FutureExt, channel::oneshot};
use std::time;
mod runtime;
pub use runtime::{DeterministicRuntime, SingleThreadedRuntime, DeterministicRuntimeHandle, SingleThreadedRuntimeHandle};

pub trait Environment: Unpin + Sized + Clone + Send {
    fn spawn<F>(&self, future: F)
    where
        F: Future<Output = ()> + Send + 'static;
    /// Return the time now according to the executor.
    fn now(&self) -> time::Instant;
    /// Returns a delay future which completes after the provided instant.
    fn delay(&self, deadline: time::Instant) -> tokio_timer::Delay;
    /// Returns a delay future which completes at some time from now.
    fn delay_from(&self, from_now: time::Duration) -> tokio_timer::Delay {
        let now = self.now();
        self.delay(now + from_now)
    }
    /// Creates a timeout future which will execute blah blah
    fn timeout<T>(&self, value: T, timeout: time::Duration) -> tokio_timer::Timeout<T>;
}

pub fn spawn_with_result<F, E, U>(env: &E, future: F) -> impl Future<Output = Option<U>>
where
    F: Future<Output = U> + Send + 'static,
    U: Send + 'static,
    E: Environment,
{
    let (tx, rx) = oneshot::channel();
    env.spawn(async {
        tx.send(future.await).unwrap_or(());
    });
    Box::new(rx).map(|v| v.ok())    
}