metrics/recorder/cell.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
use super::{Recorder, SetRecorderError};
use std::{
cell::UnsafeCell,
sync::atomic::{AtomicUsize, Ordering},
};
/// The recorder is uninitialized.
const UNINITIALIZED: usize = 0;
/// The recorder is currently being initialized.
const INITIALIZING: usize = 1;
/// The recorder has been initialized successfully and can be read.
const INITIALIZED: usize = 2;
/// An specialized version of `OnceCell` for `Recorder`.
pub struct RecorderOnceCell {
recorder: UnsafeCell<Option<&'static dyn Recorder>>,
state: AtomicUsize,
}
impl RecorderOnceCell {
/// Creates an uninitialized `RecorderOnceCell`.
pub const fn new() -> Self {
Self { recorder: UnsafeCell::new(None), state: AtomicUsize::new(UNINITIALIZED) }
}
pub fn set<R>(&self, recorder: R) -> Result<(), SetRecorderError<R>>
where
R: Recorder + 'static,
{
// Try and transition the cell from `UNINITIALIZED` to `INITIALIZING`, which would give
// us exclusive access to set the recorder.
match self.state.compare_exchange(
UNINITIALIZED,
INITIALIZING,
Ordering::Acquire,
Ordering::Relaxed,
) {
Ok(UNINITIALIZED) => {
unsafe {
// SAFETY: Access is unique because we can only be here if we won the race
// to transition from `UNINITIALIZED` to `INITIALIZING` above.
self.recorder.get().write(Some(Box::leak(Box::new(recorder))));
}
// Mark the recorder as initialized, which will make it visible to readers.
self.state.store(INITIALIZED, Ordering::Release);
Ok(())
}
_ => Err(SetRecorderError(recorder)),
}
}
pub fn try_load(&self) -> Option<&'static dyn Recorder> {
if self.state.load(Ordering::Acquire) != INITIALIZED {
None
} else {
// SAFETY: If the state is `INITIALIZED`, then we know that the recorder has been
// installed and is safe to read.
unsafe { self.recorder.get().read() }
}
}
}
// SAFETY: We can only mutate through `set`, which is protected by the `state` and unsafe
// function where the caller has to guarantee synced-ness.
unsafe impl Send for RecorderOnceCell {}
unsafe impl Sync for RecorderOnceCell {}