1#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
3#[repr(transparent)]
4pub struct CpuIndex(u32);
5
6impl CpuIndex {
7 pub const INVALID_RAW: u32 = u32::MAX;
9
10 pub const fn from_u32(index: u32) -> Option<Self> {
12 if index == Self::INVALID_RAW {
13 None
14 } else {
15 Some(Self(index))
16 }
17 }
18
19 pub const fn as_u32(self) -> u32 {
21 self.0
22 }
23
24 pub const fn as_usize(self) -> usize {
26 self.0 as usize
27 }
28}
29
30impl TryFrom<usize> for CpuIndex {
31 type Error = CpuIndexError;
32
33 fn try_from(index: usize) -> Result<Self, Self::Error> {
34 let raw = u32::try_from(index).map_err(|_| CpuIndexError { index })?;
35 Self::from_u32(raw).ok_or(CpuIndexError { index })
36 }
37}
38
39#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
41#[error("CPU index {index} exceeds the CPU-local index range")]
42pub struct CpuIndexError {
43 index: usize,
44}
45
46impl CpuIndexError {
47 pub const fn index(self) -> usize {
49 self.index
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn cpu_index_reserves_the_invalid_header_value() {
59 assert_eq!(CpuIndex::try_from(7).unwrap().as_u32(), 7);
60 assert!(CpuIndex::from_u32(CpuIndex::INVALID_RAW).is_none());
61 }
62}