Skip to main content

nm/
publish_model.rs

1use std::panic::{RefUnwindSafe, UnwindSafe};
2use std::rc::Rc;
3use std::sync::Arc;
4
5#[cfg(test)]
6use crate::ObservationBagSnapshot;
7use crate::{Magnitude, ObservationBag, ObservationBagSync, Observations, Sealed};
8
9/// Defines how the metrics related to an event are published for reporting purposes.
10///
11/// For more information, refer to either the [crate-level documentation][crate] or the
12/// documentation of [`Event`][crate::Event].
13///
14/// This trait is sealed and can only be implemented in the `nm` crate.
15#[expect(private_bounds, reason = "intentionally sealed trait")]
16pub trait PublishModel: PublishModelPrivate + Sealed {}
17
18/// Privately accessible functionality expected from implementations of `PublishModel`.
19pub(crate) trait PublishModelPrivate {
20    /// Records `count` observations of the given `magnitude` for the event.
21    fn insert(&self, magnitude: Magnitude, count: usize);
22
23    /// Takes a snapshot of the recorded observations for this event.
24    #[cfg(test)]
25    fn snapshot(&self) -> ObservationBagSnapshot;
26}
27
28/// A publishing model that requires the owner of the event to explicitly publish
29/// the event's metrics.
30///
31/// The owner must call [`MetricsPusher::push()`][1] on the metrics pusher associated with the
32/// event at creation time.
33///
34/// [1]: crate::MetricsPusher::push
35#[derive(Debug)]
36pub struct Push {
37    pub(crate) observations: Rc<ObservationBag>,
38}
39
40// Push is single-threaded (!Send, !Sync) and uses interior mutability only for
41// metrics tracking. Inconsistent state after a caught panic cannot affect safety.
42impl UnwindSafe for Push {}
43impl RefUnwindSafe for Push {}
44
45impl Sealed for Push {}
46impl PublishModel for Push {}
47impl PublishModelPrivate for Push {
48    #[cfg(test)]
49    fn snapshot(&self) -> ObservationBagSnapshot {
50        self.observations.snapshot()
51    }
52
53    fn insert(&self, magnitude: Magnitude, count: usize) {
54        self.observations.insert(magnitude, count);
55    }
56}
57
58/// A publishing model that requires no action from the owner of an event.
59///
60/// Data is automatically pulled from the event when a report is generated.
61#[derive(Debug)]
62pub struct Pull {
63    // While an event is a single-threaded type, we need to use an Arc here because the
64    // observations may still be read (without locking) from other threads.
65    pub(crate) observations: Arc<ObservationBagSync>,
66}
67
68impl Sealed for Pull {}
69impl PublishModel for Pull {}
70impl PublishModelPrivate for Pull {
71    #[cfg(test)]
72    fn snapshot(&self) -> ObservationBagSnapshot {
73        self.observations.snapshot()
74    }
75
76    fn insert(&self, magnitude: Magnitude, count: usize) {
77        self.observations.insert(magnitude, count);
78    }
79}
80
81#[cfg(test)]
82#[cfg_attr(coverage_nightly, coverage(off))]
83mod tests {
84    use std::panic::{RefUnwindSafe, UnwindSafe};
85
86    use static_assertions::assert_impl_all;
87
88    use super::*;
89
90    assert_impl_all!(Push: UnwindSafe, RefUnwindSafe);
91    assert_impl_all!(Pull: UnwindSafe, RefUnwindSafe);
92}