use dever_runtime::{ channel::{Channel, Error}, task::{Limits, Runtime}, }; use std::{ future::{Future, poll_fn}, sync::{ Arc, atomic::{AtomicUsize, Ordering}, }, task::Poll, }; fn runtime() -> Runtime { Runtime::new(Limits { threads: 2, workers: 1, tasks: 8, }) .unwrap() } async fn pending(future: std::pin::Pin<&mut impl Future>) { let mut future = future; poll_fn(|context| { assert!(future.as_mut().poll(context).is_pending()); Poll::Ready(()) }) .await; } #[test] fn capacity_is_bounded() { for capacity in [-1, 0, 65537] { assert!(matches!( Channel::::new(capacity), Err(Error::Capacity) )); } Channel::::new(1).unwrap(); Channel::::new(65536).unwrap(); } #[test] fn backpressure_preserves_fifo_and_nullable_items() { runtime() .run(async |_| { let channel = Channel::new(1).unwrap(); channel.send(Some(1)).await.unwrap(); let mut sent = std::pin::pin!(channel.send(None)); pending(sent.as_mut()).await; assert_eq!(channel.receive().await, Ok(Some(Some(1)))); sent.await.unwrap(); let alias = channel.clone(); alias.close().await.unwrap(); channel.close().await.unwrap(); assert_eq!(channel.receive().await, Ok(Some(None))); assert_eq!(alias.receive().await, Ok(None)); }) .unwrap(); } #[test] fn close_wakes_senders_and_all_receivers_without_discarding_queued_values() { runtime() .run(async |_| { let channel = Channel::new(1).unwrap(); channel.send(1).await.unwrap(); let mut sent = std::pin::pin!(channel.send(2)); pending(sent.as_mut()).await; channel.close().await.unwrap(); assert_eq!(sent.await, Err(Error::Closed)); assert_eq!(channel.receive().await, Ok(Some(1))); assert_eq!(channel.receive().await, Ok(None)); let empty = Channel::::new(1).unwrap(); let mut first = std::pin::pin!(empty.receive()); let mut second = std::pin::pin!(empty.receive()); pending(first.as_mut()).await; pending(second.as_mut()).await; empty.close().await.unwrap(); assert_eq!(first.await, Ok(None)); assert_eq!(second.await, Ok(None)); }) .unwrap(); } #[test] fn cancelling_waiters_returns_reserved_capacity_and_items() { runtime() .run(async |_| { let channel = Channel::new(1).unwrap(); channel.send(1).await.unwrap(); { let mut sent = std::pin::pin!(channel.send(2)); pending(sent.as_mut()).await; assert_eq!(channel.receive().await, Ok(Some(1))); } channel.send(3).await.unwrap(); assert_eq!(channel.receive().await, Ok(Some(3))); { let mut received = std::pin::pin!(channel.receive()); pending(received.as_mut()).await; channel.send(4).await.unwrap(); } assert_eq!(channel.receive().await, Ok(Some(4))); }) .unwrap(); } #[test] fn producers_and_consumers_transfer_every_item_once() { runtime() .run(async |scope| { let channel = Channel::new(4).unwrap(); let mut producers = Vec::new(); let mut consumers = Vec::new(); for start in [0, 64] { let sender = channel.clone(); producers.push( scope .spawn_leaf(move || async move { for value in start..start + 64 { sender.send(value).await.unwrap(); } }) .unwrap(), ); let channel = channel.clone(); consumers.push( scope .spawn_leaf(move || async move { let mut values = Vec::new(); while let Some(value) = channel.receive().await.unwrap() { values.push(value); } values }) .unwrap(), ); } for task in producers { task.wait().await.unwrap(); } channel.close().await.unwrap(); let mut received = Vec::new(); for task in consumers { received.extend(task.wait().await.unwrap()); } received.sort(); assert_eq!(received, (0..128).collect::>()); }) .unwrap(); } struct Notice(Arc); impl Drop for Notice { fn drop(&mut self) { self.0.fetch_add(1, Ordering::SeqCst); } } #[test] fn last_alias_releases_nonclone_messages_once() { let drops = Arc::new(AtomicUsize::new(0)); runtime() .run(async |_| { let channel = Channel::new(1).unwrap(); channel.send(Notice(drops.clone())).await.unwrap(); let alias = channel.clone(); drop(channel); assert_eq!(drops.load(Ordering::SeqCst), 0); drop(alias); assert_eq!(drops.load(Ordering::SeqCst), 1); }) .unwrap(); }