1use crate::error::FastError;
13use crate::operators::DictionaryValue;
14use crate::pmap::PresenceMap;
15use std::collections::HashMap;
16
17#[derive(Debug)]
19pub struct FastDecoder {
20 global_dict: HashMap<String, DictionaryValue>,
22 template_dicts: HashMap<u32, HashMap<String, DictionaryValue>>,
24 last_template_id: Option<u32>,
26}
27
28impl FastDecoder {
29 #[must_use]
31 pub fn new() -> Self {
32 Self {
33 global_dict: HashMap::new(),
34 template_dicts: HashMap::new(),
35 last_template_id: None,
36 }
37 }
38
39 pub fn reset(&mut self) {
41 self.global_dict.clear();
42 self.template_dicts.clear();
43 self.last_template_id = None;
44 }
45
46 pub fn decode_uint(data: &[u8], offset: &mut usize) -> Result<u64, FastError> {
58 let mut result: u64 = 0;
59
60 loop {
61 if *offset >= data.len() {
62 return Err(FastError::UnexpectedEof);
63 }
64
65 let byte = data[*offset];
66 *offset += 1;
67
68 if result > (u64::MAX >> 7) {
70 return Err(FastError::IntegerOverflow);
71 }
72
73 result = (result << 7) | (byte & 0x7F) as u64;
74
75 if byte & 0x80 != 0 {
77 break;
78 }
79 }
80
81 Ok(result)
82 }
83
84 pub fn decode_int(data: &[u8], offset: &mut usize) -> Result<i64, FastError> {
96 if *offset >= data.len() {
97 return Err(FastError::UnexpectedEof);
98 }
99
100 let first_byte = data[*offset];
101 let negative = (first_byte & 0x40) != 0;
102
103 let mut result: i64 = if negative { -1 } else { 0 };
104
105 loop {
106 if *offset >= data.len() {
107 return Err(FastError::UnexpectedEof);
108 }
109
110 let byte = data[*offset];
111 *offset += 1;
112
113 result = (result << 7) | (byte & 0x7F) as i64;
114
115 if byte & 0x80 != 0 {
116 break;
117 }
118 }
119
120 Ok(result)
121 }
122
123 pub fn decode_ascii(data: &[u8], offset: &mut usize) -> Result<String, FastError> {
135 let mut result = Vec::new();
136
137 loop {
138 if *offset >= data.len() {
139 return Err(FastError::UnexpectedEof);
140 }
141
142 let byte = data[*offset];
143 *offset += 1;
144
145 result.push(byte & 0x7F);
147
148 if byte & 0x80 != 0 {
150 break;
151 }
152 }
153
154 String::from_utf8(result).map_err(|_| FastError::InvalidString)
155 }
156
157 pub fn decode_bytes(data: &[u8], offset: &mut usize) -> Result<Vec<u8>, FastError> {
169 let length = Self::decode_uint(data, offset)? as usize;
170
171 if *offset + length > data.len() {
172 return Err(FastError::UnexpectedEof);
173 }
174
175 let bytes = data[*offset..*offset + length].to_vec();
176 *offset += length;
177
178 Ok(bytes)
179 }
180
181 pub fn decode_pmap(data: &[u8], offset: &mut usize) -> Result<PresenceMap, FastError> {
193 PresenceMap::decode(data, offset)
194 }
195
196 #[must_use]
198 pub fn get_global(&self, key: &str) -> Option<&DictionaryValue> {
199 self.global_dict.get(key)
200 }
201
202 pub fn set_global(&mut self, key: impl Into<String>, value: DictionaryValue) {
204 self.global_dict.insert(key.into(), value);
205 }
206
207 #[must_use]
209 pub fn get_template(&self, template_id: u32, key: &str) -> Option<&DictionaryValue> {
210 self.template_dicts
211 .get(&template_id)
212 .and_then(|dict| dict.get(key))
213 }
214
215 pub fn set_template(
217 &mut self,
218 template_id: u32,
219 key: impl Into<String>,
220 value: DictionaryValue,
221 ) {
222 self.template_dicts
223 .entry(template_id)
224 .or_default()
225 .insert(key.into(), value);
226 }
227
228 #[must_use]
230 pub const fn last_template_id(&self) -> Option<u32> {
231 self.last_template_id
232 }
233
234 pub fn set_last_template_id(&mut self, id: u32) {
236 self.last_template_id = Some(id);
237 }
238}
239
240impl Default for FastDecoder {
241 fn default() -> Self {
242 Self::new()
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249
250 #[test]
251 fn test_decode_uint_single_byte() {
252 let data = [0x81]; let mut offset = 0;
254 let result = FastDecoder::decode_uint(&data, &mut offset).unwrap();
255 assert_eq!(result, 1);
256 assert_eq!(offset, 1);
257 }
258
259 #[test]
260 fn test_decode_uint_multi_byte() {
261 let data = [0x00, 0x81]; let mut offset = 0;
263 let result = FastDecoder::decode_uint(&data, &mut offset).unwrap();
264 assert_eq!(result, 1);
265 assert_eq!(offset, 2);
266 }
267
268 #[test]
269 fn test_decode_uint_larger() {
270 let data = [0x07, 0xAE]; let mut offset = 0;
276 let result = FastDecoder::decode_uint(&data, &mut offset).unwrap();
277 assert_eq!(result, 942);
278 }
279
280 #[test]
281 fn test_decode_int_positive() {
282 let data = [0x81]; let mut offset = 0;
284 let result = FastDecoder::decode_int(&data, &mut offset).unwrap();
285 assert_eq!(result, 1);
286 }
287
288 #[test]
289 fn test_decode_int_negative() {
290 let data = [0xFF]; let mut offset = 0;
292 let result = FastDecoder::decode_int(&data, &mut offset).unwrap();
293 assert_eq!(result, -1);
294 }
295
296 #[test]
297 fn test_decode_ascii() {
298 let data = [b'H', b'i', b'!' | 0x80]; let mut offset = 0;
300 let result = FastDecoder::decode_ascii(&data, &mut offset).unwrap();
301 assert_eq!(result, "Hi!");
302 }
303
304 #[test]
305 fn test_decoder_dictionary() {
306 let mut decoder = FastDecoder::new();
307
308 decoder.set_global("test", DictionaryValue::Int(42));
309 assert_eq!(decoder.get_global("test").unwrap().as_i64(), Some(42));
310
311 decoder.set_template(1, "field", DictionaryValue::UInt(100));
312 assert_eq!(
313 decoder.get_template(1, "field").unwrap().as_u64(),
314 Some(100)
315 );
316 }
317}