Skip to main content

vibeio_hyper/
lib.rs

1//! A compatibility layer for using [`hyper`] with the `vibeio` async runtime.
2//!
3//! This crate provides the necessary adapters to run `hyper`-based HTTP servers
4//! and clients on top of `vibeio` instead of `tokio`. It implements the traits
5//! required by `hyper`'s runtime abstraction:
6//!
7//! - [`VibeioExecutor`]: An executor that spawns tasks on the `vibeio` runtime
8//!   using `vibeio::spawn`.
9//! - [`VibeioTimer`]: A timer that uses `vibeio::time::sleep` for delay operations.
10//! - [`VibeioIo`]: A wrapper type that adapts `vibeio`'s I/O types to implement
11//!   `hyper`'s `Read` and `Write` traits, and also implements `tokio`'s
12//!   `AsyncRead` and `AsyncWrite` traits for compatibility.
13//!
14//! # Overview
15//!
16//! This crate enables `hyper` to work with `vibeio` by implementing `hyper`'s
17//! runtime traits (`Executor`, `Timer`, `Read`, `Write`, `Sleep`) in terms of
18//! `vibeio` primitives.
19//!
20//! ## Executor
21//!
22//! The [`VibeioExecutor`] type implements `hyper::rt::Executor` by spawning
23//! futures onto the `vibeio` runtime via `vibeio::spawn`.
24//!
25//! ## Timer
26//!
27//! The [`VibeioTimer`] type implements `hyper::rt::Timer` by converting sleep
28//! requests into `vibeio::time::sleep` futures wrapped in a compatible type.
29//!
30//! ## I/O Adapters
31//!
32//! The [`VibeioIo<T>`] wrapper adapts any type that implements `tokio::io::AsyncRead`
33//! and `tokio::io::AsyncWrite` to work with `hyper`'s I/O traits. It also
34//! implements the reverse conversion, allowing `hyper`'s I/O types to be used
35//! with `tokio`-style async functions.
36//!
37//! # Implementation notes
38//!
39//! - The `VibeioIo` wrapper uses `Pin<Box<T>>` internally to support the
40//!   trait implementations required by `hyper` and `tokio`.
41//! - The `VibeioSleep` type (internal) implements both `hyper::rt::Sleep`
42//!   and `std::future::Future` to bridge the two runtimes' sleep abstractions.
43//! - Timer handles are properly cancelled when `VibeioSleep` is dropped to
44//!   avoid resource leaks.
45
46use std::{
47    ops::{Deref, DerefMut},
48    pin::Pin,
49    task::{Context, Poll},
50};
51
52use hyper::rt::Executor;
53#[cfg(feature = "time")]
54use hyper::rt::{Sleep, Timer};
55use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
56
57/// An executor that spawns tasks onto the `vibeio` runtime.
58///
59/// This type implements `hyper::rt::Executor` and uses `vibeio::spawn` to
60/// execute futures on the `vibeio` runtime.
61#[derive(Debug, Default, Clone, Copy)]
62pub struct VibeioExecutor;
63
64impl<Fut> Executor<Fut> for VibeioExecutor
65where
66    Fut: std::future::Future + 'static,
67    Fut::Output: 'static,
68{
69    #[inline]
70    fn execute(&self, fut: Fut) {
71        vibeio::spawn(fut);
72    }
73}
74
75/// A timer that uses `vibeio`'s time utilities for sleep operations.
76///
77/// This type implements `hyper::rt::Timer` and uses `vibeio::time::sleep`
78/// to implement delay operations.
79#[cfg(feature = "time")]
80#[derive(Debug, Default, Clone, Copy)]
81pub struct VibeioTimer;
82
83#[cfg(feature = "time")]
84impl Timer for VibeioTimer {
85    #[inline]
86    fn sleep(&self, duration: std::time::Duration) -> Pin<Box<dyn Sleep>> {
87        Box::pin(VibeioSleep {
88            inner: Box::pin(vibeio::time::sleep(duration)),
89        })
90    }
91
92    #[inline]
93    fn sleep_until(&self, deadline: std::time::Instant) -> Pin<Box<dyn Sleep>> {
94        Box::pin(VibeioSleep {
95            inner: Box::pin(vibeio::time::sleep_until(deadline)),
96        })
97    }
98
99    #[inline]
100    fn reset(&self, sleep: &mut Pin<Box<dyn Sleep>>, new_deadline: std::time::Instant) {
101        if let Some(mut sleep) = sleep.as_mut().downcast_mut_pin::<VibeioSleep>() {
102            sleep.reset(new_deadline);
103        }
104    }
105}
106
107/// A sleep future that wraps `vibeio::time::Sleep` and implements `hyper::rt::Sleep`.
108#[cfg(feature = "time")]
109struct VibeioSleep {
110    inner: Pin<Box<vibeio::time::Sleep>>,
111}
112
113#[cfg(feature = "time")]
114impl std::future::Future for VibeioSleep {
115    type Output = ();
116
117    #[inline]
118    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
119        self.inner.as_mut().poll(cx)
120    }
121}
122
123#[cfg(feature = "time")]
124impl Sleep for VibeioSleep {}
125
126#[cfg(feature = "time")]
127unsafe impl Send for VibeioSleep {}
128#[cfg(feature = "time")]
129unsafe impl Sync for VibeioSleep {}
130
131#[cfg(feature = "time")]
132impl VibeioSleep {
133    #[inline]
134    fn reset(&mut self, new_deadline: std::time::Instant) {
135        self.inner.reset(new_deadline);
136    }
137}
138
139/// A wrapper type that adapts I/O types for use with `hyper` and `tokio`.
140///
141/// `VibeioIo<T>` wraps any type `T` that implements `tokio::io::AsyncRead`
142/// and `tokio::io::AsyncWrite` and provides implementations for:
143///
144/// - `hyper::rt::Read` and `hyper::rt::Write`
145/// - `tokio::io::AsyncRead` and `tokio::io::AsyncWrite`
146///
147/// This allows seamless interoperability between `hyper`'s I/O traits and
148/// `tokio`'s async I/O traits when using the `vibeio` runtime.
149#[derive(Debug)]
150pub struct VibeioIo<T> {
151    inner: Pin<Box<T>>,
152}
153
154impl<T> VibeioIo<T> {
155    /// Creates a new `VibeioIo` wrapper around the given I/O type.
156    #[inline]
157    pub fn new(inner: T) -> Self {
158        Self {
159            inner: Box::pin(inner),
160        }
161    }
162}
163
164impl<T> Deref for VibeioIo<T> {
165    type Target = Pin<Box<T>>;
166
167    #[inline]
168    fn deref(&self) -> &Self::Target {
169        &self.inner
170    }
171}
172
173impl<T> DerefMut for VibeioIo<T> {
174    #[inline]
175    fn deref_mut(&mut self) -> &mut Self::Target {
176        &mut self.inner
177    }
178}
179
180// Implement hyper::rt::Read for types that implement tokio::io::AsyncRead
181impl<T> hyper::rt::Read for VibeioIo<T>
182where
183    T: AsyncRead,
184{
185    #[inline]
186    fn poll_read(
187        mut self: Pin<&mut Self>,
188        cx: &mut Context<'_>,
189        mut buf: hyper::rt::ReadBufCursor<'_>,
190    ) -> Poll<Result<(), std::io::Error>> {
191        let n = {
192            let mut tbuf = unsafe { ReadBuf::uninit(buf.as_mut()) };
193            match self.inner.as_mut().poll_read(cx, &mut tbuf) {
194                Poll::Ready(Ok(_)) => tbuf.filled().len(),
195                Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
196                Poll::Pending => return Poll::Pending,
197            }
198        };
199
200        unsafe { buf.advance(n) };
201        Poll::Ready(Ok(()))
202    }
203}
204
205// Implement hyper::rt::Write for types that implement tokio::io::AsyncWrite
206impl<T> hyper::rt::Write for VibeioIo<T>
207where
208    T: AsyncWrite,
209{
210    #[inline]
211    fn poll_write(
212        mut self: Pin<&mut Self>,
213        cx: &mut Context<'_>,
214        buf: &[u8],
215    ) -> Poll<Result<usize, std::io::Error>> {
216        self.inner.as_mut().poll_write(cx, buf)
217    }
218
219    #[inline]
220    fn poll_flush(
221        mut self: Pin<&mut Self>,
222        cx: &mut Context<'_>,
223    ) -> Poll<Result<(), std::io::Error>> {
224        self.inner.as_mut().poll_flush(cx)
225    }
226
227    #[inline]
228    fn poll_shutdown(
229        mut self: Pin<&mut Self>,
230        cx: &mut Context<'_>,
231    ) -> Poll<Result<(), std::io::Error>> {
232        self.inner.as_mut().poll_shutdown(cx)
233    }
234
235    #[inline]
236    fn is_write_vectored(&self) -> bool {
237        self.inner.is_write_vectored()
238    }
239
240    #[inline]
241    fn poll_write_vectored(
242        mut self: Pin<&mut Self>,
243        cx: &mut Context<'_>,
244        bufs: &[std::io::IoSlice<'_>],
245    ) -> Poll<Result<usize, std::io::Error>> {
246        self.inner.as_mut().poll_write_vectored(cx, bufs)
247    }
248}
249
250// Implement tokio::io::AsyncRead for types that implement hyper::rt::Read
251impl<T> AsyncRead for VibeioIo<T>
252where
253    T: hyper::rt::Read,
254{
255    #[inline]
256    fn poll_read(
257        mut self: Pin<&mut Self>,
258        cx: &mut Context<'_>,
259        tbuf: &mut ReadBuf<'_>,
260    ) -> Poll<std::io::Result<()>> {
261        let filled = tbuf.filled().len();
262        let sub_filled = {
263            let mut buf = unsafe { hyper::rt::ReadBuf::uninit(tbuf.unfilled_mut()) };
264            match self.inner.as_mut().poll_read(cx, buf.unfilled()) {
265                Poll::Ready(Ok(_)) => buf.filled().len(),
266                Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
267                Poll::Pending => return Poll::Pending,
268            }
269        };
270
271        unsafe {
272            tbuf.assume_init(sub_filled);
273            tbuf.set_filled(filled + sub_filled);
274        };
275        Poll::Ready(Ok(()))
276    }
277}
278
279// Implement tokio::io::AsyncWrite for types that implement hyper::rt::Write
280impl<T> AsyncWrite for VibeioIo<T>
281where
282    T: hyper::rt::Write,
283{
284    #[inline]
285    fn poll_write(
286        mut self: Pin<&mut Self>,
287        cx: &mut Context<'_>,
288        buf: &[u8],
289    ) -> Poll<Result<usize, std::io::Error>> {
290        self.inner.as_mut().poll_write(cx, buf)
291    }
292
293    #[inline]
294    fn poll_flush(
295        mut self: Pin<&mut Self>,
296        cx: &mut Context<'_>,
297    ) -> Poll<Result<(), std::io::Error>> {
298        self.inner.as_mut().poll_flush(cx)
299    }
300
301    #[inline]
302    fn poll_shutdown(
303        mut self: Pin<&mut Self>,
304        cx: &mut Context<'_>,
305    ) -> Poll<Result<(), std::io::Error>> {
306        self.inner.as_mut().poll_shutdown(cx)
307    }
308
309    #[inline]
310    fn is_write_vectored(&self) -> bool {
311        self.inner.is_write_vectored()
312    }
313
314    #[inline]
315    fn poll_write_vectored(
316        mut self: Pin<&mut Self>,
317        cx: &mut Context<'_>,
318        bufs: &[std::io::IoSlice<'_>],
319    ) -> Poll<Result<usize, std::io::Error>> {
320        self.inner.as_mut().poll_write_vectored(cx, bufs)
321    }
322}