use std::sync::Arc;
pub use quinn_udp::RecvMeta;
pub use quinn_udp::Transmit;
pub use quinn_udp::EcnCodepoint;
pub use quinn_udp::UdpSockRef;
pub use quinn_udp::BATCH_SIZE;
pub use quinn_udp::UdpSocketState;
#[derive(Debug, Default)]
pub struct Mutex<T: ?Sized>(Arc<futures::lock::Mutex<T>>);
impl<T: ?Sized> Clone for Mutex<T> {
fn clone(&self) -> Self {
Self(Arc::clone(&self.0))
}
}
impl<T> Mutex<T> {
pub fn new(value: T) -> Self {
Self(Arc::new(futures::lock::Mutex::new(value)))
}
}
impl<T: ?Sized> Mutex<T> {
pub async fn lock(&self) -> futures::lock::MutexGuard<'_, T> {
self.0.lock().await
}
pub fn try_lock(&self) -> Option<futures::lock::MutexGuard<'_, T>> {
self.0.try_lock()
}
}
#[derive(Debug, Clone, Default)]
pub struct Notify(Arc<event_listener::Event>);
impl Notify {
pub fn new() -> Self {
Self(Arc::new(event_listener::Event::new()))
}
pub fn notify_one(&self) {
self.0.notify(1);
}
pub fn notify_waiters(&self) {
self.0.notify(usize::MAX);
}
pub async fn notified(&self) {
self.0.listen().await;
}
}
#[derive(Debug)]
pub struct SendError<T>(pub T);
#[derive(Debug)]
pub enum TrySendError<T> {
Full(T),
Disconnected(T),
}
#[derive(Debug)]
pub enum TryRecvError {
Empty,
Disconnected,
}
impl<T> std::fmt::Display for SendError<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "channel disconnected")
}
}
impl<T: std::fmt::Debug> std::error::Error for SendError<T> {}
#[derive(Debug)]
pub struct Sender<T>(async_channel::Sender<T>);
impl<T> Clone for Sender<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T> Sender<T> {
pub async fn send(&self, value: T) -> Result<(), SendError<T>> {
self.0.send(value).await.map_err(|e| SendError(e.0))
}
pub fn try_send(&self, value: T) -> Result<(), TrySendError<T>> {
self.0.try_send(value).map_err(|e| match e {
async_channel::TrySendError::Full(v) => TrySendError::Full(v),
async_channel::TrySendError::Closed(v) => TrySendError::Disconnected(v),
})
}
pub fn is_closed(&self) -> bool {
self.0.is_closed()
}
}
#[derive(Debug)]
pub struct Receiver<T>(async_channel::Receiver<T>);
impl<T> Clone for Receiver<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T> Receiver<T> {
pub async fn recv(&mut self) -> Option<T> {
self.0.recv().await.ok()
}
pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
self.0.try_recv().map_err(|e| match e {
async_channel::TryRecvError::Empty => TryRecvError::Empty,
async_channel::TryRecvError::Closed => TryRecvError::Disconnected,
})
}
pub fn is_closed(&self) -> bool {
self.0.is_closed()
}
}
pub fn channel<T>(capacity: usize) -> (Sender<T>, Receiver<T>) {
let (tx, rx) = async_channel::bounded(capacity.max(1));
(Sender(tx), Receiver(rx))
}
#[derive(Debug)]
pub struct BroadcastSendError<T>(pub T);
#[derive(Debug)]
pub enum BroadcastRecvError {
Closed,
Lagged(u64),
}
impl<T> std::fmt::Display for BroadcastSendError<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "broadcast send failed: no receivers")
}
}
impl<T: std::fmt::Debug> std::error::Error for BroadcastSendError<T> {}
impl std::fmt::Display for BroadcastRecvError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BroadcastRecvError::Closed => write!(f, "broadcast channel closed"),
BroadcastRecvError::Lagged(n) => write!(f, "broadcast receiver lagged by {n}"),
}
}
}
impl std::error::Error for BroadcastRecvError {}
#[derive(Debug)]
pub struct BroadcastSender<T> {
tx: async_broadcast::Sender<T>,
inactive: async_broadcast::InactiveReceiver<T>,
}
impl<T> Clone for BroadcastSender<T> {
fn clone(&self) -> Self {
Self {
tx: self.tx.clone(),
inactive: self.inactive.clone(),
}
}
}
impl<T: Clone> BroadcastSender<T> {
pub fn send(&self, value: T) -> Result<usize, BroadcastSendError<T>> {
match self.tx.try_broadcast(value) {
Ok(_) => Ok(self.tx.receiver_count()),
Err(async_broadcast::TrySendError::Inactive(v)) => Err(BroadcastSendError(v)),
Err(async_broadcast::TrySendError::Closed(v)) => Err(BroadcastSendError(v)),
Err(async_broadcast::TrySendError::Full(v)) => Err(BroadcastSendError(v)),
}
}
pub fn subscribe(&self) -> BroadcastReceiver<T> {
BroadcastReceiver(self.inactive.activate_cloned())
}
pub fn receiver_count(&self) -> usize {
self.tx.receiver_count()
}
}
#[derive(Debug)]
pub struct BroadcastReceiver<T>(async_broadcast::Receiver<T>);
impl<T: Clone> Clone for BroadcastReceiver<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: Clone> BroadcastReceiver<T> {
pub async fn recv(&mut self) -> Result<T, BroadcastRecvError> {
match self.0.recv().await {
Ok(v) => Ok(v),
Err(async_broadcast::RecvError::Overflowed(n)) => Err(BroadcastRecvError::Lagged(n)),
Err(async_broadcast::RecvError::Closed) => Err(BroadcastRecvError::Closed),
}
}
}
pub fn broadcast_channel<T: Clone>(capacity: usize) -> BroadcastSender<T> {
let (mut tx, rx) = async_broadcast::broadcast(capacity.max(1));
tx.set_overflow(true);
BroadcastSender {
tx,
inactive: rx.deactivate(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mutex_shares_state_across_clones() {
let a = Mutex::new(0u32);
let b = a.clone();
futures::executor::block_on(async {
*a.lock().await = 7;
assert_eq!(*b.lock().await, 7, "clones must share one lock");
});
}
#[test]
fn mutex_try_lock_fails_while_held() {
let m = Mutex::new(1u32);
futures::executor::block_on(async {
let _g = m.lock().await;
assert!(m.try_lock().is_none());
});
assert!(m.try_lock().is_some(), "released after guard drop");
}
#[test]
fn channel_roundtrip_and_try_variants() {
let (tx, mut rx) = channel::<u8>(2);
futures::executor::block_on(async {
tx.send(1).await.unwrap();
tx.try_send(2).unwrap();
assert!(matches!(tx.try_send(3), Err(TrySendError::Full(3))));
assert_eq!(rx.recv().await, Some(1));
assert_eq!(rx.try_recv().unwrap(), 2);
assert!(matches!(rx.try_recv(), Err(TryRecvError::Empty)));
});
}
#[test]
fn channel_capacity_zero_is_clamped_not_panic() {
let (tx, mut rx) = channel::<u8>(0);
futures::executor::block_on(async {
tx.send(9).await.unwrap();
assert_eq!(rx.recv().await, Some(9));
});
}
#[test]
fn recv_returns_none_after_senders_dropped() {
let (tx, mut rx) = channel::<u8>(1);
drop(tx);
assert_eq!(futures::executor::block_on(rx.recv()), None);
}
#[test]
fn sender_reports_closed_when_receiver_dropped() {
let (tx, rx) = channel::<u8>(1);
assert!(!tx.is_closed());
drop(rx);
assert!(tx.is_closed());
}
#[test]
fn broadcast_reaches_every_subscriber() {
let tx = broadcast_channel::<u8>(4);
let mut a = tx.subscribe();
let mut b = tx.subscribe();
assert_eq!(tx.send(5).unwrap(), 2, "delivered to both subscribers");
futures::executor::block_on(async {
assert_eq!(a.recv().await.unwrap(), 5);
assert_eq!(b.recv().await.unwrap(), 5);
});
}
#[test]
fn broadcast_send_never_blocks_without_subscribers() {
let tx = broadcast_channel::<u8>(4);
assert!(
tx.send(1).is_err(),
"no active receivers => Err, not a hang"
);
assert_eq!(tx.receiver_count(), 0);
}
#[test]
fn broadcast_survives_losing_all_subscribers() {
let tx = broadcast_channel::<u8>(4);
futures::executor::block_on(async {
{
let mut early = tx.subscribe();
assert_eq!(tx.send(2).unwrap(), 1);
assert_eq!(early.recv().await.unwrap(), 2);
}
let mut late = tx.subscribe();
assert_eq!(
tx.send(3).unwrap(),
1,
"channel must remain open across a gap in subscribers"
);
assert_eq!(late.recv().await.unwrap(), 3);
});
}
#[test]
fn notify_waiters_wakes_a_parked_task() {
let n = Notify::new();
futures::executor::block_on(async {
let listener = n.0.listen();
n.notify_waiters();
listener.await;
});
}
#[test]
fn notify_with_no_waiters_stores_no_permit() {
let n = Notify::new();
n.notify_waiters();
let listener = n.0.listen();
assert!(
futures::FutureExt::now_or_never(listener).is_none(),
"notify_waiters must not store a permit for future waiters"
);
}
}