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, with unique keys and slots. Consumers may rely on those invariants
26/// without rebuilding uniqueness sets. The capability does not validate live
27/// store bytes, application schemas, journals or lifecycle readiness.
28///
29
30#[derive(Clone, Debug, Eq, PartialEq)]
31pub struct CommittedAllocations {
32    declarations: Arc<Vec<AllocationDeclaration>>,
33    generation: u64,
34}
35
36impl CommittedAllocations {
37    pub(crate) fn from_persisted(
38        mut declarations: Vec<AllocationDeclaration>,
39        generation: u64,
40    ) -> Self {
41        // Governance remains durable ownership, never application-open authority.
42        declarations
43            .retain(|declaration| !crate::is_ic_memory_stable_key(declaration.stable_key.as_str()));
44        Self {
45            declarations: Arc::new(declarations),
46            generation,
47        }
48    }
49
50    /// Return the persisted ledger generation that grants this capability.
51    #[must_use]
52    pub const fn generation(&self) -> u64 {
53        self.generation
54    }
55
56    /// Borrow the committed allocation declarations.
57    #[must_use]
58    pub fn declarations(&self) -> &[AllocationDeclaration] {
59        &self.declarations
60    }
61
62    /// Find a committed slot by stable key.
63    #[must_use]
64    pub fn slot_for(&self, key: &StableKey) -> Option<&MemoryManagerSlot> {
65        declaration_for_key(self.declarations(), key.as_str()).map(AllocationDeclaration::slot)
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn persistence_confirmation_publishes_shared_application_authority() {
75        let declarations = vec![
76            AllocationDeclaration::memory_manager(crate::IC_MEMORY_LEDGER_STABLE_KEY, 0).unwrap(),
77            AllocationDeclaration::memory_manager("app.rows.v1", 100).unwrap(),
78        ];
79        let committed = CommittedAllocations::from_persisted(declarations, 2);
80        let shared = committed.clone();
81
82        assert_eq!(committed.declarations().len(), 1);
83        assert_eq!(shared, committed);
84        assert!(std::ptr::eq(
85            shared.declarations(),
86            committed.declarations()
87        ));
88        assert_eq!(
89            committed.declarations()[0].stable_key().as_str(),
90            "app.rows.v1"
91        );
92        assert_eq!(committed.generation(), 2);
93        assert_eq!(
94            committed
95                .slot_for(&StableKey::parse("app.rows.v1").unwrap())
96                .unwrap()
97                .id(),
98            100
99        );
100        assert!(
101            committed
102                .slot_for(&StableKey::parse(crate::IC_MEMORY_LEDGER_STABLE_KEY).unwrap())
103                .is_none()
104        );
105    }
106}