gix_ref/store/packed/
find.rs1use gix_error::{ErrorExt, ExnResult, Message, ResultExt, message};
2
3use gix_object::bstr::{BStr, BString};
4
5use crate::{FullNameRef, PartialNameRef, store_impl::packed};
6
7impl packed::Buffer {
9 pub fn try_find<'a, Name, E>(&self, name: Name) -> ExnResult<Option<packed::Reference<'_>>>
14 where
15 Name: TryInto<&'a PartialNameRef, Error = E>,
16 Result<&'a PartialNameRef, E>: ResultExt<Success = &'a PartialNameRef>,
17 {
18 let name = name
19 .try_into()
20 .or_raise_erased(|| message("The ref name or path is not a valid ref name"))?;
21 let mut buf = BString::default();
22 for inbetween in &["", "tags", "heads", "remotes"] {
23 let (name, was_absolute) = if name.looks_like_full_name(false) {
24 let name = FullNameRef::new_unchecked(name.as_bstr());
25 let name = match transform_full_name_for_lookup(name) {
26 None => return Ok(None),
27 Some(name) => name,
28 };
29 (name, true)
30 } else {
31 let full_name = name.construct_full_name_ref(inbetween, &mut buf, false);
32 (full_name, false)
33 };
34 match self.try_find_full_name(name)? {
35 Some(r) => return Ok(Some(r)),
36 None if was_absolute => return Ok(None),
37 None => continue,
38 }
39 }
40 Ok(None)
41 }
42
43 pub(crate) fn try_find_full_name(&self, name: &FullNameRef) -> ExnResult<Option<packed::Reference<'_>>> {
46 match self.binary_search_by(name.as_bstr()) {
47 Ok(line_start) => {
48 let mut input = &self.as_ref()[line_start..];
49 packed::decode::reference(&mut input, self.object_hash).map(Some)
50 }
51 Err((parse_failure, _)) => {
52 if parse_failure {
53 Err(gix_error::corruption("Malformed packed reference record").raise())
54 } else {
55 Ok(None)
56 }
57 }
58 }
59 .or_raise_erased(|| Message::new("Could not decode packed reference").with("name", name.as_bstr()))
60 }
61
62 pub fn find<'a, Name, E>(&self, name: Name) -> ExnResult<packed::Reference<'_>>
64 where
65 Name: TryInto<&'a PartialNameRef, Error = E>,
66 Result<&'a PartialNameRef, E>: ResultExt<Success = &'a PartialNameRef>,
67 {
68 let name = name
69 .try_into()
70 .or_raise_erased(|| message("The ref name or path is not a valid ref name"))?;
71 self.try_find::<_, std::convert::Infallible>(name)?.ok_or_else(|| {
72 crate::file::find::NotFound {
73 name: name.to_partial_path().to_owned(),
74 }
75 .raise_erased()
76 })
77 }
78
79 pub(in crate::store_impl::packed) fn binary_search_by(&self, full_name: &BStr) -> Result<usize, (bool, usize)> {
82 let a = self.as_ref();
83 let mut encountered_parse_failure = false;
84 a.binary_search_by_key(&full_name.as_ref(), |b: &u8| {
85 let ofs = std::ptr::from_ref::<u8>(b) as usize - a.as_ptr() as usize;
86 let line = packed::decode::record_at_offset(a, ofs);
87 match packed::decode::name_at_record_start(line, self.object_hash) {
92 Some(name) => name,
93 None => {
94 encountered_parse_failure = true;
95 &[]
96 }
97 }
98 })
99 .map(|pos| packed::decode::record_start_at_offset(a, pos))
100 .map_err(|pos| {
101 (
102 encountered_parse_failure,
103 packed::decode::record_start_at_offset(a, pos),
104 )
105 })
106 }
107}
108
109pub(crate) fn transform_full_name_for_lookup(name: &FullNameRef) -> Option<&FullNameRef> {
110 match name.category_and_short_name() {
111 Some((c, sn)) => {
112 use crate::Category::*;
113 Some(match c {
114 MainRef | LinkedRef { .. } => FullNameRef::new_unchecked(sn),
115 Tag | RemoteBranch | LocalBranch | Bisect | Rewritten | Note => name,
116 MainPseudoRef | PseudoRef | LinkedPseudoRef { .. } | WorktreePrivate => return None,
117 })
118 }
119 None => Some(name),
120 }
121}