async_core/
lib.rs

1//! This crate provides wrappers for async operations in order to help standardize rust async
2//! runtimes.
3//!
4//! SAFETY: The current runtime *must* be cleaned up after each tick of a runtime, and must
5//! therefore live shorter than the runtime itself as the runtime can not be dropped while it
6//! is running. Without this, async-core causes undefined behavior.
7//!
8//! SAFETY: In a no_std environment, creating multiple threads is inherently unsafe as there is no
9//! safe API wrapping threads. I assume you know what you are doing if you are using this with
10//! multiple threads in a no_std environment. Please do not share runtimes between threads this way.
11//!
12//! ## How to use a runtime:
13//!
14//! - Import the re-exported Runtime and get_current_runtime.
15//! - (Skip this if you are a library developer and want your users to control the runtime) Create
16//!   a runtime like you normally would
17//! - Don't use that runtime's specifics if you can somehow avoid it. Use get_current_runtime and
18//!   the functions provided in the returned RuntimeWrapper
19//!
20//! ## How to implement a runtime:
21//!
22//! - Re-export everything so your users can use async_core without needing to add it as a
23//!   dependency.
24//! - In the runtime, call set_current_runtime and clear_current_runtime:
25//! ```
26//! set_current_runtime(self);
27//! let result = execute_futures(); // Do your cool runtime things here
28//! clear_current_runtime();
29//! result
30//! ```
31//! - If your crate has a no_std feature, link that with this crate's no_std feature.
32//! - Make absolutely sure you call set_current_runtime and clear_current_runtime.
33
34#![no_std]
35#[cfg(not(feature = "no_std"))]
36extern crate std;
37
38extern crate alloc;
39
40mod runtime;
41pub use runtime::*;
42
43mod defer;
44#[cfg(not(feature = "no_std"))]
45pub use defer::*;
46
47mod yielding;
48pub use yielding::*;
49
50mod joiner;
51pub use joiner::*;
52
53use alloc::boxed::Box;
54use core::pin::Pin;
55use core::{cell::RefCell, future::Future};
56use core::{mem, mem::ManuallyDrop, panic};
57
58pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
59#[inline]
60pub fn prep<'a, T>(future: impl Future<Output = T> + 'a + Send) -> BoxFuture<'a, T> {
61    Box::pin(future)
62}
63
64#[cfg(feature = "no_std")]
65mod no_std_util {
66    pub struct ForceShare<T>(pub T);
67    unsafe impl<T> Send for ForceShare<T> {}
68    unsafe impl<T> Sync for ForceShare<T> {}
69    impl<T> ForceShare<T> {
70        pub fn with<F, R>(&self, fun: F) -> R
71        where
72            F: FnOnce(&T) -> R,
73        {
74            fun(&self.0)
75        }
76    }
77}
78
79#[cfg(feature = "no_std")]
80static CURRENT_RUNTIME: no_std_util::ForceShare<
81    RefCell<Option<ManuallyDrop<Box<dyn InternalRuntime>>>>,
82> = no_std_util::ForceShare(RefCell::new(None));
83
84#[cfg(not(feature = "no_std"))]
85std::thread_local! {
86    static CURRENT_RUNTIME: RefCell<Option<ManuallyDrop<Box<dyn InternalRuntime>>>> = RefCell::new(None);
87}
88
89/// This gets the currently running runtime. PANICS IF IT IS CALLED FROM OUTSIDE THE RUNTIME.
90pub async fn get_current_runtime<'a>() -> RuntimeWrapper<'a> {
91    CURRENT_RUNTIME.with(|x| {
92        if let Some(x) = x.borrow_mut().as_mut() {
93            unsafe { RuntimeWrapper(&mut *(x.as_mut() as *mut _)) }
94        } else {
95            panic!(
96                "get_current_runtime MUST only be called from a future running within a Runtime!"
97            )
98        }
99    })
100}
101
102/// This sets the currently running runtime. MUST *ONLY* BE CALLED BY A RUNTIME WHEN IT IS ABOUT TO
103/// START EXECUTING, AND MUST BE CLEARED AFTERWARDS.
104pub fn set_current_runtime(runtime: &mut dyn InternalRuntime) {
105    CURRENT_RUNTIME.with(move |x| {
106        *x.borrow_mut() = Some(unsafe {
107            ManuallyDrop::new(Box::from_raw(
108                mem::transmute::<_, *mut dyn InternalRuntime>(runtime),
109            ))
110        })
111    })
112}
113
114/// This clears the currently running runtime. MUST *ONLY* BE CALLED BY A RUNTIME WHEN IT WILL
115/// (temporarily of permanently) STOP EXECUTING FUTURES. MUST FOLLOW A set_current_runtime CALL.
116/// IF THE RUNTIME STARTS TO BE USED AGAIN, set_current_runtime MUST BE CALLED AGAIN.
117pub fn clear_current_runtime() {
118    CURRENT_RUNTIME.with(|x| *x.borrow_mut() = None)
119}