agentic_codebase/format/
compression.rs1use crate::types::{AcbError, AcbResult};
7
8pub fn compress(data: &[u8]) -> Vec<u8> {
12 lz4_flex::compress_prepend_size(data)
13}
14
15pub fn decompress(data: &[u8]) -> AcbResult<Vec<u8>> {
21 lz4_flex::decompress_size_prepended(data)
22 .map_err(|e| AcbError::Compression(format!("LZ4 decompression failed: {}", e)))
23}
24
25#[derive(Debug, Default)]
30pub struct StringPoolBuilder {
31 data: Vec<u8>,
32}
33
34impl StringPoolBuilder {
35 pub fn new() -> Self {
37 Self { data: Vec::new() }
38 }
39
40 pub fn add(&mut self, s: &str) -> (u32, u16) {
42 let offset = self.data.len() as u32;
43 let len = s.len() as u16;
44 self.data.extend_from_slice(s.as_bytes());
45 (offset, len)
46 }
47
48 pub fn data(&self) -> &[u8] {
50 &self.data
51 }
52
53 pub fn uncompressed_size(&self) -> usize {
55 self.data.len()
56 }
57
58 pub fn compress(&self) -> Vec<u8> {
60 compress(&self.data)
61 }
62}
63
64#[derive(Debug, Clone)]
66pub struct StringPool {
67 data: Vec<u8>,
68}
69
70impl StringPool {
71 pub fn from_data(data: Vec<u8>) -> Self {
73 Self { data }
74 }
75
76 pub fn from_compressed(compressed: &[u8]) -> AcbResult<Self> {
78 let data = decompress(compressed)?;
79 Ok(Self { data })
80 }
81
82 pub fn get(&self, offset: u32, len: u16) -> AcbResult<&str> {
88 let start = offset as usize;
89 let end = start + len as usize;
90 if end > self.data.len() {
91 return Err(AcbError::Corrupt(offset as u64));
92 }
93 std::str::from_utf8(&self.data[start..end]).map_err(|_| AcbError::Corrupt(offset as u64))
94 }
95
96 pub fn len(&self) -> usize {
98 self.data.len()
99 }
100
101 pub fn is_empty(&self) -> bool {
103 self.data.is_empty()
104 }
105}