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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! an index into the pack file
//!
/// From itertools
/// Create an iterator running multiple iterators in lockstep.
///
/// The `izip!` iterator yields elements until any subiterator
/// returns `None`.
///
/// This is a version of the standard ``.zip()`` that's supporting more than
/// two iterators. The iterator element type is a tuple with one element
/// from each of the input iterators. Just like ``.zip()``, the iteration stops
/// when the shortest of the inputs reaches its end.
///
/// **Note:** The result of this macro is in the general case an iterator
/// composed of repeated `.zip()` and a `.map()`; it has an anonymous type.
/// The special cases of one and two arguments produce the equivalent of
/// `$a.into_iter()` and `$a.into_iter().zip($b)` respectively.
///
/// Prefer this macro `izip!()` over [`multizip`] for the performance benefits
/// of using the standard library `.zip()`.
///
/// [`multizip`]: fn.multizip.html
///
/// ```
/// # use itertools::izip;
/// #
/// # fn main() {
///
/// // iterate over three sequences side-by-side
/// let mut results = [0, 0, 0, 0];
/// let inputs = [3, 7, 9, 6];
///
/// for (r, index, input) in izip!(&mut results, 0..10, &inputs) {
///     *r = index * 10 + input;
/// }
///
/// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]);
/// # }
/// ```
macro_rules! izip {
    // @closure creates a tuple-flattening closure for .map() call. usage:
    // @closure partial_pattern => partial_tuple , rest , of , iterators
    // eg. izip!( @closure ((a, b), c) => (a, b, c) , dd , ee )
    ( @closure $p:pat => $tup:expr ) => {
        |$p| $tup
    };

    // The "b" identifier is a different identifier on each recursion level thanks to hygiene.
    ( @closure $p:pat => ( $($tup:tt)* ) , $_iter:expr $( , $tail:expr )* ) => {
        izip!(@closure ($p, b) => ( $($tup)*, b ) $( , $tail )*)
    };

    // unary
    ($first:expr $(,)*) => {
        std::iter::IntoIterator::into_iter($first)
    };

    // binary
    ($first:expr, $second:expr $(,)*) => {
        izip!($first)
            .zip($second)
    };

    // n-ary where n > 2
    ( $first:expr $( , $rest:expr )* $(,)* ) => {
        izip!($first)
            $(
                .zip($rest)
            )*
            .map(
                izip!(@closure a => (a) $( , $rest )*)
            )
    };
}

use memmap2::Mmap;

/// The version of an index file
#[derive(Default, PartialEq, Eq, Ord, PartialOrd, Debug, Hash, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[allow(missing_docs)]
pub enum Version {
    V1 = 1,
    #[default]
    V2 = 2,
}

impl Version {
    /// The kind of hash to produce to be compatible to this kind of index
    pub fn hash(&self) -> gix_hash::Kind {
        match self {
            Version::V1 | Version::V2 => gix_hash::Kind::Sha1,
        }
    }
}

/// A way to indicate if a lookup, despite successful, was ambiguous or yielded exactly
/// one result in the particular index.
pub type PrefixLookupResult = Result<EntryIndex, ()>;

/// The type for referring to indices of an entry within the index file.
pub type EntryIndex = u32;

const FAN_LEN: usize = 256;

/// A representation of a pack index file
pub struct File {
    data: Mmap,
    path: std::path::PathBuf,
    version: Version,
    num_objects: u32,
    fan: [u32; FAN_LEN],
    hash_len: usize,
    object_hash: gix_hash::Kind,
}

/// Basic file information
impl File {
    /// The version of the pack index
    pub fn version(&self) -> Version {
        self.version
    }
    /// The path of the opened index file
    pub fn path(&self) -> &std::path::Path {
        &self.path
    }
    /// The amount of objects stored in the pack and index, as one past the highest entry index.
    pub fn num_objects(&self) -> EntryIndex {
        self.num_objects
    }
    /// The kind of hash we assume
    pub fn object_hash(&self) -> gix_hash::Kind {
        self.object_hash
    }
}

const V2_SIGNATURE: &[u8] = b"\xfftOc";
///
#[allow(clippy::empty_docs)]
pub mod init;

pub(crate) mod access;
pub use access::Entry;

pub(crate) mod encode;
///
#[allow(clippy::empty_docs)]
pub mod traverse;
mod util;
///
#[allow(clippy::empty_docs)]
pub mod verify;
///
#[cfg(feature = "streaming-input")]
pub mod write;