use crate::common::StaticTypeMap;
use tokio::sync::mpsc::{error::SendError, Sender, UnboundedSender};
mod subscription;
#[cfg(test)]
mod test;
pub use subscription::*;
static CHANNELS: StaticTypeMap = StaticTypeMap::new();
pub trait Notification: Sized + 'static {
const BUFFER_SIZE: usize;
const DEBUG_NAME: &'static str;
type Payload: Send;
}
#[non_exhaustive]
pub enum NotifyError<N: Notification> {
NotSubscribed(N::Payload),
SendError(N::Payload),
}
pub async fn notify<N: Notification>(payload: N::Payload) -> Result<(), NotifyError<N>> {
let id = id!(N);
let channels = CHANNELS.read().await;
let sender = match channels.get(&id) {
Some(sender) => sender,
None => return Err(NotifyError::NotSubscribed(payload)),
};
if N::BUFFER_SIZE == 0 {
let sender: &UnboundedSender<_> = unsafe { sender.get_ref() };
sender.send(payload)?
} else {
let sender: &Sender<_> = unsafe { sender.get_ref() };
sender.send(payload).await?
}
Ok(())
}
impl<N: Notification> From<SendError<N::Payload>> for NotifyError<N> {
fn from(e: SendError<N::Payload>) -> Self {
NotifyError::SendError(e.0)
}
}
impl<N: Notification> std::fmt::Debug for NotifyError<N> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NotifyError::NotSubscribed(_) => {
write!(f, "NotifyError in {}: NotSubscribed", N::DEBUG_NAME)?;
}
NotifyError::SendError(_) => {
write!(f, "NotifyError in {}: SendError", N::DEBUG_NAME)?;
}
}
Ok(())
}
}