Skip to main content

ic_memory/slot/
memory_manager.rs

1use super::id_range::MemoryManagerIdRange;
2use serde::{Deserialize, Serialize};
3
4///
5/// MemoryManagerSlot
6///
7/// A usable physical `ic-stable-structures::MemoryManager` allocation ID.
8///
9/// Construction and deserialization reject the unallocated-bucket sentinel
10/// (255), so reading the ID is infallible. A slot is an identity, not authority
11/// to open memory; that still requires committed allocation validation.
12///
13/// Serde encodes the numeric ID directly. Decoding uses the same checked
14/// constructor, so serialized DTOs cannot introduce the sentinel.
15///
16
17#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
18#[serde(try_from = "u8", into = "u8")]
19pub struct MemoryManagerSlot(u8);
20
21impl MemoryManagerSlot {
22    /// Construct a slot, rejecting ID 255.
23    pub const fn new(id: u8) -> Result<Self, MemoryManagerSlotError> {
24        match validate_memory_manager_id(id) {
25            Ok(()) => Ok(Self(id)),
26            Err(error) => Err(error),
27        }
28    }
29
30    /// Return the usable virtual memory ID.
31    #[must_use]
32    pub const fn id(&self) -> u8 {
33        self.0
34    }
35}
36
37impl From<MemoryManagerSlot> for u8 {
38    fn from(slot: MemoryManagerSlot) -> Self {
39        slot.id()
40    }
41}
42
43impl TryFrom<u8> for MemoryManagerSlot {
44    type Error = MemoryManagerSlotError;
45
46    fn try_from(id: u8) -> Result<Self, Self::Error> {
47        Self::new(id)
48    }
49}
50
51pub const LEDGER_SLOT: MemoryManagerSlot = match MemoryManagerSlot::new(MEMORY_MANAGER_LEDGER_ID) {
52    Ok(slot) => slot,
53    Err(_) => panic!("the ledger ID must be usable"),
54};
55
56/// First usable `MemoryManager` virtual memory ID.
57pub const MEMORY_MANAGER_MIN_ID: u8 = 0;
58
59/// Last usable `MemoryManager` virtual memory ID.
60pub const MEMORY_MANAGER_MAX_ID: u8 = 254;
61
62/// `MemoryManager` unallocated-bucket sentinel. This is not a usable slot.
63pub const MEMORY_MANAGER_INVALID_ID: u8 = u8::MAX;
64
65/// Stable-key namespace prefix reserved for `ic-memory` allocation-governance infrastructure.
66pub const IC_MEMORY_STABLE_KEY_PREFIX: &str = "ic_memory.";
67
68/// Diagnostic owner label for `ic-memory` allocation-governance infrastructure.
69pub const IC_MEMORY_AUTHORITY_OWNER: &str = "ic-memory";
70
71/// Stable key of the allocation ledger when backed by the current MemoryManager substrate.
72pub const IC_MEMORY_LEDGER_STABLE_KEY: &str = "ic_memory.ledger.v1";
73
74/// MemoryManager ID used by the allocation ledger in the current MemoryManager substrate.
75pub const MEMORY_MANAGER_LEDGER_ID: u8 = MEMORY_MANAGER_MIN_ID;
76
77/// Last MemoryManager ID reserved for `ic-memory` governance in the current substrate.
78pub const MEMORY_MANAGER_GOVERNANCE_MAX_ID: u8 = 9;
79
80/// Return true when `stable_key` belongs to the `ic-memory` namespace.
81#[must_use]
82pub fn is_ic_memory_stable_key(stable_key: &str) -> bool {
83    stable_key.starts_with(IC_MEMORY_STABLE_KEY_PREFIX)
84}
85
86/// MemoryManager range reserved for `ic-memory` governance in the current substrate.
87#[must_use]
88pub const fn memory_manager_governance_range() -> MemoryManagerIdRange {
89    const RANGE: MemoryManagerIdRange =
90        match MemoryManagerIdRange::new(MEMORY_MANAGER_MIN_ID, MEMORY_MANAGER_GOVERNANCE_MAX_ID) {
91            Ok(range) => range,
92            Err(_) => panic!("the governance range must be usable"),
93        };
94    RANGE
95}
96
97///
98/// MemoryManagerSlotError
99///
100/// Invalid `MemoryManager` allocation ID.
101///
102
103#[non_exhaustive]
104#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
105pub enum MemoryManagerSlotError {
106    /// ID 255 is the unallocated-bucket sentinel.
107    #[error("MemoryManager ID {id} is not a usable allocation slot")]
108    InvalidMemoryManagerId {
109        /// Invalid MemoryManager ID.
110        id: u8,
111    },
112}
113
114/// Validate that a `MemoryManager` ID is usable as an allocation slot.
115pub const fn validate_memory_manager_id(id: u8) -> Result<(), MemoryManagerSlotError> {
116    if id == MEMORY_MANAGER_INVALID_ID {
117        return Err(MemoryManagerSlotError::InvalidMemoryManagerId { id });
118    }
119    Ok(())
120}