use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
use std::sync::Arc;
use std::task::{Context, Poll};
use std::time::Duration;
use tokio::sync::mpsc;
use tokio::sync::mpsc::error::{SendError, SendTimeoutError, TryRecvError, TrySendError};
use crate::channels::{
register_channel_wrap, send_channel_event, ChannelEvent, ChannelType, Instant,
InstrumentChannelWrap, InstrumentChannelWrapLog,
};
type Payload<T> = (u64, Option<Instant>, T);
#[inline]
fn delay_nanos(send_ts: Instant, now: Instant) -> u64 {
now.duration_since(send_ts).as_nanos() as u64
}
#[inline]
fn sample_stamp(msg_id: u64) -> Option<Instant> {
crate::lib_on::sampling::channels_should_time(msg_id).then(Instant::now)
}
#[inline]
fn recv_stamp(send_ts: Option<Instant>) -> (Option<Instant>, Option<u64>) {
match send_ts {
Some(ts) => {
let now = Instant::now();
(Some(now), Some(delay_nanos(ts, now)))
}
None => (None, None),
}
}
#[inline]
fn clamp_to_capacity(queue_len: usize, capacity: Option<usize>) -> usize {
match capacity {
Some(cap) => queue_len.min(cap),
None => queue_len,
}
}
fn emit_sent(
id: u32,
msg_id: u64,
sent_at: Option<Instant>,
log: Option<String>,
queue_len: usize,
) {
send_channel_event(ChannelEvent::WrapMessageSent {
id,
msg_id,
log,
timestamp: crate::channels::anchor_first_msg(msg_id, sent_at),
queue_len,
});
}
fn emit_received(
id: u32,
msg_id: u64,
now: Option<Instant>,
queue_len: usize,
delay_nanos: Option<u64>,
) {
send_channel_event(ChannelEvent::WrapMessageReceived {
id,
msg_id,
timestamp: now,
queue_len,
delay_nanos,
});
}
fn bump_if_alive(sender_count: &AtomicUsize) -> Option<()> {
let mut count = sender_count.load(Ordering::Acquire);
loop {
if count == 0 {
return None;
}
match sender_count.compare_exchange_weak(
count,
count + 1,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => return Some(()),
Err(current) => count = current,
}
}
}
pub struct Sender<T> {
inner: mpsc::Sender<Payload<T>>,
id: u32,
capacity: usize,
sender_count: Arc<AtomicUsize>,
next_id: Arc<AtomicU64>,
depth: Arc<AtomicUsize>,
log_fn: Option<fn(&T) -> String>,
}
impl<T> Sender<T> {
pub async fn send(&self, msg: T) -> Result<(), SendError<T>> {
let log = self.log_fn.map(|f| f(&msg));
let msg_id = self.next_id.fetch_add(1, Ordering::Relaxed);
let sent_at = sample_stamp(msg_id);
let queue_len = (self.depth.fetch_add(1, Ordering::Relaxed) + 1).min(self.capacity);
match self.inner.send((msg_id, sent_at, msg)).await {
Ok(()) => {
emit_sent(self.id, msg_id, sent_at, log, queue_len);
Ok(())
}
Err(SendError((_, _, msg))) => {
self.depth.fetch_sub(1, Ordering::Relaxed);
Err(SendError(msg))
}
}
}
pub fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
let log = self.log_fn.map(|f| f(&msg));
let msg_id = self.next_id.fetch_add(1, Ordering::Relaxed);
let sent_at = sample_stamp(msg_id);
let queue_len = (self.depth.fetch_add(1, Ordering::Relaxed) + 1).min(self.capacity);
match self.inner.try_send((msg_id, sent_at, msg)) {
Ok(()) => {
emit_sent(self.id, msg_id, sent_at, log, queue_len);
Ok(())
}
Err(e) => {
self.depth.fetch_sub(1, Ordering::Relaxed);
Err(match e {
TrySendError::Full((_, _, msg)) => TrySendError::Full(msg),
TrySendError::Closed((_, _, msg)) => TrySendError::Closed(msg),
})
}
}
}
pub async fn send_timeout(&self, msg: T, timeout: Duration) -> Result<(), SendTimeoutError<T>> {
let log = self.log_fn.map(|f| f(&msg));
let msg_id = self.next_id.fetch_add(1, Ordering::Relaxed);
let sent_at = sample_stamp(msg_id);
let queue_len = (self.depth.fetch_add(1, Ordering::Relaxed) + 1).min(self.capacity);
match self
.inner
.send_timeout((msg_id, sent_at, msg), timeout)
.await
{
Ok(()) => {
emit_sent(self.id, msg_id, sent_at, log, queue_len);
Ok(())
}
Err(e) => {
self.depth.fetch_sub(1, Ordering::Relaxed);
Err(match e {
SendTimeoutError::Timeout((_, _, msg)) => SendTimeoutError::Timeout(msg),
SendTimeoutError::Closed((_, _, msg)) => SendTimeoutError::Closed(msg),
})
}
}
}
pub fn blocking_send(&self, msg: T) -> Result<(), SendError<T>> {
let log = self.log_fn.map(|f| f(&msg));
let msg_id = self.next_id.fetch_add(1, Ordering::Relaxed);
let sent_at = sample_stamp(msg_id);
let queue_len = (self.depth.fetch_add(1, Ordering::Relaxed) + 1).min(self.capacity);
match self.inner.blocking_send((msg_id, sent_at, msg)) {
Ok(()) => {
emit_sent(self.id, msg_id, sent_at, log, queue_len);
Ok(())
}
Err(SendError((_, _, msg))) => {
self.depth.fetch_sub(1, Ordering::Relaxed);
Err(SendError(msg))
}
}
}
pub async fn closed(&self) {
self.inner.closed().await
}
pub fn is_closed(&self) -> bool {
self.inner.is_closed()
}
pub fn same_channel(&self, other: &Self) -> bool {
self.inner.same_channel(&other.inner)
}
pub fn downgrade(&self) -> WeakSender<T> {
WeakSender {
inner: self.inner.downgrade(),
id: self.id,
capacity: self.capacity,
sender_count: Arc::clone(&self.sender_count),
next_id: Arc::clone(&self.next_id),
depth: Arc::clone(&self.depth),
log_fn: self.log_fn,
}
}
pub fn strong_count(&self) -> usize {
self.inner.strong_count()
}
pub fn weak_count(&self) -> usize {
self.inner.weak_count()
}
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
pub fn max_capacity(&self) -> usize {
self.inner.max_capacity()
}
}
impl<T> Clone for Sender<T> {
fn clone(&self) -> Self {
self.sender_count.fetch_add(1, Ordering::Relaxed);
Self {
inner: self.inner.clone(),
id: self.id,
capacity: self.capacity,
sender_count: Arc::clone(&self.sender_count),
next_id: Arc::clone(&self.next_id),
depth: Arc::clone(&self.depth),
log_fn: self.log_fn,
}
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
if self.sender_count.fetch_sub(1, Ordering::AcqRel) == 1 {
send_channel_event(ChannelEvent::Closed { id: self.id });
}
}
}
pub struct WeakSender<T> {
inner: mpsc::WeakSender<Payload<T>>,
id: u32,
capacity: usize,
sender_count: Arc<AtomicUsize>,
next_id: Arc<AtomicU64>,
depth: Arc<AtomicUsize>,
log_fn: Option<fn(&T) -> String>,
}
impl<T> WeakSender<T> {
pub fn upgrade(&self) -> Option<Sender<T>> {
let tx = self.inner.upgrade()?;
bump_if_alive(&self.sender_count)?;
Some(Sender {
inner: tx,
id: self.id,
capacity: self.capacity,
sender_count: Arc::clone(&self.sender_count),
next_id: Arc::clone(&self.next_id),
depth: Arc::clone(&self.depth),
log_fn: self.log_fn,
})
}
pub fn strong_count(&self) -> usize {
self.inner.strong_count()
}
pub fn weak_count(&self) -> usize {
self.inner.weak_count()
}
}
impl<T> Clone for WeakSender<T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
id: self.id,
capacity: self.capacity,
sender_count: Arc::clone(&self.sender_count),
next_id: Arc::clone(&self.next_id),
depth: Arc::clone(&self.depth),
log_fn: self.log_fn,
}
}
}
pub struct Receiver<T> {
inner: mpsc::Receiver<Payload<T>>,
id: u32,
capacity: Option<usize>,
depth: Arc<AtomicUsize>,
poll_buf: Vec<Payload<T>>,
}
impl<T> Receiver<T> {
fn on_received(&self, msg_id: u64, now: Option<Instant>, delay_nanos: Option<u64>) {
let queue_len = clamp_to_capacity(
self.depth.fetch_sub(1, Ordering::Relaxed) - 1,
self.capacity,
);
emit_received(self.id, msg_id, now, queue_len, delay_nanos);
}
fn flush_poll_buf(&mut self, buffer: &mut Vec<T>) {
let mut payloads = std::mem::take(&mut self.poll_buf);
buffer.reserve(payloads.len());
for (msg_id, send_ts, msg) in payloads.drain(..) {
let (now, delay) = recv_stamp(send_ts);
self.on_received(msg_id, now, delay);
buffer.push(msg);
}
self.poll_buf = payloads;
}
pub async fn recv(&mut self) -> Option<T> {
let (msg_id, send_ts, msg) = self.inner.recv().await?;
let (now, delay) = recv_stamp(send_ts);
self.on_received(msg_id, now, delay);
Some(msg)
}
pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
let (msg_id, send_ts, msg) = self.inner.try_recv()?;
let (now, delay) = recv_stamp(send_ts);
self.on_received(msg_id, now, delay);
Ok(msg)
}
pub async fn recv_many(&mut self, buffer: &mut Vec<T>, limit: usize) -> usize {
let n = self.inner.recv_many(&mut self.poll_buf, limit).await;
self.flush_poll_buf(buffer);
n
}
pub fn blocking_recv(&mut self) -> Option<T> {
let (msg_id, send_ts, msg) = self.inner.blocking_recv()?;
let (now, delay) = recv_stamp(send_ts);
self.on_received(msg_id, now, delay);
Some(msg)
}
pub fn blocking_recv_many(&mut self, buffer: &mut Vec<T>, limit: usize) -> usize {
let n = self.inner.blocking_recv_many(&mut self.poll_buf, limit);
self.flush_poll_buf(buffer);
n
}
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
match self.inner.poll_recv(cx) {
Poll::Ready(Some((msg_id, send_ts, msg))) => {
let (now, delay) = recv_stamp(send_ts);
self.on_received(msg_id, now, delay);
Poll::Ready(Some(msg))
}
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending,
}
}
pub fn poll_recv_many(
&mut self,
cx: &mut Context<'_>,
buffer: &mut Vec<T>,
limit: usize,
) -> Poll<usize> {
match self.inner.poll_recv_many(cx, &mut self.poll_buf, limit) {
Poll::Ready(n) => {
self.flush_poll_buf(buffer);
Poll::Ready(n)
}
Poll::Pending => Poll::Pending,
}
}
pub fn close(&mut self) {
self.inner.close();
}
pub fn is_closed(&self) -> bool {
self.inner.is_closed()
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn sender_strong_count(&self) -> usize {
self.inner.sender_strong_count()
}
pub fn sender_weak_count(&self) -> usize {
self.inner.sender_weak_count()
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
send_channel_event(ChannelEvent::Closed { id: self.id });
}
}
unsafe impl<T: Send> Sync for Receiver<T> {}
pub struct UnboundedSender<T> {
inner: mpsc::UnboundedSender<Payload<T>>,
id: u32,
sender_count: Arc<AtomicUsize>,
next_id: Arc<AtomicU64>,
depth: Arc<AtomicUsize>,
log_fn: Option<fn(&T) -> String>,
}
impl<T> UnboundedSender<T> {
pub fn send(&self, msg: T) -> Result<(), SendError<T>> {
let log = self.log_fn.map(|f| f(&msg));
let msg_id = self.next_id.fetch_add(1, Ordering::Relaxed);
let sent_at = sample_stamp(msg_id);
let queue_len = self.depth.fetch_add(1, Ordering::Relaxed) + 1;
match self.inner.send((msg_id, sent_at, msg)) {
Ok(()) => {
emit_sent(self.id, msg_id, sent_at, log, queue_len);
Ok(())
}
Err(SendError((_, _, msg))) => {
self.depth.fetch_sub(1, Ordering::Relaxed);
Err(SendError(msg))
}
}
}
pub async fn closed(&self) {
self.inner.closed().await
}
pub fn is_closed(&self) -> bool {
self.inner.is_closed()
}
pub fn same_channel(&self, other: &Self) -> bool {
self.inner.same_channel(&other.inner)
}
pub fn downgrade(&self) -> WeakUnboundedSender<T> {
WeakUnboundedSender {
inner: self.inner.downgrade(),
id: self.id,
sender_count: Arc::clone(&self.sender_count),
next_id: Arc::clone(&self.next_id),
depth: Arc::clone(&self.depth),
log_fn: self.log_fn,
}
}
pub fn strong_count(&self) -> usize {
self.inner.strong_count()
}
pub fn weak_count(&self) -> usize {
self.inner.weak_count()
}
}
impl<T> Clone for UnboundedSender<T> {
fn clone(&self) -> Self {
self.sender_count.fetch_add(1, Ordering::Relaxed);
Self {
inner: self.inner.clone(),
id: self.id,
sender_count: Arc::clone(&self.sender_count),
next_id: Arc::clone(&self.next_id),
depth: Arc::clone(&self.depth),
log_fn: self.log_fn,
}
}
}
impl<T> Drop for UnboundedSender<T> {
fn drop(&mut self) {
if self.sender_count.fetch_sub(1, Ordering::AcqRel) == 1 {
send_channel_event(ChannelEvent::Closed { id: self.id });
}
}
}
pub struct WeakUnboundedSender<T> {
inner: mpsc::WeakUnboundedSender<Payload<T>>,
id: u32,
sender_count: Arc<AtomicUsize>,
next_id: Arc<AtomicU64>,
depth: Arc<AtomicUsize>,
log_fn: Option<fn(&T) -> String>,
}
impl<T> WeakUnboundedSender<T> {
pub fn upgrade(&self) -> Option<UnboundedSender<T>> {
let tx = self.inner.upgrade()?;
bump_if_alive(&self.sender_count)?;
Some(UnboundedSender {
inner: tx,
id: self.id,
sender_count: Arc::clone(&self.sender_count),
next_id: Arc::clone(&self.next_id),
depth: Arc::clone(&self.depth),
log_fn: self.log_fn,
})
}
pub fn strong_count(&self) -> usize {
self.inner.strong_count()
}
pub fn weak_count(&self) -> usize {
self.inner.weak_count()
}
}
impl<T> Clone for WeakUnboundedSender<T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
id: self.id,
sender_count: Arc::clone(&self.sender_count),
next_id: Arc::clone(&self.next_id),
depth: Arc::clone(&self.depth),
log_fn: self.log_fn,
}
}
}
pub struct UnboundedReceiver<T> {
inner: mpsc::UnboundedReceiver<Payload<T>>,
id: u32,
depth: Arc<AtomicUsize>,
poll_buf: Vec<Payload<T>>,
}
impl<T> UnboundedReceiver<T> {
fn on_received(&self, msg_id: u64, now: Option<Instant>, delay_nanos: Option<u64>) {
let queue_len = self.depth.fetch_sub(1, Ordering::Relaxed) - 1;
emit_received(self.id, msg_id, now, queue_len, delay_nanos);
}
fn flush_poll_buf(&mut self, buffer: &mut Vec<T>) {
let mut payloads = std::mem::take(&mut self.poll_buf);
buffer.reserve(payloads.len());
for (msg_id, send_ts, msg) in payloads.drain(..) {
let (now, delay) = recv_stamp(send_ts);
self.on_received(msg_id, now, delay);
buffer.push(msg);
}
self.poll_buf = payloads;
}
pub async fn recv(&mut self) -> Option<T> {
let (msg_id, send_ts, msg) = self.inner.recv().await?;
let (now, delay) = recv_stamp(send_ts);
self.on_received(msg_id, now, delay);
Some(msg)
}
pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
let (msg_id, send_ts, msg) = self.inner.try_recv()?;
let (now, delay) = recv_stamp(send_ts);
self.on_received(msg_id, now, delay);
Ok(msg)
}
pub async fn recv_many(&mut self, buffer: &mut Vec<T>, limit: usize) -> usize {
let n = self.inner.recv_many(&mut self.poll_buf, limit).await;
self.flush_poll_buf(buffer);
n
}
pub fn blocking_recv(&mut self) -> Option<T> {
let (msg_id, send_ts, msg) = self.inner.blocking_recv()?;
let (now, delay) = recv_stamp(send_ts);
self.on_received(msg_id, now, delay);
Some(msg)
}
pub fn blocking_recv_many(&mut self, buffer: &mut Vec<T>, limit: usize) -> usize {
let n = self.inner.blocking_recv_many(&mut self.poll_buf, limit);
self.flush_poll_buf(buffer);
n
}
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
match self.inner.poll_recv(cx) {
Poll::Ready(Some((msg_id, send_ts, msg))) => {
let (now, delay) = recv_stamp(send_ts);
self.on_received(msg_id, now, delay);
Poll::Ready(Some(msg))
}
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending,
}
}
pub fn poll_recv_many(
&mut self,
cx: &mut Context<'_>,
buffer: &mut Vec<T>,
limit: usize,
) -> Poll<usize> {
match self.inner.poll_recv_many(cx, &mut self.poll_buf, limit) {
Poll::Ready(n) => {
self.flush_poll_buf(buffer);
Poll::Ready(n)
}
Poll::Pending => Poll::Pending,
}
}
pub fn close(&mut self) {
self.inner.close();
}
pub fn is_closed(&self) -> bool {
self.inner.is_closed()
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn sender_strong_count(&self) -> usize {
self.inner.sender_strong_count()
}
pub fn sender_weak_count(&self) -> usize {
self.inner.sender_weak_count()
}
}
impl<T> Drop for UnboundedReceiver<T> {
fn drop(&mut self) {
send_channel_event(ChannelEvent::Closed { id: self.id });
}
}
unsafe impl<T: Send> Sync for UnboundedReceiver<T> {}
macro_rules! impl_debug_via_inner {
($($ty:ident),+) => {$(
impl<T> std::fmt::Debug for $ty<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(stringify!($ty))
.field("inner", &self.inner)
.field("id", &self.id)
.finish_non_exhaustive()
}
}
)+};
}
impl_debug_via_inner!(
Sender,
Receiver,
UnboundedSender,
UnboundedReceiver,
WeakSender,
WeakUnboundedSender
);
fn build_bounded<T>(
inner: (mpsc::Sender<T>, mpsc::Receiver<T>),
source: &'static str,
label: Option<String>,
log_fn: Option<fn(&T) -> String>,
) -> (Sender<T>, Receiver<T>) {
let capacity = inner.0.max_capacity();
let id = register_channel_wrap::<T>(source, label, ChannelType::Bounded(capacity));
let (tx, rx) = mpsc::channel::<Payload<T>>(capacity);
let depth = Arc::new(AtomicUsize::new(0));
let sender = Sender {
inner: tx,
id,
capacity,
sender_count: Arc::new(AtomicUsize::new(1)),
next_id: Arc::new(AtomicU64::new(0)),
depth: Arc::clone(&depth),
log_fn,
};
let receiver = Receiver {
inner: rx,
id,
capacity: Some(capacity),
depth,
poll_buf: Vec::new(),
};
(sender, receiver)
}
fn build_unbounded<T>(
source: &'static str,
label: Option<String>,
log_fn: Option<fn(&T) -> String>,
) -> (UnboundedSender<T>, UnboundedReceiver<T>) {
let id = register_channel_wrap::<T>(source, label, ChannelType::Unbounded);
let (tx, rx) = mpsc::unbounded_channel::<Payload<T>>();
let depth = Arc::new(AtomicUsize::new(0));
let sender = UnboundedSender {
inner: tx,
id,
sender_count: Arc::new(AtomicUsize::new(1)),
next_id: Arc::new(AtomicU64::new(0)),
depth: Arc::clone(&depth),
log_fn,
};
let receiver = UnboundedReceiver {
inner: rx,
id,
depth,
poll_buf: Vec::new(),
};
(sender, receiver)
}
impl<T: Send + 'static> InstrumentChannelWrap for (mpsc::Sender<T>, mpsc::Receiver<T>) {
type Output = (Sender<T>, Receiver<T>);
fn instrument_wrap(
self,
source: &'static str,
label: Option<String>,
_capacity: Option<usize>,
) -> Self::Output {
build_bounded(self, source, label, None)
}
}
impl<T: Send + 'static> InstrumentChannelWrap
for (mpsc::UnboundedSender<T>, mpsc::UnboundedReceiver<T>)
{
type Output = (UnboundedSender<T>, UnboundedReceiver<T>);
fn instrument_wrap(
self,
source: &'static str,
label: Option<String>,
_capacity: Option<usize>,
) -> Self::Output {
build_unbounded(source, label, None)
}
}
impl<T: Send + std::fmt::Debug + 'static> InstrumentChannelWrapLog
for (mpsc::Sender<T>, mpsc::Receiver<T>)
{
type Output = (Sender<T>, Receiver<T>);
fn instrument_wrap_log(
self,
source: &'static str,
label: Option<String>,
_capacity: Option<usize>,
) -> Self::Output {
let log_fn: fn(&T) -> String = |m| crate::output::format_debug_truncated(m);
build_bounded(self, source, label, Some(log_fn))
}
}
impl<T: Send + std::fmt::Debug + 'static> InstrumentChannelWrapLog
for (mpsc::UnboundedSender<T>, mpsc::UnboundedReceiver<T>)
{
type Output = (UnboundedSender<T>, UnboundedReceiver<T>);
fn instrument_wrap_log(
self,
source: &'static str,
label: Option<String>,
_capacity: Option<usize>,
) -> Self::Output {
let log_fn: fn(&T) -> String = |m| crate::output::format_debug_truncated(m);
build_unbounded(source, label, Some(log_fn))
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::future::poll_fn;
fn bounded<T: Send + 'static>(capacity: usize) -> (Sender<T>, Receiver<T>) {
build_bounded(mpsc::channel::<T>(capacity), "test", None, None)
}
fn unbounded<T: Send + 'static>() -> (UnboundedSender<T>, UnboundedReceiver<T>) {
build_unbounded::<T>("test", None, None)
}
#[test]
fn send_only_payload_keeps_endpoints_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
type P = std::cell::Cell<u8>;
assert_send_sync::<Sender<P>>();
assert_send_sync::<Receiver<P>>();
assert_send_sync::<UnboundedSender<P>>();
assert_send_sync::<UnboundedReceiver<P>>();
assert_send_sync::<WeakSender<P>>();
assert_send_sync::<WeakUnboundedSender<P>>();
}
#[test]
fn weak_sender_upgrade_lifecycle() {
let (tx, rx) = bounded::<u32>(4);
let weak = tx.downgrade();
assert_eq!(tx.strong_count(), 1);
assert_eq!(tx.weak_count(), 1);
let tx2 = weak.upgrade().expect("upgrade with strong sender alive");
assert_eq!(tx.strong_count(), 2);
assert_eq!(rx.sender_strong_count(), tx.strong_count());
assert_eq!(rx.sender_weak_count(), tx.weak_count());
drop(tx);
drop(tx2);
assert!(weak.upgrade().is_none());
assert_eq!(weak.strong_count(), 0);
}
#[test]
fn weak_unbounded_sender_upgrade_lifecycle() {
let (tx, rx) = unbounded::<u32>();
let weak = tx.downgrade();
let tx2 = weak.upgrade().expect("upgrade with strong sender alive");
assert_eq!(rx.sender_strong_count(), 2);
assert_eq!(rx.sender_weak_count(), 1);
drop(tx);
drop(tx2);
assert!(weak.upgrade().is_none());
}
#[test]
fn same_channel_across_clones() {
let (tx_a, _rx_a) = bounded::<u32>(4);
let (tx_b, _rx_b) = bounded::<u32>(4);
assert!(tx_a.same_channel(&tx_a.clone()));
assert!(!tx_a.same_channel(&tx_b));
let (utx_a, _urx_a) = unbounded::<u32>();
let (utx_b, _urx_b) = unbounded::<u32>();
assert!(utx_a.same_channel(&utx_a.clone()));
assert!(!utx_a.same_channel(&utx_b));
}
#[test]
fn len_tracks_inner_channel() {
let (tx, mut rx) = bounded::<u32>(4);
assert!(rx.is_empty());
tx.try_send(1).unwrap();
tx.try_send(2).unwrap();
assert_eq!(rx.len(), 2);
rx.try_recv().unwrap();
assert_eq!(rx.len(), 1);
rx.try_recv().unwrap();
assert!(rx.is_empty());
}
#[test]
fn close_stops_sends_but_drains() {
let (tx, mut rx) = bounded::<u32>(4);
tx.try_send(1).unwrap();
rx.close();
assert!(rx.is_closed());
assert!(matches!(tx.try_send(2), Err(TrySendError::Closed(2))));
assert_eq!(rx.try_recv(), Ok(1));
}
#[test]
fn blocking_send_recv_off_runtime() {
let (tx, mut rx) = bounded::<u32>(4);
let producer = std::thread::spawn(move || {
for i in 0..25 {
tx.blocking_send(i).unwrap();
}
});
let consumer = std::thread::spawn(move || {
let mut buf = Vec::new();
while let Some(v) = rx.blocking_recv() {
buf.push(v);
if rx.blocking_recv_many(&mut buf, 8) == 0 {
break;
}
}
buf
});
producer.join().unwrap();
let buf = consumer.join().unwrap();
assert_eq!(buf, (0..25).collect::<Vec<_>>());
}
#[tokio::test]
async fn send_timeout_rolls_back_depth() {
let (tx, mut rx) = bounded::<u32>(2);
tx.send(0).await.unwrap();
tx.send(1).await.unwrap();
let err = tx.send_timeout(2, Duration::from_millis(10)).await;
assert!(matches!(err, Err(SendTimeoutError::Timeout(2))));
assert_eq!(rx.len(), 2);
assert_eq!(rx.recv().await, Some(0));
tx.send_timeout(3, Duration::from_millis(10)).await.unwrap();
}
#[tokio::test]
async fn poll_recv_many_pending_then_ready() {
let (tx, mut rx) = bounded::<u32>(8);
let mut buf = Vec::new();
let was_pending =
poll_fn(|cx| Poll::Ready(rx.poll_recv_many(cx, &mut buf, 4).is_pending())).await;
assert!(was_pending);
assert!(buf.is_empty());
for i in 0..6 {
tx.send(i).await.unwrap();
}
let n = poll_fn(|cx| rx.poll_recv_many(cx, &mut buf, 4)).await;
assert_eq!(n, 4);
let n = poll_fn(|cx| rx.poll_recv_many(cx, &mut buf, 4)).await;
assert_eq!(n, 2);
assert_eq!(buf, (0..6).collect::<Vec<_>>());
let was_pending = poll_fn(|cx| Poll::Ready(rx.poll_recv(cx).is_pending())).await;
assert!(was_pending);
drop(tx);
let closed = poll_fn(|cx| rx.poll_recv(cx)).await;
assert_eq!(closed, None);
}
}