use crate::{
dispatcher::{self, Dispatch, Registrar},
subscriber::Interest,
Metadata,
};
use std::{
fmt,
hash::{Hash, Hasher},
ptr,
sync::Mutex,
};
lazy_static! {
static ref REGISTRY: Mutex<Registry> = Mutex::new(Registry {
callsites: Vec::new(),
dispatchers: Vec::new(),
});
}
struct Registry {
callsites: Vec<&'static dyn Callsite>,
dispatchers: Vec<dispatcher::Registrar>,
}
impl Registry {
fn rebuild_callsite_interest(&self, callsite: &'static dyn Callsite) {
let meta = callsite.metadata();
let mut interest = Interest::never();
for registrar in &self.dispatchers {
if let Some(sub_interest) = registrar.try_register(meta) {
interest = interest.and(sub_interest);
}
}
callsite.set_interest(interest)
}
fn rebuild_interest(&mut self) {
self.dispatchers.retain(Registrar::is_alive);
self.callsites.iter().for_each(|&callsite| {
self.rebuild_callsite_interest(callsite);
});
}
}
pub trait Callsite: Sync {
fn set_interest(&self, interest: Interest);
fn metadata(&self) -> &Metadata;
}
#[derive(Clone)]
pub struct Identifier(
#[doc(hidden)]
pub &'static dyn Callsite,
);
pub fn rebuild_interest_cache() {
let mut registry = REGISTRY.lock().unwrap();
registry.rebuild_interest();
}
pub fn register(callsite: &'static dyn Callsite) {
let mut registry = REGISTRY.lock().unwrap();
registry.rebuild_callsite_interest(callsite);
registry.callsites.push(callsite);
}
pub(crate) fn register_dispatch(dispatch: &Dispatch) {
let mut registry = REGISTRY.lock().unwrap();
registry.dispatchers.push(dispatch.registrar());
registry.rebuild_interest();
}
impl PartialEq for Identifier {
fn eq(&self, other: &Identifier) -> bool {
ptr::eq(self.0, other.0)
}
}
impl Eq for Identifier {}
impl fmt::Debug for Identifier {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Identifier({:p})", self.0)
}
}
impl Hash for Identifier {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
(self.0 as *const dyn Callsite).hash(state)
}
}