use super::LedgerIntegrityError;
use crate::{declaration::AllocationDeclaration, key::StableKey, slot::MemoryManagerSlot};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct AllocationLedger {
pub(crate) current_generation: u64,
#[serde(deserialize_with = "crate::cbor::deserialize_records")]
pub(crate) records: Vec<AllocationRecord>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct AllocationRecord {
pub(crate) stable_key: StableKey,
pub(crate) slot: MemoryManagerSlot,
pub(crate) state: AllocationState,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub enum AllocationState {
Reserved,
Active,
Retired,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RecoveredLedger {
ledger: AllocationLedger,
}
impl RecoveredLedger {
pub(crate) fn genesis_for_absent_snapshot(error: &super::LedgerCommitError) -> Option<Self> {
matches!(
error,
super::LedgerCommitError::Recovery(crate::CommitRecoveryError::NoValidGeneration)
)
.then(|| Self::from_trusted_ledger(AllocationLedger::empty_genesis()))
}
pub(crate) const fn from_trusted_ledger(ledger: AllocationLedger) -> Self {
Self { ledger }
}
#[must_use]
pub const fn ledger(&self) -> &AllocationLedger {
&self.ledger
}
#[must_use]
pub const fn current_generation(&self) -> u64 {
self.ledger.current_generation
}
pub(crate) fn into_ledger(self) -> AllocationLedger {
self.ledger
}
}
impl AllocationRecord {
pub(crate) fn from_declaration(
declaration: &AllocationDeclaration,
state: AllocationState,
) -> Self {
Self {
stable_key: declaration.stable_key.clone(),
slot: declaration.slot.clone(),
state,
}
}
pub(crate) fn active(declaration: &AllocationDeclaration) -> Self {
Self::from_declaration(declaration, AllocationState::Active)
}
#[cfg(test)]
pub(crate) fn reserved(declaration: &AllocationDeclaration) -> Self {
Self::from_declaration(declaration, AllocationState::Reserved)
}
#[must_use]
pub const fn stable_key(&self) -> &StableKey {
&self.stable_key
}
#[must_use]
pub const fn slot(&self) -> &MemoryManagerSlot {
&self.slot
}
#[must_use]
pub const fn state(&self) -> AllocationState {
self.state
}
}
impl AllocationLedger {
pub(crate) const fn empty_genesis() -> Self {
Self {
current_generation: 0,
records: Vec::new(),
}
}
pub fn new(
current_generation: u64,
records: Vec<AllocationRecord>,
) -> Result<Self, LedgerIntegrityError> {
let ledger = Self {
current_generation,
records,
};
ledger.validate_integrity()?;
Ok(ledger)
}
#[must_use]
pub const fn current_generation(&self) -> u64 {
self.current_generation
}
#[must_use]
pub fn records(&self) -> &[AllocationRecord] {
&self.records
}
pub(crate) fn occupied_slots(&self) -> [bool; crate::constants::MAX_ALLOCATIONS] {
let mut occupied = [false; crate::constants::MAX_ALLOCATIONS];
for record in &self.records {
occupied[usize::from(record.slot.id())] = true;
}
occupied
}
}