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    /// Return the usable `MemoryManager` virtual memory ID represented by this descriptor.
76    ///
77    /// This validates substrate, descriptor version, slot kind, and sentinel ID
78    /// rules before returning the numeric ID.
79    pub fn memory_manager_id(&self) -> Result<u8, MemoryManagerSlotError> {
80        if self.substrate != MEMORY_MANAGER_SUBSTRATE {
81            return Err(MemoryManagerSlotError::UnsupportedSubstrate {
82                substrate: self.substrate.clone(),
83            });
84        }
85        if self.descriptor_version != MEMORY_MANAGER_DESCRIPTOR_VERSION {
86            return Err(MemoryManagerSlotError::UnsupportedDescriptorVersion {
87                version: self.descriptor_version,
88            });
89        }
90
91        let AllocationSlot::MemoryManagerId(id) = self.slot else {
92            return Err(MemoryManagerSlotError::UnsupportedSlot);
93        };
94
95        validate_memory_manager_id(id)?;
96        Ok(id)
97    }
98}
99
100///
101/// MemoryManagerSlotError
102///
103/// Invalid or unsupported `MemoryManager` allocation slot descriptor.
104#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
105pub enum MemoryManagerSlotError {
106    /// Descriptor is not a `MemoryManagerId` slot.
107    #[error("allocation slot is not a MemoryManager virtual memory ID")]
108    UnsupportedSlot,
109    /// Descriptor is attached to another substrate.
110    #[error("allocation slot substrate '{substrate}' is not supported as a MemoryManager slot")]
111    UnsupportedSubstrate {
112        /// Unsupported substrate identifier.
113        substrate: String,
114    },
115    /// Descriptor uses an unsupported encoding version.
116    #[error("MemoryManager slot descriptor version {version} is unsupported")]
117    UnsupportedDescriptorVersion {
118        /// Unsupported descriptor version.
119        version: u32,
120    },
121    /// ID 255 is the unallocated-bucket sentinel.
122    #[error("MemoryManager ID {id} is not a usable allocation slot")]
123    InvalidMemoryManagerId {
124        /// Invalid MemoryManager ID.
125        id: u8,
126    },
127}
128
129/// Validate that a `MemoryManager` ID is usable as an allocation slot.
130pub const fn validate_memory_manager_id(id: u8) -> Result<(), MemoryManagerSlotError> {
131    if id == MEMORY_MANAGER_INVALID_ID {
132        return Err(MemoryManagerSlotError::InvalidMemoryManagerId { id });
133    }
134    Ok(())
135}