extern crate alloc;
use crate::alloc::{SyncVec, SyncVecError};
use crate::sync_types::{self, Lock as _, WeakSyncRcPtr as _};
use core::{convert, marker, mem, num, ops, sync, task};
use ops::Deref as _;
use sync::atomic;
#[derive(Clone, Copy, Debug)]
pub enum BroadcastWakerError {
MemoryAllocationFailure,
}
impl convert::From<SyncVecError> for BroadcastWakerError {
fn from(value: SyncVecError) -> Self {
match value {
SyncVecError::MemoryAllocationFailure => BroadcastWakerError::MemoryAllocationFailure,
}
}
}
pub struct BroadcastWakerSubscriptions<ST: sync_types::SyncTypes> {
state: ST::Lock<BroadcastWakerSubscriptionsState>,
wake_gen: atomic::AtomicU64,
}
impl<ST: sync_types::SyncTypes> BroadcastWakerSubscriptions<ST> {
pub fn new() -> Self {
Self {
state: ST::Lock::from(BroadcastWakerSubscriptionsState {
subscribers: SyncVec::new(),
last_subscription_id: 0,
}),
wake_gen: atomic::AtomicU64::new(0),
}
}
pub fn subscribe(&self) -> Result<BroadcastWakerSubscriptionId, BroadcastWakerError> {
let mut state_guard = self.state.lock();
state_guard.last_subscription_id += 1;
let subscription_id = num::NonZeroU64::new(state_guard.last_subscription_id).unwrap();
let subscribers_lock =
sync_types::LockForInner::<'_, _, _, BroadcastWakerSubscriptionsStateDerefInnerSubscribersTag>::from_outer(
&self.state,
);
let mut subscribers_guard = sync_types::LockForInnerGuard::<
'_,
_,
_,
BroadcastWakerSubscriptionsStateDerefInnerSubscribersTag,
>::from_outer(state_guard);
let result;
(subscribers_guard, result) = SyncVec::try_reserve_exact(&subscribers_lock, subscribers_guard, 1);
if let Err(e) = result {
return Err(BroadcastWakerError::from(e));
}
subscribers_guard.push((subscription_id, None));
Ok(BroadcastWakerSubscriptionId { subscription_id })
}
pub fn unsubscribe(
&self,
subscription_id: BroadcastWakerSubscriptionId,
wake_remaining: bool,
) -> Option<Option<task::Waker>> {
let mut state_guard = self.state.lock();
let removed_waker = match state_guard
.subscribers
.iter()
.position(|(entry_subscription_id, _)| subscription_id.subscription_id == *entry_subscription_id)
{
Some(index) => Some(state_guard.subscribers.remove(index).1),
None => None,
};
if wake_remaining {
self.wake_impl(&state_guard);
}
removed_waker
}
pub fn set_subscription_waker(&self, subscription_id: BroadcastWakerSubscriptionId, waker: task::Waker) {
let mut state_guard = self.state.lock();
if let Some(subscription_entry) = state_guard
.subscribers
.iter_mut()
.find(|(entry_subscription_id, _)| subscription_id.subscription_id == *entry_subscription_id)
{
subscription_entry.1 = Some(waker);
}
}
pub fn wake_gen(&self) -> u64 {
atomic::fence(atomic::Ordering::Acquire);
self.wake_gen.load(atomic::Ordering::Acquire)
}
pub fn waker<'a, SP: 'a + sync_types::SyncRcPtr<Self>, SR: sync_types::SyncRcPtrRef<'a, Self, SP>>(
this: &SR,
) -> task::Waker {
let raw_waker = broadcast_raw_waker_new(this);
unsafe { task::Waker::from_raw(raw_waker) }
}
fn wake(&self) {
self.wake_impl(&self.state.lock());
}
fn wake_impl(&self, state: &BroadcastWakerSubscriptionsState) {
self.wake_gen.fetch_add(1, atomic::Ordering::Release);
atomic::fence(atomic::Ordering::Release);
for subscriber in state.subscribers.iter() {
if let Some(waker) = subscriber.1.as_ref() {
waker.wake_by_ref()
}
}
}
}
impl<ST: sync_types::SyncTypes> Default for BroadcastWakerSubscriptions<ST> {
fn default() -> Self {
Self::new()
}
}
struct BroadcastWakerSubscriptionsState {
subscribers: SyncVec<(num::NonZeroU64, Option<task::Waker>)>,
last_subscription_id: u64,
}
struct BroadcastWakerSubscriptionsStateDerefInnerSubscribersTag;
impl sync_types::DerefInnerByTag<BroadcastWakerSubscriptionsStateDerefInnerSubscribersTag>
for BroadcastWakerSubscriptionsState
{
crate::impl_deref_inner_by_tag!(subscribers, SyncVec<(num::NonZeroU64, Option<task::Waker>)>);
}
impl sync_types::DerefMutInnerByTag<BroadcastWakerSubscriptionsStateDerefInnerSubscribersTag>
for BroadcastWakerSubscriptionsState
{
crate::impl_deref_mut_inner_by_tag!(subscribers);
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct BroadcastWakerSubscriptionId {
subscription_id: num::NonZeroU64,
}
struct BroadcastRawWakerVTable<ST: sync_types::SyncTypes, SP: sync_types::SyncRcPtr<BroadcastWakerSubscriptions<ST>>> {
_phantom: marker::PhantomData<fn() -> (*const ST, *const SP)>,
}
impl<ST: sync_types::SyncTypes, SP: sync_types::SyncRcPtr<BroadcastWakerSubscriptions<ST>>>
BroadcastRawWakerVTable<ST, SP>
{
const RAW_WAKER_VTABLE: task::RawWakerVTable = task::RawWakerVTable::new(
broadcast_raw_waker_clone::<ST, SP>,
broadcast_raw_waker_wake::<ST, SP>,
broadcast_raw_waker_wake_by_ref::<ST, SP>,
broadcast_raw_waker_drop::<ST, SP>,
);
}
fn broadcast_raw_waker_new<
'a,
ST: sync_types::SyncTypes,
SP: 'a + sync_types::SyncRcPtr<BroadcastWakerSubscriptions<ST>>,
SR: sync_types::SyncRcPtrRef<'a, BroadcastWakerSubscriptions<ST>, SP>,
>(
subscriptions: &SR,
) -> task::RawWaker {
let subscriptions = subscriptions.make_weak_clone();
let data: *const BroadcastWakerSubscriptions<ST> = SP::WeakSyncRcPtr::into_raw(subscriptions);
task::RawWaker::new(data as *const (), &BroadcastRawWakerVTable::<ST, SP>::RAW_WAKER_VTABLE)
}
unsafe fn broadcast_raw_waker_clone<
ST: sync_types::SyncTypes,
SP: sync_types::SyncRcPtr<BroadcastWakerSubscriptions<ST>>,
>(
data: *const (),
) -> task::RawWaker {
let data = data as *const BroadcastWakerSubscriptions<ST>;
let subscriptions = mem::ManuallyDrop::new(unsafe { SP::WeakSyncRcPtr::from_raw(data) });
let data: *const BroadcastWakerSubscriptions<ST> = SP::WeakSyncRcPtr::into_raw(subscriptions.deref().clone());
task::RawWaker::new(data as *const (), &BroadcastRawWakerVTable::<ST, SP>::RAW_WAKER_VTABLE)
}
unsafe fn broadcast_raw_waker_drop<
ST: sync_types::SyncTypes,
SP: sync_types::SyncRcPtr<BroadcastWakerSubscriptions<ST>>,
>(
data: *const (),
) {
let data = data as *const BroadcastWakerSubscriptions<ST>;
let subscriptions = unsafe { SP::WeakSyncRcPtr::from_raw(data) };
drop(subscriptions)
}
unsafe fn broadcast_raw_waker_wake<
ST: sync_types::SyncTypes,
SP: sync_types::SyncRcPtr<BroadcastWakerSubscriptions<ST>>,
>(
data: *const (),
) {
let data = data as *const BroadcastWakerSubscriptions<ST>;
let subscriptions = unsafe { SP::WeakSyncRcPtr::from_raw(data) };
if let Some(subscriptions) = subscriptions.upgrade() {
subscriptions.deref().wake();
}
}
unsafe fn broadcast_raw_waker_wake_by_ref<
ST: sync_types::SyncTypes,
SP: sync_types::SyncRcPtr<BroadcastWakerSubscriptions<ST>>,
>(
data: *const (),
) {
let data = data as *const BroadcastWakerSubscriptions<ST>;
let subscriptions = mem::ManuallyDrop::new(unsafe { SP::WeakSyncRcPtr::from_raw(data) });
if let Some(subscriptions) = subscriptions.upgrade() {
subscriptions.deref().wake();
}
}