runtime_raw/
lib.rs

1//! Types for defining custom [Runtime](https://github.com/rustasync/runtime)s. See the
2//! [Runtime](https://docs.rs/runtime) documentation for more details.
3//!
4//! These types are only necessary when implementing custom runtimes. If you're only trying to
5//! perform IO, then there's no need to bother with any of these types as they will have been
6//! implemented for you already.
7
8#![deny(unsafe_code)]
9#![warn(
10    missing_debug_implementations,
11    missing_docs,
12    nonstandard_style,
13    rust_2018_idioms
14)]
15
16use futures::executor;
17use futures::future::BoxFuture;
18use futures::prelude::*;
19use futures::task::SpawnError;
20
21use std::cell::Cell;
22use std::io;
23use std::net::SocketAddr;
24use std::pin::Pin;
25use std::time::{Duration, Instant};
26
27mod tcp;
28mod time;
29mod udp;
30
31pub use tcp::*;
32pub use time::*;
33pub use udp::*;
34
35thread_local! {
36    static RUNTIME: Cell<Option<&'static dyn Runtime>> = Cell::new(None);
37}
38
39/// Get the current runtime.
40#[inline]
41pub fn current_runtime() -> &'static dyn Runtime {
42    RUNTIME.with(|r| r.get().expect("the runtime has not been set"))
43}
44
45/// Set the current runtime.
46///
47/// This function must be called at the beginning of runtime's threads before they start polling
48/// any futures.
49pub fn set_runtime(runtime: &'static dyn Runtime) {
50    RUNTIME.with(|r| {
51        assert!(r.get().is_none(), "the runtime has already been set");
52        r.set(Some(runtime))
53    });
54}
55
56/// Runs a future inside a runtime and blocks on the result.
57pub fn enter<R, F, T>(rt: R, fut: F) -> T
58where
59    R: Runtime,
60    F: Future<Output = T> + Send + 'static,
61    T: Send + 'static,
62{
63    let (tx, rx) = futures::channel::oneshot::channel();
64
65    let fut = async move {
66        let t = fut.await;
67        let _ = tx.send(t);
68    };
69
70    rt.spawn_boxed(fut.boxed()).expect("cannot spawn a future");
71
72    executor::block_on(rx).expect("the main future has panicked")
73}
74
75/// The runtime trait.
76pub trait Runtime: Send + Sync + 'static {
77    /// Spawn a new future.
78    fn spawn_boxed(&self, fut: BoxFuture<'static, ()>) -> Result<(), SpawnError>;
79
80    /// Create a new `TcpStream`.
81    ///
82    /// This method is defined on the `Runtime` trait because defining it on
83    /// `TcpStream` would prevent it from being a trait object.
84    fn connect_tcp_stream(
85        &self,
86        addr: &SocketAddr,
87    ) -> BoxFuture<'static, io::Result<Pin<Box<dyn TcpStream>>>>;
88
89    /// Create a new `TcpListener`.
90    ///
91    /// This method is defined on the `Runtime` trait because defining it on
92    /// `TcpListener` would prevent it from being a trait object.
93    fn bind_tcp_listener(&self, addr: &SocketAddr) -> io::Result<Pin<Box<dyn TcpListener>>>;
94
95    /// Create a new `UdpSocket`.
96    ///
97    /// This method is defined on the `Runtime` trait because defining it on
98    /// `UdpSocket` would prevent it from being a trait object.
99    fn bind_udp_socket(&self, addr: &SocketAddr) -> io::Result<Pin<Box<dyn UdpSocket>>>;
100
101    /// Create a new Future that wakes up after the given duration
102    ///
103    /// This method is defined on the `Runtime` trait because defining it on
104    /// `Delay` would prevent it from being a trait object.
105    fn new_delay(&self, dur: Duration) -> Pin<Box<dyn Delay>>;
106
107    /// Create a new Future that wakes up at the given time.
108    ///
109    /// This method is defined on the `Runtime` trait because defining it on
110    /// `Delay` would prevent it from being a trait object.
111    fn new_delay_at(&self, at: Instant) -> Pin<Box<dyn Delay>>;
112
113    /// A stream representing notifications at a fixed interval.
114    ///
115    /// This method is defined on the `Runtime` trait because defining it on
116    /// `Interval` would prevent it from being a trait object.
117    fn new_interval(&self, dur: Duration) -> Pin<Box<dyn Interval>>;
118}