Skip to main content

cpu_local/
identity.rs

1/// Dense logical index assigned to one CPU-local area.
2#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
3#[repr(transparent)]
4pub struct CpuIndex(u32);
5
6impl CpuIndex {
7    /// Reserved value used by an unbound CPU-area header.
8    pub const INVALID_RAW: u32 = u32::MAX;
9
10    /// Creates an index from its validated representation.
11    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    /// Returns the integer representation used at ABI boundaries.
20    pub const fn as_u32(self) -> u32 {
21        self.0
22    }
23
24    /// Returns this index as a Rust collection index.
25    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/// Error returned when a logical CPU index does not fit the supported range.
40#[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    /// Returns the rejected index.
48    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}