use std::borrow::Cow;
use std::marker::PhantomPinned;
use std::ops::Deref;
use std::pin::Pin;
use crate::{Metric, MetricEntry};
use parking_lot::{const_rwlock, RwLock, RwLockReadGuard};
pub(crate) struct DynMetricsRegistry {
metrics: Vec<MetricEntry>,
}
impl DynMetricsRegistry {
const fn new() -> Self {
Self {
metrics: Vec::new(),
}
}
fn register(&mut self, entry: MetricEntry) {
self.metrics.push(entry);
}
fn unregister(&mut self, metric: *const dyn Metric) {
self.metrics
.retain(|x| x.metric.0 as *const () != metric as *const ());
}
pub(crate) fn metrics(&self) -> &[MetricEntry] {
&self.metrics
}
}
static REGISTRY: RwLock<DynMetricsRegistry> = const_rwlock(DynMetricsRegistry::new());
pub(crate) fn get_registry() -> RwLockReadGuard<'static, DynMetricsRegistry> {
REGISTRY.read()
}
pub fn register(entry: MetricEntry) {
REGISTRY.write().register(entry);
}
pub fn unregister(metric: *const dyn Metric) {
REGISTRY.write().unregister(metric);
}
pub struct DynPinnedMetric<M: Metric> {
metric: M,
_marker: PhantomPinned,
}
impl<M: Metric> DynPinnedMetric<M> {
pub fn new(metric: M) -> Self {
Self {
metric,
_marker: PhantomPinned,
}
}
pub fn register(self: Pin<&Self>, name: impl Into<Cow<'static, str>>) {
unsafe { register(MetricEntry::new_unchecked(&self.metric, name.into())) };
}
}
impl<M: Metric> Drop for DynPinnedMetric<M> {
fn drop(&mut self) {
unregister(&self.metric);
}
}
impl<M: Metric> Deref for DynPinnedMetric<M> {
type Target = M;
#[inline]
fn deref(&self) -> &Self::Target {
&self.metric
}
}
pub struct DynBoxedMetric<M: Metric> {
metric: Pin<Box<DynPinnedMetric<M>>>,
}
impl<M: Metric> DynBoxedMetric<M> {
pub fn new(metric: M, name: impl Into<Cow<'static, str>>) -> Self {
let this = Self::unregistered(metric);
this.register(name.into());
this
}
pub fn unregistered(metric: M) -> Self {
Self {
metric: Box::pin(DynPinnedMetric::new(metric)),
}
}
pub fn register(&self, name: impl Into<Cow<'static, str>>) {
self.metric.as_ref().register(name.into())
}
}
impl<M: Metric> Deref for DynBoxedMetric<M> {
type Target = M;
#[inline]
fn deref(&self) -> &Self::Target {
&*self.metric
}
}