use crate::stdlib::{
fmt,
hash::{Hash, Hasher},
sync::Mutex,
vec::Vec,
};
use crate::{
dispatcher::{self, Dispatch},
metadata::{LevelFilter, Metadata},
subscriber::Interest,
};
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 interests = self
.dispatchers
.iter()
.filter_map(|registrar| registrar.try_register(meta));
let interest = if let Some(interest) = interests.next() {
interests.fold(interest, Interest::and)
} else {
Interest::never()
};
callsite.set_interest(interest)
}
fn rebuild_interest(&mut self) {
let mut max_level = LevelFilter::OFF;
self.dispatchers.retain(|registrar| {
if let Some(dispatch) = registrar.upgrade() {
let level_hint = dispatch.max_level_hint().unwrap_or(LevelFilter::TRACE);
if level_hint > max_level {
max_level = level_hint;
}
true
} else {
false
}
});
self.callsites.iter().for_each(|&callsite| {
self.rebuild_callsite_interest(callsite);
});
LevelFilter::set_max(max_level);
}
}
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 {
self.0 as *const _ as *const () == other.0 as *const _ as *const ()
}
}
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)
}
}