Skip to main content

ic_memory/slot/
id_range.rs

1use super::memory_manager::{
2    MEMORY_MANAGER_INVALID_ID, MEMORY_MANAGER_MAX_ID, MEMORY_MANAGER_MIN_ID,
3};
4use serde::{Deserialize, Deserializer, Serialize, de::Error as _};
5
6///
7/// MemoryManagerIdRange
8///
9/// Inclusive range of usable `MemoryManager` virtual memory IDs.
10/// Construction and deserialization reject reversed bounds and sentinel ID 255.
11///
12
13#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
14pub struct MemoryManagerIdRange {
15    start: u8,
16    end: u8,
17}
18
19impl<'de> Deserialize<'de> for MemoryManagerIdRange {
20    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
21        #[derive(Deserialize)]
22        #[serde(rename = "MemoryManagerIdRange", deny_unknown_fields)]
23        struct Bounds {
24            start: u8,
25            end: u8,
26        }
27
28        let bounds = Bounds::deserialize(deserializer)?;
29        Self::new(bounds.start, bounds.end).map_err(D::Error::custom)
30    }
31}
32
33impl MemoryManagerIdRange {
34    /// Construct and validate an inclusive `MemoryManager` ID range.
35    pub const fn new(start: u8, end: u8) -> Result<Self, MemoryManagerRangeError> {
36        if start > end {
37            return Err(MemoryManagerRangeError::InvalidRange { start, end });
38        }
39        // Ordered bounds make a usable end sufficient to exclude the sentinel.
40        if end == MEMORY_MANAGER_INVALID_ID {
41            return Err(MemoryManagerRangeError::InvalidMemoryManagerId { id: end });
42        }
43        Ok(Self { start, end })
44    }
45
46    /// Return the full usable `MemoryManager` ID range.
47    #[must_use]
48    pub const fn all_usable() -> Self {
49        Self {
50            start: MEMORY_MANAGER_MIN_ID,
51            end: MEMORY_MANAGER_MAX_ID,
52        }
53    }
54
55    /// Return true when `id` is inside this inclusive range.
56    #[must_use]
57    pub const fn contains(&self, id: u8) -> bool {
58        id >= self.start && id <= self.end
59    }
60
61    /// First usable ID in the range.
62    #[must_use]
63    pub const fn start(&self) -> u8 {
64        self.start
65    }
66
67    /// Last usable ID in the range.
68    #[must_use]
69    pub const fn end(&self) -> u8 {
70        self.end
71    }
72}
73
74///
75/// MemoryManagerRangeError
76///
77/// Invalid `MemoryManager` virtual memory ID range.
78#[non_exhaustive]
79#[derive(Clone, Copy, Debug, Eq, thiserror::Error, PartialEq)]
80pub enum MemoryManagerRangeError {
81    /// Range bounds are reversed.
82    #[error("MemoryManager ID range is invalid: start={start} end={end}")]
83    InvalidRange {
84        /// Requested first ID.
85        start: u8,
86        /// Requested last ID.
87        end: u8,
88    },
89    /// ID 255 is the unallocated-bucket sentinel.
90    #[error("MemoryManager ID {id} is not a usable allocation slot")]
91    InvalidMemoryManagerId {
92        /// Invalid MemoryManager ID.
93        id: u8,
94    },
95}