use super::range_authority::MemoryManagerIdRange;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(try_from = "SlotEncoding", into = "SlotEncoding")]
pub struct MemoryManagerSlot(u8);
impl MemoryManagerSlot {
pub const fn new(id: u8) -> Result<Self, MemoryManagerSlotError> {
match validate_memory_manager_id(id) {
Ok(()) => Ok(Self(id)),
Err(error) => Err(error),
}
}
#[must_use]
pub const fn id(&self) -> u8 {
self.0
}
}
#[derive(Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
struct SlotEncoding {
slot: SlotIdEncoding,
}
#[derive(Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
enum SlotIdEncoding {
MemoryManagerId(u8),
}
impl From<MemoryManagerSlot> for SlotEncoding {
fn from(slot: MemoryManagerSlot) -> Self {
Self {
slot: SlotIdEncoding::MemoryManagerId(slot.id()),
}
}
}
impl TryFrom<SlotEncoding> for MemoryManagerSlot {
type Error = MemoryManagerSlotError;
fn try_from(encoded: SlotEncoding) -> Result<Self, Self::Error> {
let SlotIdEncoding::MemoryManagerId(id) = encoded.slot;
Self::new(id)
}
}
pub const LEDGER_SLOT: MemoryManagerSlot = match MemoryManagerSlot::new(MEMORY_MANAGER_LEDGER_ID) {
Ok(slot) => slot,
Err(_) => panic!("the ledger ID must be usable"),
};
pub const MEMORY_MANAGER_MIN_ID: u8 = 0;
pub const MEMORY_MANAGER_MAX_ID: u8 = 254;
pub const MEMORY_MANAGER_INVALID_ID: u8 = u8::MAX;
pub const IC_MEMORY_STABLE_KEY_PREFIX: &str = "ic_memory.";
pub const IC_MEMORY_AUTHORITY_OWNER: &str = "ic-memory";
pub const IC_MEMORY_AUTHORITY_PURPOSE: &str = "ic-memory allocation-governance authority";
pub const IC_MEMORY_LEDGER_STABLE_KEY: &str = "ic_memory.ledger.v1";
pub const IC_MEMORY_LEDGER_LABEL: &str = "MemoryLayoutLedger";
pub const MEMORY_MANAGER_LEDGER_ID: u8 = MEMORY_MANAGER_MIN_ID;
pub const MEMORY_MANAGER_GOVERNANCE_MAX_ID: u8 = 9;
#[must_use]
pub fn is_ic_memory_stable_key(stable_key: &str) -> bool {
stable_key.starts_with(IC_MEMORY_STABLE_KEY_PREFIX)
}
#[must_use]
pub const fn memory_manager_governance_range() -> MemoryManagerIdRange {
const RANGE: MemoryManagerIdRange =
match MemoryManagerIdRange::new(MEMORY_MANAGER_MIN_ID, MEMORY_MANAGER_GOVERNANCE_MAX_ID) {
Ok(range) => range,
Err(_) => panic!("the governance range must be usable"),
};
RANGE
}
#[non_exhaustive]
#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
pub enum MemoryManagerSlotError {
#[error("MemoryManager ID {id} is not a usable allocation slot")]
InvalidMemoryManagerId {
id: u8,
},
}
pub const fn validate_memory_manager_id(id: u8) -> Result<(), MemoryManagerSlotError> {
if id == MEMORY_MANAGER_INVALID_ID {
return Err(MemoryManagerSlotError::InvalidMemoryManagerId { id });
}
Ok(())
}