| 43 | /// - (in the latter case) explicit blob contents (L bytes) |
| 44 | #[allow(clippy::missing_panics_doc, clippy::unwrap_used)] |
| 45 | pub fn encode_blobs<T>(blobs: &[T]) -> (alloc::vec::Vec<u8>, usize) |
| 46 | where |
| 47 | T: AsRef<[u8]>, |
| 48 | { |
| 49 | use alloc::{collections::BTreeMap, vec::Vec}; |
| 50 | |
| 51 | let mut dedup_map = BTreeMap::new(); |
| 52 | blobs |
| 53 | .iter() |
| 54 | .map(AsRef::as_ref) |
| 55 | .filter(|blob| !blob.is_empty()) |
| 56 | .for_each(|blob| { |
| 57 | let v = dedup_map.entry(blob.as_ref()).or_insert(0); |
| 58 | *v += 1; |
| 59 | }); |
| 60 | |
| 61 | let mut dedup_list: Vec<&[u8]> = dedup_map |
| 62 | .iter() |
| 63 | .filter(|&(_, &v)| v > 1) |
| 64 | .map(|(&k, _)| k) |
| 65 | .collect(); |
| 66 | dedup_list.sort_by_key(|e| { |
| 67 | let k = match e { |
| 68 | [0] => 2, |
| 69 | [1] => 1, |
| 70 | _ => 0, |
| 71 | }; |
| 72 | (k, dedup_map.get(e).unwrap()) |
| 73 | }); |
| 74 | dedup_list.reverse(); |
| 75 | let idx_len = dedup_list.len(); |
| 76 | |
| 77 | let rev_idx: BTreeMap<&[u8], usize> = dedup_list |
| 78 | .iter() |
| 79 | .enumerate() |
| 80 | .map(|(i, &e)| (e, i)) |
| 81 | .collect(); |
| 82 | |
| 83 | let mut out_buf = Vec::new(); |
| 84 | let mut buf = [0u8; 4]; |
| 85 | |
| 86 | out_buf.extend_from_slice(encode_vlq(blobs.len(), &mut buf)); |
| 87 | out_buf.extend_from_slice(encode_vlq(dedup_list.len(), &mut buf)); |
| 88 | |
| 89 | for e in dedup_list { |
| 90 | out_buf.extend_from_slice(encode_vlq(e.len(), &mut buf)); |
| 91 | out_buf.extend_from_slice(e); |
| 92 | } |
| 93 | |
| 94 | for blob in blobs.iter().map(AsRef::as_ref) { |
| 95 | if let Some(dup_pos) = rev_idx.get(blob) { |
| 96 | let n = (dup_pos << 1) + 1usize; |
| 97 | out_buf.extend_from_slice(encode_vlq(n, &mut buf)); |
| 98 | } else { |
| 99 | let n = blob.len() << 1; |
| 100 | out_buf.extend_from_slice(encode_vlq(n, &mut buf)); |
| 101 | out_buf.extend_from_slice(blob); |
| 102 | } |