maybe_fut/
rt.rs

1//! Sync contains the runtime to execute async code when working in sync context.
2
3use std::pin::Pin;
4use std::task::{Context, Poll, Waker};
5
6/// A runtime to execute sync code without async context.
7///
8/// This type should be used only when exporting the sync api of a library using
9/// maybe-fut to create an interoperable async/sync api.
10///
11/// Can also be run using [`block_on`] function.
12pub struct SyncRuntime;
13
14impl SyncRuntime {
15    pub fn block_on<F>(mut f: F) -> F::Output
16    where
17        F: Future,
18    {
19        let mut f = unsafe { Pin::new_unchecked(&mut f) };
20
21        let mut ctx = Context::from_waker(Waker::noop());
22
23        let Poll::Ready(val) = f.as_mut().poll(&mut ctx) else {
24            unreachable!("Future should not be pending in sync context");
25        };
26
27        val
28    }
29}
30
31/// Blocks on a future in a sync context.
32///
33/// It is equivalent to calling [`SyncRuntime::block_on`].
34pub fn block_on<F>(f: F) -> F::Output
35where
36    F: Future,
37{
38    SyncRuntime::block_on(f)
39}
40
41#[cfg(test)]
42mod test {
43
44    use pretty_assertions::assert_eq;
45
46    use super::*;
47
48    #[test]
49    fn test_should_execute_async_code_in_sync_context() {
50        let result = SyncRuntime::block_on(async_fn());
51        assert_eq!(result, 42);
52    }
53
54    #[test]
55    fn test_should_execute_async_code_in_sync_context_with_block_on() {
56        let result = block_on(async_fn());
57        assert_eq!(result, 42);
58    }
59
60    async fn async_fn() -> i32 {
61        42
62    }
63}