Skip to main content

crux_core/effects/registry/
effect_id.rs

1use std::marker::PhantomData;
2
3// The id is a generational id, first 32 bits are the generation
4// the second 32 are the index itself. That way we get to reuse
5// the slots in the registry slab and still recognise a stale
6// id if we are given one.
7
8const INDEX_BITS: u32 = 32;
9const INDEX_MASK: u64 = u32::MAX as u64;
10
11/// Opaque ID for a parked effect request.
12///
13/// The raw value packs a slab index and generation into a single integer so
14/// callers can pass it over custom FFI boundaries without learning the storage
15/// layout.
16#[derive(Debug, PartialEq, Eq, Hash)]
17pub struct EffectId<T = ()> {
18    pub(crate) raw: u64,
19    pub(crate) phantom: PhantomData<fn(T) -> T>,
20}
21
22impl<T> Clone for EffectId<T> {
23    fn clone(&self) -> Self {
24        *self
25    }
26}
27
28impl<T> Copy for EffectId<T> {}
29
30impl<T> EffectId<T> {
31    /// Reconstruct an `EffectId` from its raw integer representation.
32    ///
33    /// Use this on the resolve path to turn an id received back from a custom
34    /// FFI (as a plain integer) into a typed `EffectId`. The `raw` value must be
35    /// one previously produced by [`EffectId::into_raw`]; arbitrary integers may
36    /// refer to no request, or to a stale slot.
37    #[must_use]
38    pub const fn from_raw(raw: u64) -> Self {
39        Self {
40            raw,
41            phantom: PhantomData,
42        }
43    }
44
45    /// Unpack the id into its raw integer representation for passing across a
46    /// custom FFI boundary.
47    ///
48    /// The returned value packs both the slab index and the generation, and can
49    /// be turned back into an `EffectId` with [`EffectId::from_raw`].
50    #[must_use]
51    pub const fn into_raw(self) -> u64 {
52        self.raw
53    }
54
55    pub(crate) fn new(index: usize, generation: u32) -> Self {
56        let index = u32::try_from(index).expect("ParkedEffectId index overflow");
57        Self::from_raw((u64::from(generation) << INDEX_BITS) | u64::from(index))
58    }
59
60    pub(crate) const fn index(self) -> usize {
61        (self.raw & INDEX_MASK) as usize
62    }
63
64    pub(crate) const fn generation(self) -> u32 {
65        (self.raw >> INDEX_BITS) as u32
66    }
67}