use std::any::{
TypeId,
type_name,
};
use std::fmt::{
self,
Display,
Formatter,
};
use std::hash::{
Hash,
Hasher,
};
use std::marker::PhantomData;
use crate::{
EventBusError,
EventBusResult,
TopicKey,
};
#[derive(Debug)]
pub struct Topic<T: 'static> {
name: String,
payload_type_id: TypeId,
payload_type_name: &'static str,
marker: PhantomData<fn() -> T>,
}
impl<T: 'static> Topic<T> {
pub fn try_new(name: impl Into<String>) -> EventBusResult<Self> {
let name = name.into();
if name.trim().is_empty() {
return Err(EventBusError::invalid_argument(
"name",
"topic name must not be blank",
));
}
Ok(Self {
name,
payload_type_id: TypeId::of::<T>(),
payload_type_name: type_name::<T>(),
marker: PhantomData,
})
}
pub fn name(&self) -> &str {
&self.name
}
pub fn payload_type_id(&self) -> TypeId {
self.payload_type_id
}
pub fn payload_type_name(&self) -> &'static str {
self.payload_type_name
}
pub fn key(&self) -> TopicKey {
TopicKey::new(self.name.clone(), self.payload_type_id)
}
}
impl<T: 'static> Clone for Topic<T> {
fn clone(&self) -> Self {
Self {
name: self.name.clone(),
payload_type_id: self.payload_type_id,
payload_type_name: self.payload_type_name,
marker: PhantomData,
}
}
}
impl<T: 'static> PartialEq for Topic<T> {
fn eq(&self, other: &Self) -> bool {
self.name == other.name && self.payload_type_id == other.payload_type_id
}
}
impl<T: 'static> Eq for Topic<T> {}
impl<T: 'static> Hash for Topic<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state);
self.payload_type_id.hash(state);
}
}
impl<T: 'static> Display for Topic<T> {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
write!(formatter, "{}.{}", self.payload_type_name, self.name)
}
}