round_based/mpc/party/
runtime.rs

1//! Async runtime abstraction
2//!
3//! Runtime abstraction allows the MPC protocol to stay runtime-agnostic while being
4//! able to use features that are common to any runtime
5
6/// Async runtime abstraction
7///
8/// Abstracts async runtime like [tokio]. Currently only exposes a [yield_now](Self::yield_now)
9/// function.
10pub trait AsyncRuntime {
11    /// Yields the execution back to the runtime
12    ///
13    /// If the protocol performs a long computation, it might be better for performance
14    /// to split it with yield points, so the single computation does not starve other
15    /// tasks.
16    async fn yield_now(&self);
17}
18
19/// [Tokio](tokio)-specific async runtime
20#[cfg(feature = "runtime-tokio")]
21#[derive(Debug, Default)]
22pub struct TokioRuntime;
23
24#[cfg(feature = "runtime-tokio")]
25impl AsyncRuntime for TokioRuntime {
26    async fn yield_now(&self) {
27        tokio::task::yield_now().await
28    }
29}
30
31#[doc(inline)]
32pub use unknown_runtime::UnknownRuntime;
33
34/// Default runtime
35#[cfg(feature = "runtime-tokio")]
36#[cfg_attr(docsrs, doc(cfg(all())))]
37pub type DefaultRuntime = TokioRuntime;
38/// Default runtime
39#[cfg(not(feature = "runtime-tokio"))]
40#[cfg_attr(docsrs, doc(cfg(all())))]
41pub type DefaultRuntime = UnknownRuntime;
42
43/// Unknown async runtime
44mod unknown_runtime {
45    /// Unknown async runtime
46    ///
47    /// Tries to implement runtime features using generic futures code. It's better to use
48    /// runtime-specific implementation.
49    #[derive(Debug, Default)]
50    pub struct UnknownRuntime;
51
52    impl super::AsyncRuntime for UnknownRuntime {
53        async fn yield_now(&self) {
54            YieldNow(false).await
55        }
56    }
57
58    /// Future for the `yield_now` function.
59    struct YieldNow(bool);
60
61    impl core::future::Future for YieldNow {
62        type Output = ();
63
64        fn poll(
65            mut self: core::pin::Pin<&mut Self>,
66            cx: &mut core::task::Context<'_>,
67        ) -> core::task::Poll<Self::Output> {
68            if !self.0 {
69                self.0 = true;
70                cx.waker().wake_by_ref();
71                core::task::Poll::Pending
72            } else {
73                core::task::Poll::Ready(())
74            }
75        }
76    }
77}