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
//! Operations on a single commit-graph file.

use std::{
    fmt::{Display, Formatter},
    ops::Range,
    path::PathBuf,
};

use filebuffer::FileBuffer;
use git_hash::SIZE_OF_SHA1_DIGEST as SHA1_SIZE;

pub use self::{commit::Commit, init::Error};

mod access;
pub mod commit;
mod init;
pub mod verify;

const CHUNK_LOOKUP_SIZE: usize = 12;
const COMMIT_DATA_ENTRY_SIZE: usize = SHA1_SIZE + 16;
const FAN_LEN: usize = 256;
const HEADER_LEN: usize = 8;
const OID_LOOKUP_ENTRY_SIZE: usize = SHA1_SIZE;

const SIGNATURE: &[u8] = b"CGPH";

type ChunkId = [u8; 4];
const BASE_GRAPHS_LIST_CHUNK_ID: ChunkId = *b"BASE";
const COMMIT_DATA_CHUNK_ID: ChunkId = *b"CDAT";
const EXTENDED_EDGES_LIST_CHUNK_ID: ChunkId = *b"EDGE";
const OID_FAN_CHUNK_ID: ChunkId = *b"OIDF";
const OID_LOOKUP_CHUNK_ID: ChunkId = *b"OIDL";
const SENTINEL_CHUNK_ID: ChunkId = [0u8; 4];

// Note that git's commit-graph-format.txt as of v2.28.0 gives an incorrect value 0x0700_0000 for
// NO_PARENT. Fixed in https://github.com/git/git/commit/4d515253afcef985e94400adbfed7044959f9121 .
const NO_PARENT: u32 = 0x7000_0000;
const EXTENDED_EDGES_MASK: u32 = 0x8000_0000;
const LAST_EXTENDED_EDGE_MASK: u32 = 0x8000_0000;

/// A single commit-graph file.
///
/// All operations on a `File` are local to that graph file. Since a commit graph can span multiple
/// files, all interesting graph operations belong on [`Graph`][crate::Graph].
pub struct File {
    base_graph_count: u8,
    base_graphs_list_offset: Option<usize>,
    commit_data_offset: usize,
    data: FileBuffer,
    extra_edges_list_range: Option<Range<usize>>,
    fan: [u32; FAN_LEN],
    oid_lookup_offset: usize,
    path: PathBuf,
}

/// The position of a given commit within a graph file, starting at 0.
///
/// Commits within a graph file are sorted in lexicographical order by OID; a commit's lexigraphical position
/// is its position in this ordering. If a commit graph spans multiple files, each file's commits
/// start at lexigraphical position 0, so it is unique across a single file but is not unique across
/// the whole commit graph. Each commit also has a graph position ([`graph::Position`][crate::graph::Position]),
/// which is unique /// across the whole commit graph. In order to avoid accidentally mixing lexigraphical positions with graph
/// positions, distinct types are used for each.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Position(pub u32);

impl Display for Position {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        self.0.fmt(f)
    }
}