use std::fmt;
#[cfg(feature = "trace")]
use tracing::trace;
use crate::bus::EventBus;
use crate::error::EventBusError;
use crate::types::SubscriptionId;
#[derive(Clone)]
#[must_use = "dropping the Subscription leaves the listener registered; call .unsubscribe() or .into_guard() or store the handle"]
pub struct Subscription {
id: SubscriptionId,
name: Option<&'static str>,
bus: EventBus,
}
impl Subscription {
pub(crate) fn new(id: SubscriptionId, name: Option<&'static str>, bus: EventBus) -> Self {
Self { id, name, bus }
}
pub const fn id(&self) -> SubscriptionId {
self.id
}
pub const fn name(&self) -> Option<&'static str> {
self.name
}
pub async fn unsubscribe(self) -> Result<bool, EventBusError> {
self.bus.unsubscribe(self.id).await
}
pub fn into_guard(self) -> SubscriptionGuard {
SubscriptionGuard::new(self.id, self.name, self.bus)
}
}
impl fmt::Debug for Subscription {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Subscription").field("id", &self.id).field("name", &self.name).finish()
}
}
#[must_use = "dropping the SubscriptionGuard immediately will unsubscribe the listener"]
pub struct SubscriptionGuard {
inner: Option<GuardInner>,
}
struct GuardInner {
subscription_id: SubscriptionId,
name: Option<&'static str>,
bus: EventBus,
}
impl SubscriptionGuard {
fn new(subscription_id: SubscriptionId, name: Option<&'static str>, bus: EventBus) -> Self {
Self {
inner: Some(GuardInner { subscription_id, name, bus }),
}
}
pub fn id(&self) -> Option<SubscriptionId> {
self.inner.as_ref().map(|i| i.subscription_id)
}
pub fn name(&self) -> Option<&'static str> {
self.inner.as_ref().and_then(|i| i.name)
}
pub fn disarm(&mut self) {
self.inner.take();
}
}
impl Drop for SubscriptionGuard {
fn drop(&mut self) {
if let Some(inner) = self.inner.take() {
#[cfg(feature = "trace")]
trace!(subscription_id = inner.subscription_id.as_u64(), "subscription_guard.drop.unsubscribe");
if inner.bus.try_unsubscribe_best_effort(inner.subscription_id) {
return;
}
let bus = inner.bus;
let subscription_id = inner.subscription_id;
tokio::spawn(async move {
let _ = bus.unsubscribe(subscription_id).await;
});
}
}
}
impl fmt::Debug for SubscriptionGuard {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SubscriptionGuard")
.field("id", &self.inner.as_ref().map(|i| i.subscription_id))
.field("name", &self.inner.as_ref().and_then(|i| i.name))
.finish()
}
}