gix_commitgraph/
access.rs

1use crate::{file, file::Commit, File, Graph, Position};
2
3/// Access
4impl Graph {
5    /// Returns the commit at the given position `pos`.
6    ///
7    /// # Panics
8    /// If `pos` is greater or equal to [`num_commits()`][Graph::num_commits()].
9    pub fn commit_at(&self, pos: Position) -> Commit<'_> {
10        let r = self.lookup_by_pos(pos);
11        r.file.commit_at(r.pos)
12    }
13
14    /// Returns the commit matching the given `id`.
15    pub fn commit_by_id(&self, id: impl AsRef<gix_hash::oid>) -> Option<Commit<'_>> {
16        let r = self.lookup_by_id(id.as_ref())?;
17        Some(r.file.commit_at(r.file_pos))
18    }
19
20    /// Returns the `hash` at the given position `pos`.
21    ///
22    /// # Panics
23    /// If `pos` is greater or equal to [`num_commits()`][Graph::num_commits()].
24    pub fn id_at(&self, pos: Position) -> &gix_hash::oid {
25        let r = self.lookup_by_pos(pos);
26        r.file.id_at(r.pos)
27    }
28
29    /// Iterate over commits in unsorted order.
30    pub fn iter_commits(&self) -> impl Iterator<Item = Commit<'_>> {
31        self.files.iter().flat_map(File::iter_commits)
32    }
33
34    /// Iterate over commit IDs in unsorted order.
35    pub fn iter_ids(&self) -> impl Iterator<Item = &gix_hash::oid> {
36        self.files.iter().flat_map(File::iter_ids)
37    }
38
39    /// Translate the given `id` to its position in the file.
40    pub fn lookup(&self, id: impl AsRef<gix_hash::oid>) -> Option<Position> {
41        Some(self.lookup_by_id(id.as_ref())?.graph_pos)
42    }
43
44    /// Returns the number of commits stored in this file.
45    pub fn num_commits(&self) -> u32 {
46        self.files.iter().map(File::num_commits).sum()
47    }
48}
49
50/// Access fundamentals
51impl Graph {
52    fn lookup_by_id(&self, id: &gix_hash::oid) -> Option<LookupByIdResult<'_>> {
53        let mut current_file_start = 0;
54        for file in &self.files {
55            if let Some(lex_pos) = file.lookup(id) {
56                return Some(LookupByIdResult {
57                    file,
58                    file_pos: lex_pos,
59                    graph_pos: Position(current_file_start + lex_pos.0),
60                });
61            }
62            current_file_start += file.num_commits();
63        }
64        None
65    }
66
67    fn lookup_by_pos(&self, pos: Position) -> LookupByPositionResult<'_> {
68        let mut remaining = pos.0;
69        for (file_index, file) in self.files.iter().enumerate() {
70            match remaining.checked_sub(file.num_commits()) {
71                Some(v) => remaining = v,
72                None => {
73                    return LookupByPositionResult {
74                        file,
75                        _file_index: file_index,
76                        pos: file::Position(remaining),
77                    }
78                }
79            }
80        }
81        panic!("graph position too large: {}", pos.0);
82    }
83}
84
85#[derive(Clone)]
86struct LookupByIdResult<'a> {
87    pub file: &'a File,
88    pub graph_pos: Position,
89    pub file_pos: file::Position,
90}
91
92#[derive(Clone)]
93struct LookupByPositionResult<'a> {
94    pub file: &'a File,
95    pub _file_index: usize,
96    pub pos: file::Position,
97}