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}