Skip to main content

ic_memory/
capability.rs

1use crate::{declaration::AllocationDeclaration, key::StableKey, slot::MemoryManagerSlot};
2use std::sync::Arc;
3
4// Typed capability callers and the runtime's validated borrowed input share
5// one lookup. Comparing text needs no temporary owned StableKey or second index.
6pub fn declaration_for_key<'a>(
7    declarations: &'a [AllocationDeclaration],
8    key: &str,
9) -> Option<&'a AllocationDeclaration> {
10    declarations
11        .iter()
12        .find(|declaration| declaration.stable_key.as_str() == key)
13}
14
15///
16/// CommittedAllocations
17///
18/// Allocation-open capability confirmed after the validated ledger generation
19/// was persisted.
20///
21/// This type is not serializable, default-constructible, or publicly
22/// constructible. [`crate::MemoryRuntime`] publishes it only after its
23/// stable-cell write succeeds; callers cannot manually confirm persistence.
24///
25/// Its immutable declarations have validated keys, slots and diagnostic
26/// metadata, with unique keys and slots. Consumers may rely on those invariants
27/// without rebuilding uniqueness sets. The capability does not validate live
28/// store bytes, application schemas, journals or lifecycle readiness.
29///
30
31#[derive(Clone, Debug, Eq, PartialEq)]
32pub struct CommittedAllocations {
33    declarations: Arc<Vec<AllocationDeclaration>>,
34    generation: u64,
35}
36
37impl CommittedAllocations {
38    pub(crate) fn from_persisted(
39        mut declarations: Vec<AllocationDeclaration>,
40        generation: u64,
41    ) -> Self {
42        // Governance remains durable ownership, never application-open authority.
43        declarations
44            .retain(|declaration| !crate::is_ic_memory_stable_key(declaration.stable_key.as_str()));
45        Self {
46            declarations: Arc::new(declarations),
47            generation,
48        }
49    }
50
51    /// Return the persisted ledger generation that grants this capability.
52    #[must_use]
53    pub const fn generation(&self) -> u64 {
54        self.generation
55    }
56
57    /// Borrow the committed allocation declarations.
58    #[must_use]
59    pub fn declarations(&self) -> &[AllocationDeclaration] {
60        &self.declarations
61    }
62
63    /// Find a committed slot by stable key.
64    #[must_use]
65    pub fn slot_for(&self, key: &StableKey) -> Option<&MemoryManagerSlot> {
66        declaration_for_key(self.declarations(), key.as_str()).map(AllocationDeclaration::slot)
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn persistence_confirmation_publishes_shared_application_authority() {
76        let declarations = vec![
77            AllocationDeclaration::memory_manager(crate::IC_MEMORY_LEDGER_STABLE_KEY, 0).unwrap(),
78            AllocationDeclaration::memory_manager("app.rows.v1", 100).unwrap(),
79        ];
80        let committed = CommittedAllocations::from_persisted(declarations, 2);
81        let shared = committed.clone();
82
83        assert_eq!(committed.declarations().len(), 1);
84        assert_eq!(shared, committed);
85        assert!(std::ptr::eq(
86            shared.declarations(),
87            committed.declarations()
88        ));
89        assert_eq!(
90            committed.declarations()[0].stable_key().as_str(),
91            "app.rows.v1"
92        );
93        assert_eq!(committed.generation(), 2);
94        assert_eq!(
95            committed
96                .slot_for(&StableKey::parse("app.rows.v1").unwrap())
97                .unwrap()
98                .id(),
99            100
100        );
101        assert!(
102            committed
103                .slot_for(&StableKey::parse(crate::IC_MEMORY_LEDGER_STABLE_KEY).unwrap())
104                .is_none()
105        );
106    }
107}