1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::file::{self, commit::Commit, File, COMMIT_DATA_ENTRY_SIZE};
use git_object::{borrowed, HashKind, SHA1_SIZE};
use std::{
convert::{TryFrom, TryInto},
fmt::{Debug, Formatter},
path::Path,
};
impl File {
pub fn commit_at(&self, pos: file::Position) -> Commit<'_> {
Commit::new(self, pos)
}
pub fn hash_kind(&self) -> HashKind {
HashKind::Sha1
}
pub fn id_at(&self, pos: file::Position) -> borrowed::Id<'_> {
assert!(
pos.0 < self.num_commits(),
"expected lexigraphical position less than {}, got {}",
self.num_commits(),
pos.0
);
let pos: usize = pos
.0
.try_into()
.expect("an architecture able to hold 32 bits of integer");
let start = self.oid_lookup_offset + (pos * SHA1_SIZE);
borrowed::Id::try_from(&self.data[start..start + SHA1_SIZE]).expect("20 bytes SHA1 to be alright")
}
pub fn iter_base_graph_ids(&self) -> impl Iterator<Item = borrowed::Id<'_>> {
let base_graphs_list = match self.base_graphs_list_offset {
Some(v) => &self.data[v..v + (SHA1_SIZE * self.base_graph_count as usize)],
None => &[],
};
base_graphs_list
.chunks_exact(SHA1_SIZE)
.map(|bytes| borrowed::Id::try_from(bytes).expect("20 bytes SHA1 to be alright"))
}
pub fn iter_commits(&self) -> impl Iterator<Item = Commit<'_>> {
(0..self.num_commits()).map(move |i| self.commit_at(file::Position(i)))
}
pub fn iter_ids(&self) -> impl Iterator<Item = borrowed::Id<'_>> {
(0..self.num_commits()).map(move |i| self.id_at(file::Position(i)))
}
pub fn lookup(&self, id: borrowed::Id<'_>) -> Option<file::Position> {
let first_byte = id.first_byte() as usize;
let mut upper_bound = self.fan[first_byte];
let mut lower_bound = if first_byte != 0 { self.fan[first_byte - 1] } else { 0 };
while lower_bound < upper_bound {
let mid = (lower_bound + upper_bound) / 2;
let mid_sha = self.id_at(file::Position(mid));
use std::cmp::Ordering::*;
match id.cmp(&mid_sha) {
Less => upper_bound = mid,
Equal => return Some(file::Position(mid)),
Greater => lower_bound = mid + 1,
}
}
None
}
pub fn num_commits(&self) -> u32 {
self.fan[255]
}
pub fn path(&self) -> &Path {
&self.path
}
}
impl File {
pub(crate) fn commit_data_bytes(&self, pos: file::Position) -> &[u8] {
assert!(
pos.0 < self.num_commits(),
"expected lexigraphical position less than {}, got {}",
self.num_commits(),
pos.0
);
let pos: usize = pos
.0
.try_into()
.expect("an architecture able to hold 32 bits of integer");
let start = self.commit_data_offset + (pos * COMMIT_DATA_ENTRY_SIZE);
&self.data[start..start + COMMIT_DATA_ENTRY_SIZE]
}
pub(crate) fn extra_edges_data(&self) -> Option<&[u8]> {
Some(&self.data[self.extra_edges_list_range.clone()?])
}
}
impl Debug for File {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, r#"File("{:?}")"#, self.path.display())
}
}