Read and decode a log segment from in-memory bytes.
(
data: &[u8],
registry: &DictionaryRegistry,
)
| 232 | |
| 233 | /// Read and decode a log segment from in-memory bytes. |
| 234 | pub fn read_log_segment_from_bytes( |
| 235 | data: &[u8], |
| 236 | registry: &DictionaryRegistry, |
| 237 | ) -> Result<LogSegmentData, SegmentReadError> { |
| 238 | let header_end = decode_tseg_header(data)?; |
| 239 | let mut cur = Cursor::new(&data[header_end..]); |
| 240 | |
| 241 | let kind = cur |
| 242 | .read_u8() |
| 243 | .ok_or(SegmentReadError::TooSmall { size: data.len() })?; |
| 244 | if kind != KIND_LOG { |
| 245 | return Err(SegmentReadError::UnknownKind { kind }); |
| 246 | } |
| 247 | |
| 248 | let entry_count = cur |
| 249 | .read_u32_le() |
| 250 | .ok_or(SegmentReadError::TooSmall { size: data.len() })? as usize; |
| 251 | let compressed_len = cur |
| 252 | .read_u32_le() |
| 253 | .ok_or(SegmentReadError::TooSmall { size: data.len() })? as usize; |
| 254 | |
| 255 | let compressed_block = cur |
| 256 | .read_bytes(compressed_len) |
| 257 | .ok_or(SegmentReadError::TooSmall { size: data.len() })?; |
| 258 | |
| 259 | let raw = decompress_log(compressed_block, registry).map_err(|e| { |
| 260 | SegmentReadError::Decompression { |
| 261 | detail: e.to_string(), |
| 262 | } |
| 263 | })?; |
| 264 | |
| 265 | // Parse raw bytes back into log entries. |
| 266 | // Format per entry: [timestamp_ms:8] [data_len:4] [data:N] |
| 267 | let mut entries = Vec::with_capacity(entry_count); |
| 268 | let mut raw_cur = Cursor::new(&raw); |
| 269 | |
| 270 | while raw_cur.remaining() >= 12 && entries.len() < entry_count { |
| 271 | let timestamp_ms = raw_cur.read_u64_le().expect( |
| 272 | "invariant: 'while raw_cur.remaining() >= 12' loop guard ensures 8 bytes for timestamp", |
| 273 | ) as i64; |
| 274 | let data_len = raw_cur |
| 275 | .read_u32_le() |
| 276 | .expect("invariant: remaining >= 12, u64 consumed 8, leaving 4 for data_len") |
| 277 | as usize; |
| 278 | |
| 279 | let entry_data = match raw_cur.read_bytes(data_len) { |
| 280 | Some(b) => b.to_vec(), |
| 281 | None => break, |
| 282 | }; |
| 283 | |
| 284 | entries.push(LogEntry { |
| 285 | timestamp_ms, |
| 286 | data: entry_data, |
| 287 | }); |
| 288 | } |
| 289 | |
| 290 | Ok(LogSegmentData { entries }) |
| 291 | } |
no test coverage detected