gix_ref/store/packed/
iter.rs1use gix_object::bstr::{BString, ByteSlice};
2
3use crate::store_impl::{packed, packed::decode};
4
5impl packed::Buffer {
7 pub fn iter(&self) -> Result<packed::Iter<'_>, packed::iter::Error> {
13 packed::Iter::new(self.as_ref(), self.object_hash)
14 }
15
16 pub fn iter_prefixed(&self, prefix: BString) -> Result<packed::Iter<'_>, packed::iter::Error> {
18 let first_record_with_prefix = self.binary_search_by(prefix.as_bstr()).unwrap_or_else(|(_, pos)| pos);
19 packed::Iter::new_with_prefix(
20 &self.as_ref()[first_record_with_prefix..],
21 self.object_hash,
22 Some(prefix),
23 )
24 }
25}
26
27impl<'a> Iterator for packed::Iter<'a> {
28 type Item = Result<packed::Reference<'a>, Error>;
29
30 fn next(&mut self) -> Option<Self::Item> {
31 if self.cursor.is_empty() {
32 return None;
33 }
34
35 let start = self.cursor;
36 match decode::reference(&mut self.cursor, self.object_hash) {
37 Ok(reference) => {
38 self.current_line += 1;
39 if let Some(ref prefix) = self.prefix {
40 if !reference.name.as_bstr().starts_with_str(prefix) {
41 self.cursor = &[];
42 return None;
43 }
44 }
45 Some(Ok(reference))
46 }
47 Err(_) => {
48 self.cursor = start;
49 let (failed_line, next_cursor) = self
50 .cursor
51 .find_byte(b'\n')
52 .map_or((self.cursor, &[][..]), |pos| self.cursor.split_at(pos + 1));
53 self.cursor = next_cursor;
54 let line_number = self.current_line;
55 self.current_line += 1;
56
57 Some(Err(Error::Reference {
58 invalid_line: failed_line
59 .get(..failed_line.len().saturating_sub(1))
60 .unwrap_or(failed_line)
61 .into(),
62 line_number,
63 }))
64 }
65 }
66 }
67}
68
69impl<'a> packed::Iter<'a> {
70 pub fn new(packed: &'a [u8], object_hash: gix_hash::Kind) -> Result<Self, Error> {
73 Self::new_with_prefix(packed, object_hash, None)
74 }
75
76 pub(in crate::store_impl::packed) fn new_with_prefix(
80 packed: &'a [u8],
81 object_hash: gix_hash::Kind,
82 prefix: Option<BString>,
83 ) -> Result<Self, Error> {
84 if packed.is_empty() {
85 Ok(packed::Iter {
86 cursor: packed,
87 object_hash,
88 prefix,
89 current_line: 1,
90 })
91 } else if packed[0] == b'#' {
92 let mut input = packed;
93 decode::header(&mut input).map_err(|_| Error::Header {
94 invalid_first_line: packed.lines().next().unwrap_or(packed).into(),
95 })?;
96 let refs = input;
97 Ok(packed::Iter {
98 cursor: refs,
99 object_hash,
100 prefix,
101 current_line: 2,
102 })
103 } else {
104 Ok(packed::Iter {
105 cursor: packed,
106 object_hash,
107 prefix,
108 current_line: 1,
109 })
110 }
111 }
112}
113
114mod error {
115 use gix_object::bstr::BString;
116
117 #[derive(Debug, thiserror::Error)]
119 #[allow(missing_docs)]
120 pub enum Error {
121 #[error("The header existed but could not be parsed: {invalid_first_line:?}")]
122 Header { invalid_first_line: BString },
123 #[error("Invalid reference in line {line_number}: {invalid_line:?}")]
124 Reference { invalid_line: BString, line_number: usize },
125 }
126}
127
128pub use error::Error;