Skip to main content

mkit_server/indexed/
entries.rs

1//! Pure index metadata derived from decoded pack entries.
2
3use crate::ServerError;
4use crate::store::index::{IndexEntry, IndexValue};
5use mkit_core::hash::Hash;
6use std::collections::BTreeMap;
7
8/// Frame facts captured directly from `decode_entries_with`.
9#[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
19/// Derive write-once index rows from the frame list, retaining the first
20/// occurrence of each object. No repository or storage observation enters
21/// this function. External bases contribute one in-pack depth; the resolver
22/// checks total depth separately.
23pub 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}