#![cfg_attr(not(test), no_std)]
use core::{
future::Future,
marker::PhantomPinned,
pin::Pin,
ptr::null_mut,
sync::atomic::{AtomicPtr, Ordering},
task::{Context, Poll, Waker},
};
use heapless::spsc::{Consumer, Producer, Queue};
pub struct Channel<T: Sync + 'static, const N: usize> {
queue: Queue<T, N>,
waker: AtomicPtr<Waker>,
}
impl<T: Send + Sync + 'static, const N: usize> Channel<T, N> {
pub const fn new() -> Self {
Self {
queue: Queue::new(),
waker: AtomicPtr::new(null_mut()),
}
}
pub fn split(&mut self) -> (SendHalf<'_, T, N>, ReceiveHalf<'_, T, N>) {
let (producer, consumer) = self.queue.split();
let waker = &self.waker;
(
SendHalf { producer, waker },
ReceiveHalf { consumer, waker },
)
}
}
pub struct SendHalf<'a, T: 'static, const N: usize> {
producer: Producer<'a, T, N>,
waker: &'a AtomicPtr<Waker>,
}
impl<'a, T: 'static, const N: usize> SendHalf<'a, T, N> {
pub fn try_send(&mut self, packet: T) -> Result<(), SendError> {
self.producer.enqueue(packet).map_err(|_| SendError::Full)?;
if let Some(waker) = unsafe { self.waker.load(Ordering::Acquire).as_ref() } {
waker.wake_by_ref();
}
Ok(())
}
}
pub struct ReceiveHalf<'a, T: Send + 'static, const N: usize> {
consumer: Consumer<'a, T, N>,
waker: &'a AtomicPtr<Waker>,
}
impl<'a, T: Send + 'static, const N: usize> ReceiveHalf<'a, T, N> {
pub fn receive(&mut self) -> impl Future<Output = T> + Send + '_ {
struct ReceiveFuture<'a, 'b, T: Send + 'static, const N: usize> {
receive: &'a mut ReceiveHalf<'b, T, N>,
waker: Option<Waker>,
_phantom: PhantomPinned,
}
impl<'a, 'b, T: Send + 'static, const N: usize> Drop for ReceiveFuture<'a, 'b, T, N> {
fn drop(&mut self) {
self.receive.waker.store(null_mut(), Ordering::Release);
}
}
impl<'a, 'b, T: Send + 'static, const N: usize> Future for ReceiveFuture<'a, 'b, T, N> {
type Output = T;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let self_mut = unsafe { self.get_unchecked_mut() };
if let Some(value) = self_mut.receive.try_receive() {
Poll::Ready(value)
} else {
if self_mut.waker.is_none() {
let waker = self_mut.waker.get_or_insert(cx.waker().clone());
self_mut.receive.waker.store(waker, Ordering::Release);
}
Poll::Pending
}
}
}
ReceiveFuture {
receive: self,
waker: None,
_phantom: PhantomPinned,
}
}
pub fn try_receive(&mut self) -> Option<T> {
self.consumer.dequeue()
}
}
#[derive(Debug)]
pub enum SendError {
Full,
}
#[cfg(test)]
#[tokio::test]
async fn simple() {
let mut ch: Channel<u32, 4> = Channel::new();
let (mut tx, mut rx) = ch.split();
assert!(matches!(tx.try_send(0), Ok(())));
assert!(matches!(tx.try_send(1), Ok(())));
assert!(matches!(tx.try_send(2), Ok(())));
assert!(matches!(tx.try_send(3), Err(SendError::Full)));
assert_eq!(rx.receive().await, 0);
assert_eq!(rx.receive().await, 1);
assert_eq!(rx.receive().await, 2);
assert!(matches!(rx.try_receive(), None));
}