Skip to main content

ic_memory/slot/
memory_manager.rs

1use super::range_authority::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/// The private serde representation describes the current durable slot encoding.
14/// It preserves that encoding independently of this checked in-memory type.
15///
16
17#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
18#[serde(try_from = "SlotEncoding", into = "SlotEncoding")]
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
37// Passive codec fields only: the current format nests the MemoryManagerId tag
38// inside a slot field. These values never enter allocation policy or execution.
39#[derive(Deserialize, Serialize)]
40#[serde(deny_unknown_fields)]
41struct SlotEncoding {
42    slot: SlotIdEncoding,
43}
44
45#[derive(Deserialize, Serialize)]
46#[serde(deny_unknown_fields)]
47enum SlotIdEncoding {
48    MemoryManagerId(u8),
49}
50
51impl From<MemoryManagerSlot> for SlotEncoding {
52    fn from(slot: MemoryManagerSlot) -> Self {
53        Self {
54            slot: SlotIdEncoding::MemoryManagerId(slot.id()),
55        }
56    }
57}
58
59impl TryFrom<SlotEncoding> for MemoryManagerSlot {
60    type Error = MemoryManagerSlotError;
61
62    fn try_from(encoded: SlotEncoding) -> Result<Self, Self::Error> {
63        let SlotIdEncoding::MemoryManagerId(id) = encoded.slot;
64        Self::new(id)
65    }
66}
67
68pub const LEDGER_SLOT: MemoryManagerSlot = match MemoryManagerSlot::new(MEMORY_MANAGER_LEDGER_ID) {
69    Ok(slot) => slot,
70    Err(_) => panic!("the ledger ID must be usable"),
71};
72
73/// First usable `MemoryManager` virtual memory ID.
74pub const MEMORY_MANAGER_MIN_ID: u8 = 0;
75
76/// Last usable `MemoryManager` virtual memory ID.
77pub const MEMORY_MANAGER_MAX_ID: u8 = 254;
78
79/// `MemoryManager` unallocated-bucket sentinel. This is not a usable slot.
80pub const MEMORY_MANAGER_INVALID_ID: u8 = u8::MAX;
81
82/// Stable-key namespace prefix reserved for `ic-memory` allocation-governance infrastructure.
83pub const IC_MEMORY_STABLE_KEY_PREFIX: &str = "ic_memory.";
84
85/// Diagnostic owner label for `ic-memory` allocation-governance infrastructure.
86pub const IC_MEMORY_AUTHORITY_OWNER: &str = "ic-memory";
87
88/// Diagnostic purpose for the `ic-memory` allocation-governance authority range.
89pub const IC_MEMORY_AUTHORITY_PURPOSE: &str = "ic-memory allocation-governance authority";
90
91/// Stable key of the allocation ledger when backed by the current MemoryManager substrate.
92pub const IC_MEMORY_LEDGER_STABLE_KEY: &str = "ic_memory.ledger.v1";
93
94/// Diagnostic label of the allocation ledger when backed by the current MemoryManager substrate.
95pub const IC_MEMORY_LEDGER_LABEL: &str = "MemoryLayoutLedger";
96
97/// MemoryManager ID used by the allocation ledger in the current MemoryManager substrate.
98pub const MEMORY_MANAGER_LEDGER_ID: u8 = MEMORY_MANAGER_MIN_ID;
99
100/// Last MemoryManager ID reserved for `ic-memory` governance in the current substrate.
101pub const MEMORY_MANAGER_GOVERNANCE_MAX_ID: u8 = 9;
102
103/// Return true when `stable_key` belongs to the `ic-memory` namespace.
104#[must_use]
105pub fn is_ic_memory_stable_key(stable_key: &str) -> bool {
106    stable_key.starts_with(IC_MEMORY_STABLE_KEY_PREFIX)
107}
108
109/// MemoryManager range reserved for `ic-memory` governance in the current substrate.
110#[must_use]
111pub const fn memory_manager_governance_range() -> MemoryManagerIdRange {
112    const RANGE: MemoryManagerIdRange =
113        match MemoryManagerIdRange::new(MEMORY_MANAGER_MIN_ID, MEMORY_MANAGER_GOVERNANCE_MAX_ID) {
114            Ok(range) => range,
115            Err(_) => panic!("the governance range must be usable"),
116        };
117    RANGE
118}
119
120///
121/// MemoryManagerSlotError
122///
123/// Invalid `MemoryManager` allocation ID.
124///
125
126#[non_exhaustive]
127#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
128pub enum MemoryManagerSlotError {
129    /// ID 255 is the unallocated-bucket sentinel.
130    #[error("MemoryManager ID {id} is not a usable allocation slot")]
131    InvalidMemoryManagerId {
132        /// Invalid MemoryManager ID.
133        id: u8,
134    },
135}
136
137/// Validate that a `MemoryManager` ID is usable as an allocation slot.
138pub const fn validate_memory_manager_id(id: u8) -> Result<(), MemoryManagerSlotError> {
139    if id == MEMORY_MANAGER_INVALID_ID {
140        return Err(MemoryManagerSlotError::InvalidMemoryManagerId { id });
141    }
142    Ok(())
143}