Skip to main content

chaud_hot/func/
storage.rs

1use super::{AtomicFnPtr, ErasedFnPtr, Func};
2use core::marker::PhantomData;
3
4/// Stores the necessary runtime information about a hot-reloadable function.
5#[repr(transparent)]
6pub struct FuncStorage<F: Func> {
7    _pd: PhantomData<F>,
8    /// # Safety
9    ///
10    /// See the [module][super#safety] docs:
11    ///
12    /// * The actual type must never change.
13    /// * The contained actual type must be `F::Ptr`.
14    inner: AtomicFnPtr,
15}
16
17impl<F: Func> FuncStorage<F> {
18    #[must_use]
19    #[expect(clippy::new_without_default, reason = "default would be unused")]
20    pub const fn new() -> Self {
21        let inner = AtomicFnPtr::new(ErasedFnPtr::erase::<F>(F::actual));
22
23        // SAFETY: Initializing does not count as a change, and the actual type
24        // requirements are enforced or need to be upheld by the caller.
25        Self { _pd: PhantomData, inner }
26    }
27
28    #[inline]
29    #[must_use]
30    pub fn get(&'static self) -> F::Ptr {
31        let erased = self.inner.load_relaxed();
32
33        // SAFETY: `inner`'s actual type is `F::Ptr`.
34        unsafe { erased.typed::<F::Ptr>() }
35    }
36
37    pub fn update(&'static self) {
38        let erased = ErasedFnPtr::erase::<F>(F::actual);
39
40        // SAFETY: `inner`'s actual type is `F::Ptr`.
41        unsafe { self.inner.store_relaxed(erased) };
42
43        log::debug!("Updated {:?} to {:?}", F::NAME, erased);
44    }
45}