Skip to main content

ic_memory/
session.rs

1use crate::{
2    declaration::AllocationDeclaration, key::StableKey, slot::AllocationSlotDescriptor,
3    substrate::StorageSubstrate,
4};
5use std::sync::Arc;
6
7///
8/// ValidatedAllocations
9///
10/// Allocation declarations accepted by policy and historical ledger validation.
11///
12/// This value is produced by [`crate::validate_allocations`] and is the bridge
13/// between declaration validation and opening storage. It is not a durable
14/// ledger record; staging commits it into the next generation before an
15/// integration should expose memory handles.
16///
17/// This is an in-memory capability, not a serde DTO. It has no public
18/// constructor and should only be produced by validation or bootstrap paths.
19///
20
21#[derive(Clone, Debug, Eq, PartialEq)]
22pub struct ValidatedAllocations {
23    inner: Arc<ValidatedState>,
24    _private: (),
25}
26
27#[derive(Clone, Debug, Eq, PartialEq)]
28struct ValidatedState {
29    /// Committed generation that validated these allocations.
30    generation: u64,
31    /// Validated declarations.
32    declarations: Vec<AllocationDeclaration>,
33    /// Optional binary/runtime identity for generation diagnostics.
34    runtime_fingerprint: Option<String>,
35}
36
37impl ValidatedAllocations {
38    pub(crate) fn new(
39        generation: u64,
40        declarations: Vec<AllocationDeclaration>,
41        runtime_fingerprint: Option<String>,
42    ) -> Self {
43        Self {
44            inner: Arc::new(ValidatedState {
45                generation,
46                declarations,
47                runtime_fingerprint,
48            }),
49            _private: (),
50        }
51    }
52
53    pub(crate) fn with_generation(self, generation: u64) -> Self {
54        let mut state = (*self.inner).clone();
55        state.generation = generation;
56        Self {
57            inner: Arc::new(state),
58            _private: (),
59        }
60    }
61
62    /// Return the committed generation that validated these allocations.
63    #[must_use]
64    pub fn generation(&self) -> u64 {
65        self.inner.generation
66    }
67
68    /// Borrow the validated declarations.
69    #[must_use]
70    pub fn declarations(&self) -> &[AllocationDeclaration] {
71        &self.inner.declarations
72    }
73
74    /// Borrow the optional runtime fingerprint.
75    #[must_use]
76    pub fn runtime_fingerprint(&self) -> Option<&str> {
77        self.inner.runtime_fingerprint.as_deref()
78    }
79
80    /// Find a validated slot by stable key.
81    #[must_use]
82    pub fn slot_for(&self, key: &StableKey) -> Option<&AllocationSlotDescriptor> {
83        self.declarations()
84            .iter()
85            .find(|declaration| &declaration.stable_key == key)
86            .map(|declaration| &declaration.slot)
87    }
88}
89
90///
91/// AllocationSession
92///
93/// Validated capability required before opening allocation slots.
94///
95/// Integrations should construct sessions only after recovering the ledger,
96/// validating declarations, and committing the next generation. Opening storage
97/// through this type keeps handle creation tied to the validated stable-key
98/// snapshot.
99pub struct AllocationSession<S: StorageSubstrate> {
100    substrate: S,
101    validated: ValidatedAllocations,
102}
103
104impl<S: StorageSubstrate> AllocationSession<S> {
105    /// Construct a session from a substrate and validated allocation set.
106    #[must_use]
107    pub const fn new(substrate: S, validated: ValidatedAllocations) -> Self {
108        Self {
109            substrate,
110            validated,
111        }
112    }
113
114    /// Borrow the validated allocation set.
115    #[must_use]
116    pub const fn validated(&self) -> &ValidatedAllocations {
117        &self.validated
118    }
119
120    /// Open an allocation by stable key.
121    pub fn open(
122        &self,
123        key: &StableKey,
124    ) -> Result<S::MemoryHandle, AllocationSessionError<S::Error>> {
125        let slot = self
126            .validated
127            .slot_for(key)
128            .ok_or_else(|| AllocationSessionError::UnknownStableKey(key.clone()))?;
129        self.substrate
130            .open_slot(slot)
131            .map_err(AllocationSessionError::Substrate)
132    }
133}
134
135///
136/// AllocationSessionError
137///
138/// Failure to open through a validated allocation session.
139#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
140pub enum AllocationSessionError<E> {
141    /// Stable key was not part of the validated allocation snapshot.
142    #[error("stable key '{0}' was not validated for this allocation session")]
143    UnknownStableKey(StableKey),
144    /// Storage substrate failed to open the validated slot.
145    #[error("storage substrate failed to open allocation slot")]
146    Substrate(E),
147}