git_commitgraph/graph/
access.rs

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