diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index 77da91df7..88fc2a439 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -25,6 +25,8 @@ tls-rustls = ["rustls", "proto/tls-rustls", "ring"] ring = ["proto/ring"] runtime-tokio = ["tokio/time", "tokio/rt", "tokio/net"] runtime-async-std = ["async-io", "async-std"] +runtime-smol = ["async-io", "smol"] + # Write logs via the `log` crate when no `tracing` subscriber exists log = ["tracing/log", "proto/log", "udp/log"] @@ -42,6 +44,7 @@ rustc-hash = "1.1" pin-project-lite = "0.2" proto = { package = "quinn-proto", path = "../quinn-proto", version = "0.11", default-features = false } rustls = { version = "0.21.0", default-features = false, features = ["quic"], optional = true } +smol = { version = "2", optional = true } thiserror = "1.0.21" tracing = "0.1.10" tokio = { version = "1.28.1", features = ["sync"] } diff --git a/quinn/src/lib.rs b/quinn/src/lib.rs index 05221548a..f1d8db5cb 100644 --- a/quinn/src/lib.rs +++ b/quinn/src/lib.rs @@ -78,6 +78,8 @@ pub use crate::endpoint::{Accept, Endpoint}; pub use crate::recv_stream::{ReadError, ReadExactError, ReadToEndError, RecvStream}; #[cfg(feature = "runtime-async-std")] pub use crate::runtime::AsyncStdRuntime; +#[cfg(feature = "runtime-smol")] +pub use crate::runtime::SmolRuntime; #[cfg(feature = "runtime-tokio")] pub use crate::runtime::TokioRuntime; pub use crate::runtime::{default_runtime, AsyncTimer, AsyncUdpSocket, Runtime}; diff --git a/quinn/src/runtime.rs b/quinn/src/runtime.rs index d4d5bd3f8..03bc2f175 100644 --- a/quinn/src/runtime.rs +++ b/quinn/src/runtime.rs @@ -70,7 +70,8 @@ pub trait AsyncUdpSocket: Send + Sync + Debug + 'static { /// /// If `runtime-tokio` is enabled and this function is called from within a Tokio runtime context, /// then `TokioRuntime` is returned. Otherwise, if `runtime-async-std` is enabled, `AsyncStdRuntime` -/// is returned. Otherwise, `None` is returned. +/// is returned. Otherwise, if `runtime-smol` is enabled, `SmolRuntime` is returned. +/// Otherwise, `None` is returned. pub fn default_runtime() -> Option> { #[cfg(feature = "runtime-tokio")] { @@ -84,7 +85,12 @@ pub fn default_runtime() -> Option> { return Some(Arc::new(AsyncStdRuntime)); } - #[cfg(not(feature = "runtime-async-std"))] + #[cfg(all(feature = "runtime-smol", not(feature = "runtime-async-std")))] + { + return Some(Arc::new(SmolRuntime)); + } + + #[cfg(not(any(feature = "runtime-async-std", feature = "runtime-smol")))] None } @@ -93,7 +99,7 @@ mod tokio; #[cfg(feature = "runtime-tokio")] pub use self::tokio::TokioRuntime; -#[cfg(feature = "runtime-async-std")] -mod async_std; -#[cfg(feature = "runtime-async-std")] -pub use self::async_std::AsyncStdRuntime; +#[cfg(feature = "async-io")] +mod async_io; +#[cfg(feature = "async-io")] +pub use self::async_io::*; diff --git a/quinn/src/runtime/async_std.rs b/quinn/src/runtime/async_io.rs similarity index 54% rename from quinn/src/runtime/async_std.rs rename to quinn/src/runtime/async_io.rs index ddff8fef1..5fd0bcfcb 100644 --- a/quinn/src/runtime/async_std.rs +++ b/quinn/src/runtime/async_io.rs @@ -11,24 +11,61 @@ use async_io::{Async, Timer}; use super::{AsyncTimer, AsyncUdpSocket, Runtime}; -/// A Quinn runtime for async-std -#[derive(Debug)] -pub struct AsyncStdRuntime; +#[cfg(feature = "smol")] +pub use self::smol::SmolRuntime; -impl Runtime for AsyncStdRuntime { - fn new_timer(&self, t: Instant) -> Pin> { - Box::pin(Timer::at(t)) - } +#[cfg(feature = "smol")] +mod smol { + use super::*; + + /// A Quinn runtime for smol + #[derive(Debug)] + pub struct SmolRuntime; + + impl Runtime for SmolRuntime { + fn new_timer(&self, t: Instant) -> Pin> { + Box::pin(Timer::at(t)) + } + + fn spawn(&self, future: Pin + Send>>) { + ::smol::spawn(future).detach(); + } - fn spawn(&self, future: Pin + Send>>) { - async_std::task::spawn(future); + fn wrap_udp_socket( + &self, + sock: std::net::UdpSocket, + ) -> io::Result> { + Ok(Arc::new(UdpSocket::new(sock)?)) + } } +} - fn wrap_udp_socket(&self, sock: std::net::UdpSocket) -> io::Result> { - Ok(Arc::new(UdpSocket { - inner: udp::UdpSocketState::new((&sock).into())?, - io: Async::new(sock)?, - })) +#[cfg(feature = "async-std")] +pub use self::async_std::AsyncStdRuntime; + +#[cfg(feature = "async-std")] +mod async_std { + use super::*; + + /// A Quinn runtime for async-std + #[derive(Debug)] + pub struct AsyncStdRuntime; + + impl Runtime for AsyncStdRuntime { + fn new_timer(&self, t: Instant) -> Pin> { + Box::pin(Timer::at(t)) + } + + fn spawn(&self, future: Pin + Send>>) { + ::async_std::task::spawn(future); + } + + fn wrap_udp_socket( + &self, + sock: std::net::UdpSocket, + ) -> io::Result> { + Ok(Arc::new(UdpSocket::new(sock)?)) + } } } @@ -48,6 +85,15 @@ struct UdpSocket { inner: udp::UdpSocketState, } +impl UdpSocket { + fn new(sock: std::net::UdpSocket) -> io::Result { + Ok(Self { + inner: udp::UdpSocketState::new((&sock).into())?, + io: Async::new(sock)?, + }) + } +} + impl AsyncUdpSocket for UdpSocket { fn poll_send(&self, cx: &mut Context, transmits: &[udp::Transmit]) -> Poll> { loop {