use core::cell::UnsafeCell;
use core::mem::MaybeUninit;
use core::sync::atomic::{AtomicUsize, Ordering};
#[derive(Debug, PartialEq, Eq)]
pub struct Full<T>(
pub T,
);
impl<T> Full<T> {
pub fn into_inner(self) -> T {
self.0
}
}
struct ChannelInner<T, const N: usize> {
buffer: [UnsafeCell<MaybeUninit<T>>; N],
head: AtomicUsize, tail: AtomicUsize, _sender_count: AtomicUsize,
_receiver_count: AtomicUsize,
}
unsafe impl<T: Send, const N: usize> Sync for ChannelInner<T, N> {}
unsafe impl<T: Send, const N: usize> Send for ChannelInner<T, N> {}
#[allow(dead_code)]
impl<T, const N: usize> ChannelInner<T, N> {
const fn new() -> Self {
Self {
buffer: unsafe {
MaybeUninit::<[UnsafeCell<MaybeUninit<T>>; N]>::uninit().assume_init()
},
head: AtomicUsize::new(0),
tail: AtomicUsize::new(0),
_sender_count: AtomicUsize::new(1),
_receiver_count: AtomicUsize::new(1),
}
}
fn try_send(&self, value: T) -> Result<(), Full<T>> {
if N == 0 {
return Err(Full(value));
}
loop {
let head = self.head.load(Ordering::Acquire);
let tail = self.tail.load(Ordering::Acquire);
if head.wrapping_sub(tail) >= N {
return Err(Full(value));
}
if self
.head
.compare_exchange_weak(head, head.wrapping_add(1), Ordering::AcqRel, Ordering::Acquire)
.is_ok()
{
let idx = head % N;
unsafe {
(*self.buffer[idx].get()) = MaybeUninit::new(value);
}
return Ok(());
}
core::hint::spin_loop();
}
}
fn try_recv(&self) -> Option<T> {
if N == 0 {
return None;
}
loop {
let tail = self.tail.load(Ordering::Acquire);
let head = self.head.load(Ordering::Acquire);
if tail == head {
return None;
}
if self
.tail
.compare_exchange_weak(tail, tail.wrapping_add(1), Ordering::AcqRel, Ordering::Acquire)
.is_ok()
{
let idx = tail % N;
let value = unsafe { (*self.buffer[idx].get()).assume_init_read() };
return Some(value);
}
core::hint::spin_loop();
}
}
fn len(&self) -> usize {
let head = self.head.load(Ordering::Acquire);
let tail = self.tail.load(Ordering::Acquire);
head.wrapping_sub(tail)
}
fn is_empty(&self) -> bool {
self.len() == 0
}
fn is_full(&self) -> bool {
self.len() >= N
}
}
impl<T, const N: usize> Drop for ChannelInner<T, N> {
fn drop(&mut self) {
let tail = *self.tail.get_mut();
let head = *self.head.get_mut();
let mut i = tail;
while i != head {
let idx = i % N;
unsafe {
self.buffer[idx].get_mut().assume_init_drop();
}
i = i.wrapping_add(1);
}
}
}
#[cfg(any(feature = "std", test))]
mod shared {
use super::*;
use alloc::sync::Arc;
pub struct Sender<T, const N: usize> {
inner: Arc<ChannelInner<T, N>>,
}
pub struct Receiver<T, const N: usize> {
inner: Arc<ChannelInner<T, N>>,
}
impl<T, const N: usize> Sender<T, N> {
pub fn try_send(&self, value: T) -> Result<(), Full<T>> {
self.inner.try_send(value)
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn is_full(&self) -> bool {
self.inner.is_full()
}
}
impl<T, const N: usize> Clone for Sender<T, N> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl<T, const N: usize> Receiver<T, N> {
pub fn try_recv(&self) -> Option<T> {
self.inner.try_recv()
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn is_full(&self) -> bool {
self.inner.is_full()
}
}
impl<T, const N: usize> Clone for Receiver<T, N> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl<T, const N: usize> core::fmt::Debug for Sender<T, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Sender")
.field("len", &self.len())
.field("capacity", &N)
.finish()
}
}
impl<T, const N: usize> core::fmt::Debug for Receiver<T, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Receiver")
.field("len", &self.len())
.field("capacity", &N)
.finish()
}
}
pub fn bounded_channel<T, const N: usize>() -> (Sender<T, N>, Receiver<T, N>) {
let inner = Arc::new(ChannelInner::new());
(
Sender { inner: inner.clone() },
Receiver { inner },
)
}
}
#[cfg(not(any(feature = "std", test)))]
#[allow(dead_code)]
mod shared {
use super::*;
pub struct Sender<T, const N: usize> { inner: *const ChannelInner<T, N> }
pub struct Receiver<T, const N: usize> { inner: *const ChannelInner<T, N> }
unsafe impl<T: Send, const N: usize> Send for Sender<T, N> {}
unsafe impl<T: Send, const N: usize> Sync for Sender<T, N> {}
unsafe impl<T: Send, const N: usize> Send for Receiver<T, N> {}
unsafe impl<T: Send, const N: usize> Sync for Receiver<T, N> {}
impl<T, const N: usize> Sender<T, N> {
pub fn try_send(&self, value: T) -> Result<(), Full<T>> { unsafe { &*self.inner }.try_send(value) }
pub fn len(&self) -> usize { unsafe { &*self.inner }.len() }
pub fn is_empty(&self) -> bool { unsafe { &*self.inner }.is_empty() }
pub fn is_full(&self) -> bool { unsafe { &*self.inner }.is_full() }
}
impl<T, const N: usize> Clone for Sender<T, N> { fn clone(&self) -> Self { Self { inner: self.inner } } }
impl<T, const N: usize> Receiver<T, N> {
pub fn try_recv(&self) -> Option<T> { unsafe { &*self.inner }.try_recv() }
pub fn len(&self) -> usize { unsafe { &*self.inner }.len() }
pub fn is_empty(&self) -> bool { unsafe { &*self.inner }.is_empty() }
pub fn is_full(&self) -> bool { unsafe { &*self.inner }.is_full() }
}
impl<T, const N: usize> Clone for Receiver<T, N> { fn clone(&self) -> Self { Self { inner: self.inner } } }
impl<T, const N: usize> core::fmt::Debug for Sender<T, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Sender").field("capacity", &N).finish() }
}
impl<T, const N: usize> core::fmt::Debug for Receiver<T, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Receiver").field("capacity", &N).finish() }
}
pub fn bounded_channel<T, const N: usize>() -> (Sender<T, N>, Receiver<T, N>) {
panic!("bounded_channel requires alloc feature or static storage in no_std mode")
}
}
pub use shared::{bounded_channel, Receiver, Sender};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn channel_send_recv() {
let (tx, rx) = bounded_channel::<u32, 4>();
tx.try_send(1).unwrap();
tx.try_send(2).unwrap();
assert_eq!(rx.try_recv(), Some(1));
assert_eq!(rx.try_recv(), Some(2));
assert_eq!(rx.try_recv(), None);
}
#[test]
fn channel_full() {
let (tx, rx) = bounded_channel::<u32, 2>();
tx.try_send(1).unwrap();
tx.try_send(2).unwrap();
assert!(tx.is_full());
let err = tx.try_send(3).unwrap_err();
assert_eq!(err.into_inner(), 3);
rx.try_recv().unwrap();
tx.try_send(3).unwrap();
}
#[test]
fn channel_empty() {
let (_tx, rx) = bounded_channel::<u32, 4>();
assert!(rx.is_empty());
assert_eq!(rx.try_recv(), None);
}
#[test]
fn channel_len() {
let (tx, rx) = bounded_channel::<u32, 8>();
assert_eq!(tx.len(), 0);
tx.try_send(1).unwrap();
tx.try_send(2).unwrap();
assert_eq!(tx.len(), 2);
assert_eq!(rx.len(), 2);
rx.try_recv().unwrap();
assert_eq!(tx.len(), 1);
}
#[test]
fn channel_fifo_order() {
let (tx, rx) = bounded_channel::<u32, 8>();
for i in 0..5 {
tx.try_send(i).unwrap();
}
for i in 0..5 {
assert_eq!(rx.try_recv(), Some(i));
}
}
#[test]
fn channel_clone_sender() {
let (tx, rx) = bounded_channel::<u32, 8>();
let tx2 = tx.clone();
tx.try_send(1).unwrap();
tx2.try_send(2).unwrap();
let a = rx.try_recv().unwrap();
let b = rx.try_recv().unwrap();
assert!((a == 1 && b == 2) || (a == 2 && b == 1));
}
#[test]
fn channel_clone_receiver() {
let (tx, rx) = bounded_channel::<u32, 8>();
let rx2 = rx.clone();
tx.try_send(1).unwrap();
tx.try_send(2).unwrap();
let a = rx.try_recv();
let b = rx2.try_recv();
assert!(a.is_some() || b.is_some());
}
#[test]
fn channel_wrap_around() {
let (tx, rx) = bounded_channel::<u32, 4>();
for round in 0..3 {
for i in 0..4 {
tx.try_send(round * 4 + i).unwrap();
}
for i in 0..4 {
assert_eq!(rx.try_recv(), Some(round * 4 + i));
}
}
}
#[test]
fn channel_zero_capacity() {
let (tx, _rx) = bounded_channel::<u32, 0>();
assert!(tx.try_send(1).is_err());
}
#[test]
fn channel_drop_with_items() {
use core::sync::atomic::{AtomicU32, Ordering};
static DROP_COUNT: AtomicU32 = AtomicU32::new(0);
#[derive(Debug)]
struct Droppable(u32);
impl Drop for Droppable {
fn drop(&mut self) {
DROP_COUNT.fetch_add(1, Ordering::Relaxed);
}
}
DROP_COUNT.store(0, Ordering::Relaxed);
{
let (tx, _rx) = bounded_channel::<Droppable, 8>();
tx.try_send(Droppable(1)).unwrap();
tx.try_send(Droppable(2)).unwrap();
tx.try_send(Droppable(3)).unwrap();
}
assert_eq!(DROP_COUNT.load(Ordering::Relaxed), 3);
}
#[test]
fn channel_debug() {
let (tx, rx) = bounded_channel::<u32, 8>();
tx.try_send(1).unwrap();
let s = alloc::format!("{:?}", tx);
assert!(s.contains("Sender"));
let s = alloc::format!("{:?}", rx);
assert!(s.contains("Receiver"));
}
#[test]
fn full_into_inner() {
let f = Full(42u32);
assert_eq!(f.into_inner(), 42);
}
}