structured_asn1/memory/
string.rs1use super::{Memory, MemoryError, OwnedVec};
4
5#[derive(Debug)]
11pub struct OwnedString {
12 bytes: OwnedVec<u8>,
13}
14
15impl OwnedString {
16 pub(super) fn new(memory: &Memory) -> Self {
17 Self {
18 bytes: memory.vector(),
19 }
20 }
21
22 #[must_use]
24 pub fn memory(&self) -> &Memory {
25 self.bytes.memory()
26 }
27
28 #[must_use]
30 pub fn len(&self) -> usize {
31 self.bytes.len()
32 }
33
34 #[must_use]
36 pub fn is_empty(&self) -> bool {
37 self.bytes.is_empty()
38 }
39
40 #[must_use]
42 pub fn capacity(&self) -> usize {
43 self.bytes.capacity()
44 }
45
46 pub fn as_str(&self, execution: &Memory) -> Result<&str, MemoryError> {
54 execution.charge_work(self.bytes.len() as u64)?;
55 Ok(core::str::from_utf8(&self.bytes).expect("only valid UTF-8 is appended"))
56 }
57
58 #[must_use]
60 pub fn as_bytes(&self) -> &[u8] {
61 &self.bytes
62 }
63
64 pub fn try_push_str(&mut self, text: &str) -> Result<(), MemoryError> {
66 self.bytes.try_extend_from_slice(text.as_bytes())
67 }
68
69 pub fn try_push(&mut self, character: char) -> Result<(), MemoryError> {
71 self.memory().charge_work(1)?;
72 let mut encoded = [0; 4];
73 self.try_push_str(character.encode_utf8(&mut encoded))
74 }
75
76 pub fn try_copy(&self) -> Result<Self, MemoryError> {
78 Ok(Self {
79 bytes: self.bytes.try_copy()?,
80 })
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::super::MemoryAccount;
87 use super::*;
88 use alloc::sync::Arc;
89
90 #[test]
91 fn repeated_scalar_append_has_amortized_growth() {
92 const LENGTH: usize = 32_768;
95 let memory = Memory::new(Arc::new(MemoryAccount::new(LENGTH * 2, LENGTH * 8)));
96 let mut text = memory.string();
97 for _ in 0..LENGTH {
98 text.try_push('a').unwrap();
99 }
100 assert_eq!(text.len(), LENGTH);
101 assert_eq!(memory.used(), text.capacity());
102 assert!(memory.work_used() <= LENGTH * 8);
103 drop(text);
104 assert_eq!(memory.used(), 0);
105 }
106
107 #[test]
108 fn text_is_valid_utf8_and_retains_its_capacity_after_move() {
109 let memory = Memory::new(Arc::new(MemoryAccount::new(64, 1024)));
112 let mut text = memory.string();
113 text.try_push_str("Дія").unwrap();
114 text.try_push('🦀').unwrap();
115 assert_eq!(text.as_str(&memory).unwrap(), "Дія🦀");
116 let capacity = text.capacity();
117 let observer = memory.clone();
118 drop(memory);
119 assert_eq!(observer.used(), capacity);
120 let copy = text.try_copy().unwrap();
121 assert_eq!(copy.as_str(&observer).unwrap(), "Дія🦀");
122 assert_eq!(observer.used(), capacity + copy.capacity());
123 drop(text);
124 assert_eq!(observer.used(), copy.capacity());
125 drop(copy);
126 assert_eq!(observer.used(), 0);
127 }
128
129 #[test]
130 fn refusal_preserves_text_and_does_not_hide_utf8_scan_work() {
131 let memory = Memory::new(Arc::new(MemoryAccount::new(4, 1024)));
134 let mut text = memory.string();
135 text.try_push('🦀').unwrap();
136 assert_eq!(text.try_push('!'), Err(MemoryError::LimitExceeded));
137 assert_eq!(text.as_str(&memory).unwrap(), "🦀");
138 memory
139 .charge_work((1024 - memory.work_used()) as u64)
140 .unwrap();
141 assert_eq!(text.as_str(&memory), Err(MemoryError::WorkExceeded));
142 assert_eq!(text.as_bytes(), "🦀".as_bytes());
143 }
144
145 #[test]
146 fn retained_text_cannot_pay_for_a_new_operations_validation() {
147 let storage = Memory::new(Arc::new(MemoryAccount::new(64, 1024)));
150 let execution = Memory::new(Arc::new(MemoryAccount::new(64, 0)));
151 let mut text = storage.string();
152 text.try_push_str("issuer").unwrap();
153 let used = storage.work_used();
154 assert_eq!(text.as_str(&execution), Err(MemoryError::WorkExceeded));
155 assert_eq!(storage.work_used(), used);
156 assert_eq!(storage.used(), text.capacity());
157 assert_eq!(execution.used(), 0);
158 }
159}