1use std::fmt;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11#[repr(u8)]
12pub enum HandleKind {
13 Agent = 1,
14 Region = 2,
15 MemoryPool = 3,
16 Signal = 4,
17 Queue = 5,
18}
19
20impl HandleKind {
21 pub fn from_u8(value: u8) -> Option<Self> {
22 match value {
23 1 => Some(Self::Agent),
24 2 => Some(Self::Region),
25 3 => Some(Self::MemoryPool),
26 4 => Some(Self::Signal),
27 5 => Some(Self::Queue),
28 _ => None,
29 }
30 }
31
32 pub fn as_str(self) -> &'static str {
33 match self {
34 Self::Agent => "agent",
35 Self::Region => "region",
36 Self::MemoryPool => "memory_pool",
37 Self::Signal => "signal",
38 Self::Queue => "queue",
39 }
40 }
41}
42
43#[derive(Clone, Copy, PartialEq, Eq, Hash)]
45pub struct PackedHandle(u64);
46
47impl PackedHandle {
48 pub const INVALID: Self = Self(0);
49
50 pub fn pack(kind: HandleKind, generation: u32, index: u32) -> Self {
51 let generation = generation & 0x00FF_FFFF;
52 let value =
53 (u64::from(kind as u8) << 56) | (u64::from(generation) << 32) | u64::from(index);
54 Self(value)
55 }
56
57 pub fn from_raw(raw: u64) -> Self {
58 Self(raw)
59 }
60
61 pub fn raw(self) -> u64 {
62 self.0
63 }
64
65 pub fn is_invalid(self) -> bool {
66 self.0 == 0
67 }
68
69 pub fn kind(self) -> Option<HandleKind> {
70 HandleKind::from_u8((self.0 >> 56) as u8)
71 }
72
73 pub fn generation(self) -> u32 {
74 ((self.0 >> 32) & 0x00FF_FFFF) as u32
75 }
76
77 pub fn index(self) -> u32 {
78 self.0 as u32
79 }
80}
81
82impl fmt::Debug for PackedHandle {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 match self.kind() {
85 Some(kind) => write!(
86 f,
87 "PackedHandle {{ kind: {}, gen: {}, index: {}, raw: {:#x} }}",
88 kind.as_str(),
89 self.generation(),
90 self.index(),
91 self.0
92 ),
93 None => write!(f, "PackedHandle {{ invalid_or_unknown: {:#x} }}", self.0),
94 }
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn pack_round_trip() {
104 let h = PackedHandle::pack(HandleKind::Agent, 7, 3);
105 assert_eq!(h.kind(), Some(HandleKind::Agent));
106 assert_eq!(h.generation(), 7);
107 assert_eq!(h.index(), 3);
108 assert_eq!(PackedHandle::from_raw(h.raw()), h);
109 }
110
111 #[test]
112 fn all_kinds_round_trip() {
113 for kind in [
114 HandleKind::Agent,
115 HandleKind::Region,
116 HandleKind::MemoryPool,
117 HandleKind::Signal,
118 HandleKind::Queue,
119 ] {
120 let h = PackedHandle::pack(kind, 1, 2);
121 assert_eq!(h.kind(), Some(kind));
122 }
123 }
124
125 #[test]
126 fn generation_is_masked_to_24_bits() {
127 let h = PackedHandle::pack(HandleKind::Agent, 0x01FF_FFFF, 1);
128 assert_eq!(h.generation(), 0x00FF_FFFF);
129 }
130
131 #[test]
132 fn zero_is_invalid() {
133 assert!(PackedHandle::INVALID.is_invalid());
134 assert!(PackedHandle::from_raw(0).kind().is_none());
135 }
136}