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
use crate::{compound, loose, pack};
use git_object::borrowed;

/// Returned by [`compound::Db::locate()`]
#[derive(thiserror::Error, Debug)]
#[allow(missing_docs)]
pub enum Error {
    #[error("An error occurred while obtaining an object from the loose object store")]
    Loose(#[from] loose::db::locate::Error),
    #[error("An error occurred while obtaining an object from the packed object store")]
    Pack(#[from] pack::data::decode::Error),
}

impl compound::Db {
    /// Find an object as identified by [`id`][borrowed::Id] and store its data in full in the provided `buffer`.
    /// This will search the object in all contained object databases.
    pub fn locate<'a>(
        &self,
        id: borrowed::Id<'_>,
        buffer: &'a mut Vec<u8>,
    ) -> Option<Result<compound::Object<'a>, Error>> {
        for alternate in &self.alternates {
            // See 8c5bd095539042d7db0e611460803cdbf172beb0 for a commit that adds polonius and makes the proper version compile.
            // See https://stackoverflow.com/questions/63906425/nll-limitation-how-to-work-around-cannot-borrow-buf-as-mutable-more-than?noredirect=1#comment113007288_63906425
            // More see below! Of course we don't want to do the lookup twice… but have to until this is fixed or we compile nightly.
            if alternate.locate(id, buffer).is_some() {
                return alternate.locate(id, buffer);
            }
        }
        for pack in &self.packs {
            // See 8c5bd095539042d7db0e611460803cdbf172beb0 for a commit that adds polonius and makes the proper version compile.
            // See https://stackoverflow.com/questions/63906425/nll-limitation-how-to-work-around-cannot-borrow-buf-as-mutable-more-than?noredirect=1#comment113007288_63906425
            // The underlying issue is described here https://github.com/rust-lang/rust/issues/45402,
            // Once Polonius becomes a thing AND is not too slow, we must remove this double-lookup to become something like this:
            // if let Some(object) = if pack.locate(id, buffer, &mut pack::cache::DecodeEntryNoop) {…}
            if pack.locate(id, buffer, &mut pack::cache::Noop).is_some() {
                let object = pack.locate(id, buffer, &mut pack::cache::Noop).unwrap();
                return Some(object.map(compound::Object::Borrowed).map_err(Into::into));
            }
        }
        self.loose
            .locate(id)
            .map(|object| object.map(compound::Object::Loose).map_err(Into::into))
    }
}