1use super::{replacement, MemoryBudget, MemoryError, MemoryReservation};
10
11#[derive(Debug)]
12pub struct BudgetedVec<T> {
13 values: Vec<T>,
14 memory: MemoryReservation,
15}
16
17impl<T> BudgetedVec<T> {
18 pub fn new(budget: &MemoryBudget) -> Self {
19 Self {
20 values: Vec::new(),
21 memory: budget.empty_reservation(),
22 }
23 }
24
25 pub fn capacity(&self) -> usize {
26 self.values.capacity()
27 }
28
29 pub fn budget(&self) -> &MemoryBudget {
30 self.memory.budget()
31 }
32
33 pub fn reserve(&mut self, additional: usize) -> Result<(), MemoryError> {
34 let required = self
35 .values
36 .len()
37 .checked_add(additional)
38 .ok_or(MemoryError::SizeOverflow)?;
39 if required <= self.values.capacity() {
40 return Ok(());
41 }
42 let (capacity, memory) = replacement::<T>(self.memory.budget(), self.capacity(), required)?;
43 let mut values = Vec::new();
44 values.try_reserve_exact(capacity)?;
45 values.append(&mut self.values);
46 self.values = values;
48 self.memory = memory;
49 Ok(())
50 }
51
52 pub fn push(&mut self, value: T) -> Result<(), MemoryError> {
53 self.reserve(1)?;
54 self.values.push(value);
55 Ok(())
56 }
57
58 pub fn clear(&mut self) {
59 self.values.clear();
60 }
61
62 pub fn truncate(&mut self, len: usize) {
63 self.values.truncate(len);
64 }
65
66 pub fn pop(&mut self) -> Option<T> {
67 self.values.pop()
68 }
69
70 pub fn into_parts(self) -> (Vec<T>, MemoryReservation) {
72 (self.values, self.memory)
73 }
74}
75
76impl<T> std::ops::Deref for BudgetedVec<T> {
77 type Target = [T];
78
79 fn deref(&self) -> &[T] {
80 &self.values
81 }
82}
83
84impl<T: Copy> BudgetedVec<T> {
85 pub fn extend_from_slice(&mut self, values: &[T]) -> Result<(), MemoryError> {
87 self.reserve(values.len())?;
88 self.values.extend_from_slice(values);
89 Ok(())
90 }
91}
92
93impl<T> std::ops::DerefMut for BudgetedVec<T> {
94 fn deref_mut(&mut self) -> &mut [T] {
95 &mut self.values
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn extending_a_slice_reserves_before_mutating_and_preserves_failed_inputs() {
105 let budget = MemoryBudget::new(16);
106 let mut values = BudgetedVec::new(&budget);
107 values.extend_from_slice(&[1_u8, 2, 3, 4]).unwrap();
108 let retained = budget.used();
109 assert!(matches!(
110 values.extend_from_slice(&[9; 32]),
111 Err(MemoryError::Limit { .. })
112 ));
113 assert_eq!(&*values, &[1, 2, 3, 4]);
114 assert_eq!(budget.used(), retained);
115 values.extend_from_slice(&[5, 6]).unwrap();
116 assert_eq!(&*values, &[1, 2, 3, 4, 5, 6]);
117 assert_eq!(budget.used(), values.capacity());
118 drop(values);
119 assert_eq!(budget.used(), 0);
120 }
121}