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