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;