(rows: &[Option<&[u8]>])
| 23 | const BLOB_FORMAT_VERSION: u8 = 1; |
| 24 | |
| 25 | pub(crate) fn build_blob_file_bytes(rows: &[Option<&[u8]>]) -> Vec<u8> { |
| 26 | let mut file_bytes = Vec::new(); |
| 27 | let mut lengths = Vec::with_capacity(rows.len()); |
| 28 | |
| 29 | for row in rows { |
| 30 | match row { |
| 31 | Some(payload) => { |
| 32 | let entry_length = payload |
| 33 | .len() |
| 34 | .checked_add(BLOB_ENTRY_OVERHEAD) |
| 35 | .and_then(|len| i64::try_from(len).ok()) |
| 36 | .unwrap_or_else(|| { |
| 37 | panic!("Blob payload length {} exceeds test helper limits", payload.len()) |
| 38 | }); |
| 39 | lengths.push(entry_length); |
| 40 | |
| 41 | file_bytes.extend_from_slice(&BLOB_MAGIC_NUMBER_BYTES); |
| 42 | file_bytes.extend_from_slice(payload); |
| 43 | let mut hasher = crc32fast::Hasher::new(); |
| 44 | hasher.update(&BLOB_MAGIC_NUMBER_BYTES); |
| 45 | hasher.update(payload); |
| 46 | |
| 47 | let entry_length_bytes = entry_length.to_le_bytes(); |
| 48 | file_bytes.extend_from_slice(&entry_length_bytes); |
| 49 | hasher.update(&entry_length_bytes); |
| 50 | file_bytes.extend_from_slice(&hasher.finalize().to_le_bytes()); |
| 51 | } |
| 52 | None => lengths.push(-1), |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | let index_bytes = encode_delta_varints(&lengths); |
| 57 | let index_length = i32::try_from(index_bytes.len()).unwrap_or_else(|_| { |
| 58 | panic!( |
| 59 | "Blob index length {} exceeds test helper limits", |
| 60 | index_bytes.len() |
| 61 | ) |
| 62 | }); |
| 63 | file_bytes.extend_from_slice(&index_bytes); |
| 64 | file_bytes.extend_from_slice(&index_length.to_le_bytes()); |
| 65 | file_bytes.push(BLOB_FORMAT_VERSION); |
| 66 | file_bytes |
| 67 | } |
| 68 | |
| 69 | pub(crate) fn write_blob_file(path: &Path, rows: &[Option<&[u8]>]) { |
| 70 | let file_bytes = build_blob_file_bytes(rows); |
no test coverage detected