1use alloc::vec::Vec;
20use bit_reverse::ParallelReverse;
21
22#[cfg_attr(feature = "std", derive(Debug))]
24#[derive(PartialEq, PartialOrd, Clone)]
25pub struct StringLike(pub Vec<u8>);
26
27#[cfg_attr(feature = "std", derive(Debug))]
29#[derive(PartialEq, PartialOrd, Clone)]
30pub struct Numeric(pub u64);
31
32#[cfg_attr(feature = "std", derive(Debug))]
34#[derive(Clone, PartialEq)]
35pub enum PactType {
36 StringLike(StringLike),
37 Numeric(Numeric),
38 List(Vec<PactType>),
39}
40
41impl PactType {
42 pub fn encode(&self, buf: &mut Vec<u8>) {
44 match self {
45 PactType::StringLike(s) => {
46 buf.push(0);
47 buf.push((s.0.len() as u8).swap_bits());
48 buf.extend(s.0.iter());
49 }
50 PactType::Numeric(n) => {
51 buf.push(1.swap_bits());
52 buf.push(8.swap_bits());
54 for b in n.0.to_le_bytes().iter() {
55 buf.push(b.swap_bits())
56 }
57 }
58 PactType::List(l) => {
59 let mut buf_elements: Vec<u8> = Vec::<u8>::default();
60 for element in l {
61 match element {
62 PactType::StringLike(_) => element.encode(&mut buf_elements),
63 PactType::Numeric(_) => element.encode(&mut buf_elements),
64 _ => {} }
66 }
67
68 buf.push(2.swap_bits());
69 buf.push((buf_elements.len() as u8).swap_bits());
70 buf.append(&mut buf_elements);
71
72 }
74 };
75 }
76 pub fn decode(buf: Vec<u8>) -> Result<(Self, usize), &'static str> {
79 match buf.len() {
81 0 => return Err("missing type ID byte"),
82 1 => return Err("missing type length byte"),
83 _ => (),
84 };
85
86 let mut read_offset = 2_usize;
88
89 let data_length = buf[1].swap_bits() as usize;
91 if data_length > buf[read_offset..].len() {
92 return Err("type length > buffer length");
93 }
94
95 match buf[0].swap_bits() {
97 0 => {
98 let read_length = read_offset + data_length;
99 let s = PactType::StringLike(StringLike(buf[read_offset..read_length].to_vec()));
100 Ok((s, read_length))
101 }
102 1 => {
103 let data_length = buf[1].swap_bits() as usize;
104 if data_length != 8 {
105 return Err("implementation only supports 64-bit numerics");
106 }
107
108 let n = PactType::Numeric(Numeric(u64::from_le_bytes([
109 buf[2].swap_bits(),
110 buf[3].swap_bits(),
111 buf[4].swap_bits(),
112 buf[5].swap_bits(),
113 buf[6].swap_bits(),
114 buf[7].swap_bits(),
115 buf[8].swap_bits(),
116 buf[9].swap_bits(),
117 ])));
118 Ok((n, 10usize))
119 }
120 2 => {
121 let mut values: Vec<PactType> = Vec::<PactType>::default();
122 let mut remaining_length = data_length;
123
124 while remaining_length > 0 {
125 let (new_value, offset) = Self::decode(buf[read_offset..].to_vec())?;
126 read_offset = read_offset + offset;
127 remaining_length = remaining_length
128 .checked_sub(offset)
129 .ok_or("list length overflow")?;
130 values.push(new_value);
131 }
132 Ok((PactType::List(values), read_offset))
133 }
134 _ => Err("unsupported type ID"),
135 }
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 #[test]
144 fn it_encodes_string_like() {
145 let s = PactType::StringLike(StringLike(b"hello world".to_vec()));
146 let buf: &mut Vec<u8> = &mut Vec::new();
147 s.encode(buf);
148 assert_eq!(buf[0], 0);
149 assert_eq!(buf[1].swap_bits(), 11);
150 assert_eq!(&buf[2..], "hello world".as_bytes());
151 }
152
153 #[test]
154 fn it_encodes_numeric() {
155 let n = PactType::Numeric(Numeric(123));
156 let buf: &mut Vec<u8> = &mut Vec::new();
157 n.encode(buf);
158
159 let mut expected: Vec<u8> = vec![1, 8, 123, 0, 0, 0, 0, 0, 0, 0];
160 expected = expected.into_iter().map(|b| b.swap_bits()).collect(); assert_eq!(buf, &expected);
162 }
163
164 #[test]
165 fn it_encodes_string_list() {
166 let l = PactType::List(vec![
167 PactType::StringLike(StringLike(b"we're no".to_vec())),
168 PactType::StringLike(StringLike(b"strangers".to_vec())),
169 PactType::StringLike(StringLike(b"to love".to_vec())),
170 ]);
171 let buf: &mut Vec<u8> = &mut Vec::new();
172 l.encode(buf);
173
174 assert_eq!(buf[0].swap_bits(), 2);
175 assert_eq!(buf[1].swap_bits(), 30);
176 assert_eq!(buf[2].swap_bits(), 0);
177 assert_eq!(buf[3].swap_bits(), 8);
178 assert_eq!(&buf[4..12], b"we're no");
179 assert_eq!(buf[12].swap_bits(), 0);
180 assert_eq!(buf[13].swap_bits(), 9);
181 assert_eq!(&buf[14..23], b"strangers");
182 assert_eq!(buf[23].swap_bits(), 0);
183 assert_eq!(buf[24].swap_bits(), 7);
184 assert_eq!(&buf[25..32], b"to love");
185 }
186
187 #[test]
188 fn it_encodes_numeric_list() {
189 let l = PactType::List(vec![
190 PactType::Numeric(Numeric(0x0123456789abcdef)),
191 PactType::Numeric(Numeric(0xfedcba9876543210)),
192 ]);
193 let buf: &mut Vec<u8> = &mut Vec::new();
194 l.encode(buf);
195
196 let list_header: Vec<u8> = vec![2, 20];
197 let item_0: Vec<u8> = vec![1, 8, 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01];
198 let item_1: Vec<u8> = vec![1, 8, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe];
199 let mut expected: Vec<u8> = [list_header, item_0, item_1].concat();
200 expected = expected.into_iter().map(|b| b.swap_bits()).collect(); assert_eq!(buf, &expected);
202 }
203
204 #[test]
205 fn it_decodes_string_like() {
206 let mut buf = vec![0, 11];
207 buf = buf.into_iter().map(|b| b.swap_bits()).collect(); buf.extend("hello world".as_bytes());
209 let (string_type, bytes_read) = PactType::decode(buf).expect("it decodes");
210
211 assert_eq!(
212 string_type,
213 PactType::StringLike(StringLike(b"hello world".to_vec())),
214 );
215
216 assert_eq!(bytes_read, 13usize,);
217 }
218
219 #[test]
220 fn it_decodes_numeric() {
221 let mut encoded: Vec<u8> = vec![1, 8, 123, 0, 0, 0, 0, 0, 0, 0];
222 encoded = encoded.into_iter().map(|b| b.swap_bits()).collect(); let (numeric_type, bytes_read) = PactType::decode(encoded).expect("it decodes");
224
225 assert_eq!(numeric_type, PactType::Numeric(Numeric(123)));
226 assert_eq!(10usize, bytes_read,);
227 }
228
229 #[test]
230 fn it_decodes_string_lists() {
231 let list_header: Vec<u8> = vec![2, 35].into_iter().map(|b| b.swap_bits()).collect();
232 let str0_header: Vec<u8> = vec![0, 8].into_iter().map(|b| b.swap_bits()).collect();
233 let str1_header: Vec<u8> = vec![0, 9].into_iter().map(|b| b.swap_bits()).collect();
234 let str2_header: Vec<u8> = vec![0, 6].into_iter().map(|b| b.swap_bits()).collect();
235 let str3_header: Vec<u8> = vec![0, 4].into_iter().map(|b| b.swap_bits()).collect();
236
237 let buf: Vec<u8> = [
238 list_header,
239 str0_header,
240 b"you know".to_vec(),
241 str1_header,
242 b"the rules".to_vec(),
243 str2_header,
244 b"and so".to_vec(),
245 str3_header,
246 b"do I".to_vec(),
247 ]
248 .concat();
249
250 let (list_type, bytes_read) = PactType::decode(buf).expect("it decodes");
251
252 let expected = PactType::List(vec![
253 PactType::StringLike(StringLike(b"you know".to_vec())),
254 PactType::StringLike(StringLike(b"the rules".to_vec())),
255 PactType::StringLike(StringLike(b"and so".to_vec())),
256 PactType::StringLike(StringLike(b"do I".to_vec())),
257 ]);
258
259 assert_eq!(list_type, expected,);
260
261 assert_eq!(bytes_read, 37usize);
262 }
263
264 #[test]
265 fn it_decodes_numeric_lists() {
266 let list_header: Vec<u8> = vec![2, 20];
267 let num_header: Vec<u8> = vec![1, 8];
268
269 let buf: Vec<u8> = [
270 list_header,
271 num_header.clone(),
272 vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef],
273 num_header,
274 vec![0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed],
275 ]
276 .concat()
277 .into_iter()
278 .map(|b| b.swap_bits())
279 .collect();
280
281 let (list_type, bytes_read) = PactType::decode(buf).expect("it decodes");
282
283 let expected = PactType::List(vec![
284 PactType::Numeric(Numeric(0xefcd_ab89_6745_2301)),
285 PactType::Numeric(Numeric(0xedfe_edfe_edfe_edfe)),
286 ]);
287
288 assert_eq!(list_type, expected,);
289
290 assert_eq!(bytes_read, 22usize);
291 }
292
293 #[test]
294 fn it_fails_decode_list_with_bad_length() {
295 let list_header: Vec<u8> = vec![2, 20];
296 let buf: Vec<u8> = [
297 list_header,
298 vec![1, 8],
299 vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef],
300 ]
301 .concat()
302 .into_iter()
303 .map(|b| b.swap_bits())
304 .collect();
305
306 assert_eq!(PactType::decode(buf), Err("type length > buffer length"));
307
308 let list_header: Vec<u8> = vec![2, 5];
309 let buf: Vec<u8> = [
310 list_header,
311 vec![1, 8],
312 vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef],
313 ]
314 .concat()
315 .into_iter()
316 .map(|b| b.swap_bits())
317 .collect();
318
319 assert_eq!(PactType::decode(buf), Err("list length overflow"));
320 }
321
322 #[test]
323 fn it_fails_with_missing_type_id() {
324 assert_eq!(PactType::decode(vec![]), Err("missing type ID byte"));
325 }
326
327 #[test]
328 fn it_fails_with_missing_type_length() {
329 assert_eq!(
330 PactType::decode([0].to_vec()),
331 Err("missing type length byte")
332 );
333 }
334
335 #[test]
336 #[should_panic(expected = "type length > buffer length")]
337 fn it_fails_with_short_string_like() {
338 PactType::decode([0, 11].to_vec()).unwrap();
339 }
340
341 #[test]
342 #[should_panic(expected = "implementation only supports 64-bit numerics")]
343 fn it_fails_with_u128_numeric() {
344 PactType::decode(
345 [
346 1.swap_bits(),
347 16.swap_bits(),
348 0,
349 0,
350 0,
351 0,
352 0,
353 0,
354 0,
355 0,
356 0,
357 0,
358 0,
359 0,
360 0,
361 0,
362 0,
363 0,
364 ]
365 .to_vec(),
366 )
367 .unwrap();
368 }
369}