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}