Skip to main content

compio_compat/
lib.rs

1//! Runtime-compatibility layers for compio.
2//!
3//! This crate provides a compatibility layer for compio's runtime, allowing it
4//! to be used with different underlying event loop implementations, e.g.,
5//! `tokio` or `smol`.
6
7#![cfg_attr(docsrs, feature(doc_cfg))]
8#![warn(missing_docs)]
9#![deny(rustdoc::broken_intra_doc_links)]
10#![doc(
11    html_logo_url = "https://github.com/compio-rs/compio-logo/raw/refs/heads/master/generated/colored-bold.svg"
12)]
13#![doc(
14    html_favicon_url = "https://github.com/compio-rs/compio-logo/raw/refs/heads/master/generated/colored-bold.svg"
15)]
16
17use std::{
18    io,
19    ops::Deref,
20    task::{Context, Poll},
21    time::Duration,
22};
23
24use compio_log::error;
25use compio_runtime::Runtime;
26use mod_use::mod_use;
27
28mod_use![sys];
29
30/// A compatibility layer for [`Runtime`]. It is driven by the underlying
31/// [`Adapter`].
32pub struct RuntimeCompat<A> {
33    runtime: A,
34}
35
36impl<A: Adapter> RuntimeCompat<A> {
37    /// Creates a new [`RuntimeCompat`] with the given runtime.
38    pub fn new(runtime: Runtime) -> io::Result<Self> {
39        let runtime = A::new(runtime)?;
40        Ok(Self { runtime })
41    }
42
43    /// Executes the given future on the runtime, driving it to completion.
44    pub async fn execute<F: Future>(&self, f: F) -> F::Output {
45        let waker = self.runtime.waker();
46        let mut context = Context::from_waker(&waker);
47        let mut future = std::pin::pin!(f);
48        loop {
49            if let Poll::Ready(result) = self.runtime.enter(|| future.as_mut().poll(&mut context)) {
50                self.runtime.enter(|| self.runtime.run());
51                return result;
52            }
53
54            let mut remaining_tasks = self.runtime.enter(|| self.runtime.run());
55
56            remaining_tasks |= self.runtime.flush();
57
58            let timeout = if remaining_tasks {
59                Some(Duration::ZERO)
60            } else {
61                self.runtime.current_timeout()
62            };
63
64            match self.runtime.wait(timeout).await {
65                Ok(_) => {}
66                Err(e)
67                    if matches!(
68                        e.kind(),
69                        io::ErrorKind::TimedOut | io::ErrorKind::Interrupted
70                    ) => {}
71                Err(e) => panic!("failed to wait for driver: {e:?}"),
72            }
73
74            if let Err(e) = self.runtime.clear() {
75                error!("failed to clear notifier: {e:?}");
76            }
77
78            self.runtime.poll_with(Some(Duration::ZERO));
79        }
80    }
81}
82
83impl<A: Adapter> Deref for RuntimeCompat<A> {
84    type Target = Runtime;
85
86    fn deref(&self) -> &Self::Target {
87        &self.runtime
88    }
89}