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
use std::path::PathBuf;

use gix_hash::ObjectId;
use gix_object::bstr::{BStr, BString};
use memmap2::Mmap;

use crate::{file, transaction::RefEdit, FullNameRef, Namespace};

#[derive(Debug)]
enum Backing {
    /// The buffer is loaded entirely in memory, along with the `offset` to the first record past the header.
    InMemory(Vec<u8>),
    /// The buffer is mapping the file on disk, along with the offset to the first record past the header
    Mapped(Mmap),
}

/// A buffer containing a packed-ref file that is either memory mapped or fully in-memory depending on a cutoff.
///
/// The buffer is guaranteed to be sorted as per the packed-ref rules which allows some operations to be more efficient.
#[derive(Debug)]
pub struct Buffer {
    data: Backing,
    /// The offset to the first record, how many bytes to skip past the header
    offset: usize,
    /// The path from which we were loaded
    path: PathBuf,
}

struct Edit {
    inner: RefEdit,
    peeled: Option<ObjectId>,
}

/// A transaction for editing packed references
pub(crate) struct Transaction {
    buffer: Option<file::packed::SharedBufferSnapshot>,
    edits: Option<Vec<Edit>>,
    lock: Option<gix_lock::File>,
    #[allow(dead_code)] // It just has to be kept alive, hence no reads
    closed_lock: Option<gix_lock::Marker>,
    precompose_unicode: bool,
    /// The namespace to use when preparing or writing refs
    namespace: Option<Namespace>,
}

/// A reference as parsed from the `packed-refs` file
#[derive(Debug, PartialEq, Eq)]
pub struct Reference<'a> {
    /// The validated full name of the reference.
    pub name: &'a FullNameRef,
    /// The target object id of the reference, hex encoded.
    pub target: &'a BStr,
    /// The fully peeled object id, hex encoded, that the ref is ultimately pointing to
    /// i.e. when all indirections are removed.
    pub object: Option<&'a BStr>,
}

impl<'a> Reference<'a> {
    /// Decode the target as object
    pub fn target(&self) -> ObjectId {
        gix_hash::ObjectId::from_hex(self.target).expect("parser validation")
    }

    /// Decode the object this reference is ultimately pointing to. Note that this is
    /// the [`target()`][Reference::target()] if this is not a fully peeled reference like a tag.
    pub fn object(&self) -> ObjectId {
        self.object.map_or_else(
            || self.target(),
            |id| ObjectId::from_hex(id).expect("parser validation"),
        )
    }
}

/// An iterator over references in a packed refs file
pub struct Iter<'a> {
    /// The position at which to parse the next reference
    cursor: &'a [u8],
    /// The next line, starting at 1
    current_line: usize,
    /// If set, references returned will match the prefix, the first failed match will stop all iteration.
    prefix: Option<BString>,
}

mod decode;

///
#[allow(clippy::empty_docs)]
pub mod iter;

///
#[allow(clippy::empty_docs)]
pub mod buffer;

///
#[allow(clippy::empty_docs)]
pub mod find;

///
#[allow(clippy::empty_docs)]
pub mod transaction;