use super::{
ChannelReceiveAccess, ChannelReceiveFuture, ChannelSendError, CloseStatus,
RecvPollState, RecvWaitQueueEntry,
};
use crate::{
intrusive_double_linked_list::{LinkedList, ListNode},
utils::update_waker_ref,
NoopLock,
};
use core::marker::PhantomData;
use futures_core::task::{Context, Poll};
use lock_api::{Mutex, RawMutex};
fn wake_waiters(waiters: &mut LinkedList<RecvWaitQueueEntry>) {
waiters.reverse_drain(|waiter| {
if let Some(handle) = waiter.task.take() {
handle.wake();
}
waiter.state = RecvPollState::Unregistered;
});
}
struct ChannelState<T> {
is_fulfilled: bool,
value: Option<T>,
waiters: LinkedList<RecvWaitQueueEntry>,
}
impl<T> ChannelState<T>
where
T: Clone,
{
fn new() -> ChannelState<T> {
ChannelState::<T> {
is_fulfilled: false,
value: None,
waiters: LinkedList::new(),
}
}
fn send(&mut self, value: T) -> Result<(), ChannelSendError<T>> {
if self.is_fulfilled {
return Err(ChannelSendError(value));
}
self.value = Some(value);
self.is_fulfilled = true;
wake_waiters(&mut self.waiters);
Ok(())
}
fn close(&mut self) -> CloseStatus {
if self.is_fulfilled {
return CloseStatus::AlreadyClosed;
}
self.is_fulfilled = true;
wake_waiters(&mut self.waiters);
CloseStatus::NewlyClosed
}
unsafe fn try_receive(
&mut self,
wait_node: &mut ListNode<RecvWaitQueueEntry>,
cx: &mut Context<'_>,
) -> Poll<Option<T>> {
match wait_node.state {
RecvPollState::Unregistered => {
match &self.value {
Some(v) => {
Poll::Ready(Some(v.clone()))
}
None => {
if self.is_fulfilled {
Poll::Ready(None)
} else {
wait_node.task = Some(cx.waker().clone());
wait_node.state = RecvPollState::Registered;
self.waiters.add_front(wait_node);
Poll::Pending
}
}
}
}
RecvPollState::Registered => {
update_waker_ref(&mut wait_node.task, cx);
Poll::Pending
}
RecvPollState::Notified => {
unreachable!("Not possible for Oneshot Broadcast");
}
}
}
fn remove_waiter(&mut self, wait_node: &mut ListNode<RecvWaitQueueEntry>) {
if let RecvPollState::Registered = wait_node.state {
if !unsafe { self.waiters.remove(wait_node) } {
panic!("Future could not be removed from wait queue");
}
wait_node.state = RecvPollState::Unregistered;
}
}
}
pub struct GenericOneshotBroadcastChannel<MutexType: RawMutex, T> {
inner: Mutex<MutexType, ChannelState<T>>,
}
unsafe impl<MutexType: RawMutex + Send, T: Send> Send
for GenericOneshotBroadcastChannel<MutexType, T>
{
}
unsafe impl<MutexType: RawMutex + Sync, T: Send> Sync
for GenericOneshotBroadcastChannel<MutexType, T>
{
}
impl<MutexType: RawMutex, T> core::fmt::Debug
for GenericOneshotBroadcastChannel<MutexType, T>
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("GenericOneshotBroadcastChannel").finish()
}
}
impl<MutexType: RawMutex, T> GenericOneshotBroadcastChannel<MutexType, T>
where
T: Clone,
{
pub fn new() -> GenericOneshotBroadcastChannel<MutexType, T> {
GenericOneshotBroadcastChannel {
inner: Mutex::new(ChannelState::new()),
}
}
pub fn send(&self, value: T) -> Result<(), ChannelSendError<T>> {
self.inner.lock().send(value)
}
pub fn close(&self) -> CloseStatus {
self.inner.lock().close()
}
pub fn receive(&self) -> ChannelReceiveFuture<MutexType, T> {
ChannelReceiveFuture {
channel: Some(self),
wait_node: ListNode::new(RecvWaitQueueEntry::new()),
_phantom: PhantomData,
}
}
}
impl<MutexType: RawMutex, T> ChannelReceiveAccess<T>
for GenericOneshotBroadcastChannel<MutexType, T>
where
T: Clone,
{
unsafe fn receive_or_register(
&self,
wait_node: &mut ListNode<RecvWaitQueueEntry>,
cx: &mut Context<'_>,
) -> Poll<Option<T>> {
self.inner.lock().try_receive(wait_node, cx)
}
fn remove_receive_waiter(
&self,
wait_node: &mut ListNode<RecvWaitQueueEntry>,
) {
self.inner.lock().remove_waiter(wait_node)
}
}
pub type LocalOneshotBroadcastChannel<T> =
GenericOneshotBroadcastChannel<NoopLock, T>;
#[cfg(feature = "std")]
mod if_std {
use super::*;
pub type OneshotBroadcastChannel<T> =
GenericOneshotBroadcastChannel<parking_lot::RawMutex, T>;
}
#[cfg(feature = "std")]
pub use self::if_std::*;
#[cfg(feature = "alloc")]
mod if_alloc {
use super::*;
pub mod shared {
use super::*;
use crate::channel::shared::ChannelReceiveFuture;
struct GenericOneshotChannelSharedState<MutexType, T>
where
MutexType: RawMutex,
T: 'static,
{
channel: GenericOneshotBroadcastChannel<MutexType, T>,
}
impl<MutexType, T> ChannelReceiveAccess<T>
for GenericOneshotChannelSharedState<MutexType, T>
where
MutexType: RawMutex,
T: Clone,
{
unsafe fn receive_or_register(
&self,
wait_node: &mut ListNode<RecvWaitQueueEntry>,
cx: &mut Context<'_>,
) -> Poll<Option<T>> {
self.channel.receive_or_register(wait_node, cx)
}
fn remove_receive_waiter(
&self,
wait_node: &mut ListNode<RecvWaitQueueEntry>,
) {
self.channel.remove_receive_waiter(wait_node)
}
}
pub struct GenericOneshotBroadcastSender<MutexType, T>
where
MutexType: RawMutex,
T: Clone + 'static,
{
inner: alloc::sync::Arc<
GenericOneshotChannelSharedState<MutexType, T>,
>,
}
pub struct GenericOneshotBroadcastReceiver<MutexType, T>
where
MutexType: RawMutex,
T: Clone + 'static,
{
inner: alloc::sync::Arc<
GenericOneshotChannelSharedState<MutexType, T>,
>,
}
impl<MutexType, T> Clone for GenericOneshotBroadcastReceiver<MutexType, T>
where
MutexType: RawMutex,
T: Clone + 'static,
{
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl<MutexType, T> core::fmt::Debug
for GenericOneshotBroadcastSender<MutexType, T>
where
MutexType: RawMutex,
T: Clone,
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("OneshotBroadcastSender").finish()
}
}
impl<MutexType, T> core::fmt::Debug
for GenericOneshotBroadcastReceiver<MutexType, T>
where
MutexType: RawMutex,
T: Clone,
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("OneshotBroadcastReceiver").finish()
}
}
impl<MutexType, T> Drop for GenericOneshotBroadcastSender<MutexType, T>
where
MutexType: RawMutex,
T: Clone,
{
fn drop(&mut self) {
self.inner.channel.close();
}
}
impl<MutexType, T> Drop for GenericOneshotBroadcastReceiver<MutexType, T>
where
MutexType: RawMutex,
T: Clone,
{
fn drop(&mut self) {
self.inner.channel.close();
}
}
pub fn generic_oneshot_broadcast_channel<MutexType, T>() -> (
GenericOneshotBroadcastSender<MutexType, T>,
GenericOneshotBroadcastReceiver<MutexType, T>,
)
where
MutexType: RawMutex,
T: Send + Clone,
{
let inner =
alloc::sync::Arc::new(GenericOneshotChannelSharedState {
channel: GenericOneshotBroadcastChannel::new(),
});
let sender = GenericOneshotBroadcastSender {
inner: inner.clone(),
};
let receiver = GenericOneshotBroadcastReceiver { inner };
(sender, receiver)
}
impl<MutexType, T> GenericOneshotBroadcastSender<MutexType, T>
where
MutexType: RawMutex + 'static,
T: Clone,
{
pub fn send(&self, value: T) -> Result<(), ChannelSendError<T>> {
self.inner.channel.send(value)
}
}
impl<MutexType, T> GenericOneshotBroadcastReceiver<MutexType, T>
where
MutexType: RawMutex + 'static,
T: Clone,
{
pub fn receive(&self) -> ChannelReceiveFuture<MutexType, T> {
ChannelReceiveFuture {
channel: Some(self.inner.clone()),
wait_node: ListNode::new(RecvWaitQueueEntry::new()),
_phantom: PhantomData,
}
}
}
#[cfg(feature = "std")]
mod if_std {
use super::*;
pub type OneshotBroadcastSender<T> =
GenericOneshotBroadcastSender<parking_lot::RawMutex, T>;
pub type OneshotBroadcastReceiver<T> =
GenericOneshotBroadcastReceiver<parking_lot::RawMutex, T>;
pub fn oneshot_broadcast_channel<T>(
) -> (OneshotBroadcastSender<T>, OneshotBroadcastReceiver<T>)
where
T: Send + Clone,
{
generic_oneshot_broadcast_channel::<parking_lot::RawMutex, T>()
}
}
#[cfg(feature = "std")]
pub use self::if_std::*;
}
}
#[cfg(feature = "alloc")]
pub use self::if_alloc::*;