Skip to main content

ic_memory/slot/
memory_manager.rs

1use super::descriptor::{AllocationSlot, AllocationSlotDescriptor};
2use super::range_authority::MemoryManagerIdRange;
3
4/// Substrate identifier for `ic-stable-structures::MemoryManager` slots.
5pub const MEMORY_MANAGER_SUBSTRATE: &str = "ic-stable-structures.memory_manager";
6
7/// Descriptor version for current `MemoryManagerId` slots.
8pub const MEMORY_MANAGER_DESCRIPTOR_VERSION: u32 = 1;
9
10/// First usable `MemoryManager` virtual memory ID.
11pub const MEMORY_MANAGER_MIN_ID: u8 = 0;
12
13/// Last usable `MemoryManager` virtual memory ID.
14pub const MEMORY_MANAGER_MAX_ID: u8 = 254;
15
16/// `MemoryManager` unallocated-bucket sentinel. This is not a usable slot.
17pub const MEMORY_MANAGER_INVALID_ID: u8 = u8::MAX;
18
19/// Stable-key namespace prefix reserved for `ic-memory` allocation-governance infrastructure.
20pub const IC_MEMORY_STABLE_KEY_PREFIX: &str = "ic_memory.";
21
22/// Diagnostic owner label for `ic-memory` allocation-governance infrastructure.
23pub const IC_MEMORY_AUTHORITY_OWNER: &str = "ic-memory";
24
25/// Diagnostic purpose for the `ic-memory` allocation-governance authority range.
26pub const IC_MEMORY_AUTHORITY_PURPOSE: &str = "ic-memory allocation-governance authority";
27
28/// Stable key of the allocation ledger when backed by the current MemoryManager substrate.
29pub const IC_MEMORY_LEDGER_STABLE_KEY: &str = "ic_memory.ledger.v1";
30
31/// Diagnostic label of the allocation ledger when backed by the current MemoryManager substrate.
32pub const IC_MEMORY_LEDGER_LABEL: &str = "MemoryLayoutLedger";
33
34/// MemoryManager ID used by the allocation ledger in the current MemoryManager substrate.
35pub const MEMORY_MANAGER_LEDGER_ID: u8 = MEMORY_MANAGER_MIN_ID;
36
37/// Last MemoryManager ID reserved for `ic-memory` governance in the current substrate.
38pub const MEMORY_MANAGER_GOVERNANCE_MAX_ID: u8 = 9;
39
40/// Return true when `stable_key` belongs to the `ic-memory` namespace.
41#[must_use]
42pub fn is_ic_memory_stable_key(stable_key: &str) -> bool {
43    stable_key.starts_with(IC_MEMORY_STABLE_KEY_PREFIX)
44}
45
46/// MemoryManager range reserved for `ic-memory` governance in the current substrate.
47#[must_use]
48pub const fn memory_manager_governance_range() -> MemoryManagerIdRange {
49    MemoryManagerIdRange {
50        start: MEMORY_MANAGER_MIN_ID,
51        end: MEMORY_MANAGER_GOVERNANCE_MAX_ID,
52    }
53}
54
55impl AllocationSlotDescriptor {
56    /// Construct a descriptor for a usable `MemoryManager` virtual memory ID.
57    ///
58    /// ID 255 is the `ic-stable-structures` unallocated-bucket sentinel and is
59    /// rejected.
60    pub fn memory_manager(id: u8) -> Result<Self, MemoryManagerSlotError> {
61        validate_memory_manager_id(id)?;
62        Ok(Self::memory_manager_unchecked(id))
63    }
64
65    /// Construct a descriptor for a `MemoryManager` virtual memory ID without validating it.
66    #[must_use]
67    pub(crate) fn memory_manager_unchecked(id: u8) -> Self {
68        Self {
69            slot: AllocationSlot::MemoryManagerId(id),
70            substrate: MEMORY_MANAGER_SUBSTRATE.to_string(),
71            descriptor_version: MEMORY_MANAGER_DESCRIPTOR_VERSION,
72        }
73    }
74
75    /// Construct a descriptor for a usable `MemoryManager` virtual memory ID.
76    ///
77    /// This is an explicit alias for [`AllocationSlotDescriptor::memory_manager`].
78    pub fn memory_manager_checked(id: u8) -> Result<Self, MemoryManagerSlotError> {
79        Self::memory_manager(id)
80    }
81
82    /// Return the usable `MemoryManager` virtual memory ID represented by this descriptor.
83    ///
84    /// This validates substrate, descriptor version, slot kind, and sentinel ID
85    /// rules before returning the numeric ID.
86    pub fn memory_manager_id(&self) -> Result<u8, MemoryManagerSlotError> {
87        if self.substrate != MEMORY_MANAGER_SUBSTRATE {
88            return Err(MemoryManagerSlotError::UnsupportedSubstrate {
89                substrate: self.substrate.clone(),
90            });
91        }
92        if self.descriptor_version != MEMORY_MANAGER_DESCRIPTOR_VERSION {
93            return Err(MemoryManagerSlotError::UnsupportedDescriptorVersion {
94                version: self.descriptor_version,
95            });
96        }
97
98        let AllocationSlot::MemoryManagerId(id) = self.slot else {
99            return Err(MemoryManagerSlotError::UnsupportedSlot);
100        };
101
102        validate_memory_manager_id(id)?;
103        Ok(id)
104    }
105}
106
107///
108/// MemoryManagerSlotError
109///
110/// Invalid or unsupported `MemoryManager` allocation slot descriptor.
111#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
112pub enum MemoryManagerSlotError {
113    /// Descriptor is not a `MemoryManagerId` slot.
114    #[error("allocation slot is not a MemoryManager virtual memory ID")]
115    UnsupportedSlot,
116    /// Descriptor is attached to another substrate.
117    #[error("allocation slot substrate '{substrate}' is not supported as a MemoryManager slot")]
118    UnsupportedSubstrate {
119        /// Unsupported substrate identifier.
120        substrate: String,
121    },
122    /// Descriptor uses an unsupported encoding version.
123    #[error("MemoryManager slot descriptor version {version} is unsupported")]
124    UnsupportedDescriptorVersion {
125        /// Unsupported descriptor version.
126        version: u32,
127    },
128    /// ID 255 is the unallocated-bucket sentinel.
129    #[error("MemoryManager ID {id} is not a usable allocation slot")]
130    InvalidMemoryManagerId {
131        /// Invalid MemoryManager ID.
132        id: u8,
133    },
134}
135
136/// Validate that a `MemoryManager` ID is usable as an allocation slot.
137pub const fn validate_memory_manager_id(id: u8) -> Result<(), MemoryManagerSlotError> {
138    if id == MEMORY_MANAGER_INVALID_ID {
139        return Err(MemoryManagerSlotError::InvalidMemoryManagerId { id });
140    }
141    Ok(())
142}