Skip to main content

molframe_core/execution/
retained.rs

1//! Owned results whose allocation charge follows their lifetime.
2
3use super::{MemoryBudgetError, MemoryReservation};
4use std::ops::Deref;
5
6/// An owned result retaining the reservation for its backing allocations.
7///
8/// Sharing `Arc<Retained<T>>` shares one charge. The value is borrowed rather
9/// than extracted, so an array view cannot silently outlive its accounting.
10#[derive(Debug)]
11pub struct Retained<T> {
12    value: T,
13    reservation: MemoryReservation,
14}
15
16impl<T> Retained<T> {
17    /// Transfers an existing allocation reservation to its completed result.
18    ///
19    /// The caller must reserve before allocation and include every retained
20    /// backing buffer in `bytes`. Unused scratch capacity is released here.
21    ///
22    /// # Errors
23    ///
24    /// Rejects an understated reservation without publishing the value.
25    pub fn new(
26        value: T,
27        reservation: MemoryReservation,
28        bytes: usize,
29    ) -> Result<Self, MemoryBudgetError> {
30        let mut retained = Self { value, reservation };
31        if bytes > retained.reservation.bytes() {
32            return Err(MemoryBudgetError::Exhausted {
33                requested: bytes,
34                available: retained.reservation.bytes(),
35            });
36        }
37        retained.reservation.shrink_to(bytes);
38        Ok(retained)
39    }
40
41    /// Charged bytes retained by this result.
42    #[must_use]
43    pub const fn retained_bytes(&self) -> usize {
44        self.reservation.bytes()
45    }
46}
47
48impl<T> Deref for Retained<T> {
49    type Target = T;
50    fn deref(&self) -> &T {
51        &self.value
52    }
53}
54
55#[cfg(test)]
56#[path = "retained_tests.rs"]
57mod tests;