git_commitgraph/file/
access.rs1use std::{
2 convert::TryInto,
3 fmt::{Debug, Formatter},
4 path::Path,
5};
6
7use crate::file::{self, commit::Commit, File, COMMIT_DATA_ENTRY_SIZE_SANS_HASH};
8
9impl File {
11 pub fn base_graph_count(&self) -> u8 {
13 self.base_graph_count
14 }
15
16 pub fn commit_at(&self, pos: file::Position) -> Commit<'_> {
24 Commit::new(self, pos)
25 }
26
27 pub fn object_hash(&self) -> git_hash::Kind {
31 self.object_hash
32 }
33
34 pub fn id_at(&self, pos: file::Position) -> &git_hash::oid {
38 assert!(
39 pos.0 < self.num_commits(),
40 "expected lexigraphical position less than {}, got {}",
41 self.num_commits(),
42 pos.0
43 );
44 let pos: usize = pos
45 .0
46 .try_into()
47 .expect("an architecture able to hold 32 bits of integer");
48 let start = self.oid_lookup_offset + (pos * self.hash_len);
49 git_hash::oid::from_bytes_unchecked(&self.data[start..][..self.hash_len])
50 }
51
52 pub fn iter_base_graph_ids(&self) -> impl Iterator<Item = &git_hash::oid> {
54 let start = self.base_graphs_list_offset.unwrap_or(0);
55 let base_graphs_list = &self.data[start..][..self.hash_len * usize::from(self.base_graph_count)];
56 base_graphs_list
57 .chunks(self.hash_len)
58 .map(git_hash::oid::from_bytes_unchecked)
59 }
60
61 pub fn iter_commits(&self) -> impl Iterator<Item = Commit<'_>> {
63 (0..self.num_commits()).map(move |i| self.commit_at(file::Position(i)))
64 }
65
66 pub fn iter_ids(&self) -> impl Iterator<Item = &git_hash::oid> {
68 (0..self.num_commits()).map(move |i| self.id_at(file::Position(i)))
69 }
70
71 pub fn lookup(&self, id: impl AsRef<git_hash::oid>) -> Option<file::Position> {
74 let id = id.as_ref();
75 let first_byte = usize::from(id.first_byte());
76 let mut upper_bound = self.fan[first_byte];
77 let mut lower_bound = if first_byte != 0 { self.fan[first_byte - 1] } else { 0 };
78
79 while lower_bound < upper_bound {
80 let mid = (lower_bound + upper_bound) / 2;
81 let mid_sha = self.id_at(file::Position(mid));
82
83 use std::cmp::Ordering::*;
84 match id.cmp(mid_sha) {
85 Less => upper_bound = mid,
86 Equal => return Some(file::Position(mid)),
87 Greater => lower_bound = mid + 1,
88 }
89 }
90 None
91 }
92
93 pub fn num_commits(&self) -> u32 {
98 self.fan[255]
99 }
100
101 pub fn path(&self) -> &Path {
103 &self.path
104 }
105}
106
107impl File {
108 pub(crate) fn commit_data_bytes(&self, pos: file::Position) -> &[u8] {
110 assert!(
111 pos.0 < self.num_commits(),
112 "expected lexigraphical position less than {}, got {}",
113 self.num_commits(),
114 pos.0
115 );
116 let pos: usize = pos
117 .0
118 .try_into()
119 .expect("an architecture able to hold 32 bits of integer");
120 let entry_size = self.hash_len + COMMIT_DATA_ENTRY_SIZE_SANS_HASH;
121 let start = self.commit_data_offset + (pos * entry_size);
122 &self.data[start..][..entry_size]
123 }
124
125 pub(crate) fn extra_edges_data(&self) -> Option<&[u8]> {
127 Some(&self.data[self.extra_edges_list_range.clone()?])
128 }
129}
130
131impl Debug for File {
132 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
133 write!(f, r#"File("{:?}")"#, self.path.display())
134 }
135}