mkit_server/indexed/
entries.rs1use crate::ServerError;
4use crate::store::index::{IndexEntry, IndexValue};
5use mkit_core::hash::Hash;
6use std::collections::BTreeMap;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct FrameMeta {
11 pub id: Hash,
12 pub frame_offset: u64,
13 pub frame_length: u64,
14 pub wire_type: u8,
15 pub delta_base: Option<Hash>,
16 pub decoded_size: u64,
17}
18
19pub fn index_entries(frames: &[FrameMeta], cap: u32) -> Result<Vec<IndexEntry>, ServerError> {
24 let mut depths = BTreeMap::new();
25 let mut entries = Vec::with_capacity(frames.len());
26 for frame in frames {
27 if depths.contains_key(&frame.id) {
28 continue;
29 }
30 let depth = match frame.delta_base {
31 None => 0,
32 Some(base) => depths.get(&base).copied().unwrap_or(0u32).saturating_add(1),
33 };
34 if depth > cap {
35 return Err(ServerError::invalid_argument("delta chain too deep"));
36 }
37 depths.insert(frame.id, depth);
38 entries.push(IndexEntry {
39 object: frame.id,
40 value: IndexValue {
41 frame_offset: frame.frame_offset,
42 frame_length: frame.frame_length,
43 wire_type: frame.wire_type,
44 decoded_size: frame.decoded_size,
45 chain_depth: depth,
46 delta_base: frame.delta_base,
47 },
48 });
49 }
50 Ok(entries)
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 fn frame(id: u8, base: Option<u8>, offset: u64) -> FrameMeta {
58 FrameMeta {
59 id: [id; 32],
60 frame_offset: offset,
61 frame_length: 10,
62 wire_type: if base.is_some() { 0x02 } else { 0x00 },
63 delta_base: base.map(|id| [id; 32]),
64 decoded_size: 5,
65 }
66 }
67
68 #[test]
69 fn first_occurrence_and_depth_are_pure_from_frames() {
70 let frames = [
71 frame(1, None, 10),
72 frame(2, Some(1), 20),
73 frame(3, Some(2), 30),
74 frame(1, Some(99), 40),
75 frame(4, Some(99), 50),
76 ];
77 let once = index_entries(&frames, 50).unwrap();
78 assert_eq!(once, index_entries(&frames, 50).unwrap());
79 assert_eq!(once.len(), 4);
80 assert_eq!(
81 once.iter()
82 .map(|entry| entry.value.chain_depth)
83 .collect::<Vec<_>>(),
84 [0, 1, 2, 1]
85 );
86 assert_eq!(once[0].value.frame_offset, 10);
87 assert_eq!(
88 index_entries(&frames, 1).unwrap_err().public_message(),
89 "delta chain too deep"
90 );
91 }
92}