uqa_core/memory/
string.rs1use super::{reconcile_buffer_capacity, replacement, MemoryBudget, MemoryError, MemoryReservation};
10
11#[derive(Debug)]
12pub struct BudgetedString {
13 value: String,
14 memory: MemoryReservation,
15}
16
17impl BudgetedString {
18 pub fn new(budget: &MemoryBudget) -> Self {
19 Self {
20 value: String::new(),
21 memory: budget.empty_reservation(),
22 }
23 }
24
25 pub fn from_budgeted(value: super::Budgeted<String>) -> Self {
27 let (value, memory) = value.into_parts();
28 Self { value, memory }
29 }
30
31 pub fn capacity(&self) -> usize {
32 self.value.capacity()
33 }
34
35 pub fn reserve(&mut self, additional: usize) -> Result<(), MemoryError> {
36 let required = self
37 .value
38 .len()
39 .checked_add(additional)
40 .ok_or(MemoryError::SizeOverflow)?;
41 if required <= self.capacity() {
42 return Ok(());
43 }
44 let (capacity, mut memory) =
45 replacement::<u8>(self.memory.budget(), self.capacity(), required)?;
46 let mut value = String::new();
47 value.try_reserve_exact(capacity)?;
48 reconcile_buffer_capacity::<u8>(&mut memory, value.capacity())?;
49 value.push_str(&self.value);
50 self.value = value;
51 self.memory = memory;
52 Ok(())
53 }
54
55 pub fn push_str(&mut self, text: &str) -> Result<(), MemoryError> {
56 self.reserve(text.len())?;
57 self.value.push_str(text);
58 Ok(())
59 }
60
61 pub fn push(&mut self, character: char) -> Result<(), MemoryError> {
62 self.reserve(character.len_utf8())?;
63 self.value.push(character);
64 Ok(())
65 }
66
67 pub fn truncate(&mut self, length: usize) {
68 self.value.truncate(length);
69 }
70
71 pub fn into_parts(self) -> (String, MemoryReservation) {
72 (self.value, self.memory)
73 }
74}
75
76impl std::ops::Deref for BudgetedString {
77 type Target = str;
78
79 fn deref(&self) -> &str {
80 &self.value
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn completed_string_transfer_preserves_buffer_and_lease() {
90 let budget = MemoryBudget::new(128);
91 let mut source = BudgetedString::new(&budget);
92 source.push_str("transferred").unwrap();
93 let (value, memory) = source.into_parts();
94 let pointer = value.as_ptr();
95 let capacity = value.capacity();
96 let output = BudgetedString::from_budgeted(super::super::Budgeted::new(value, memory));
97 assert_eq!(output.as_ptr(), pointer);
98 assert_eq!(budget.used(), capacity);
99 drop(output);
100 assert_eq!(budget.used(), 0);
101 }
102}