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}