gix_ref/store/packed/
iter.rs1use gix_error::{ErrorExt, ExnMessageResult, Message, corruption};
2
3use gix_object::bstr::{BString, ByteSlice};
4
5use crate::store_impl::{packed, packed::decode};
6
7impl packed::Buffer {
9 pub fn iter(&self) -> ExnMessageResult<packed::Iter<'_>> {
17 packed::Iter::new(self.as_ref(), self.object_hash)
18 }
19
20 pub fn iter_prefixed(&self, prefix: BString) -> ExnMessageResult<packed::Iter<'_>> {
24 let first_record_with_prefix = self.binary_search_by(prefix.as_bstr()).unwrap_or_else(|(_, pos)| pos);
25 packed::Iter::new_with_prefix(
26 &self.as_ref()[first_record_with_prefix..],
27 self.object_hash,
28 Some(prefix),
29 )
30 }
31}
32
33impl<'a> Iterator for packed::Iter<'a> {
34 type Item = ExnMessageResult<packed::Reference<'a>>;
35
36 fn next(&mut self) -> Option<Self::Item> {
39 if self.cursor.is_empty() {
40 return None;
41 }
42
43 let start = self.cursor;
44 match decode::reference(&mut self.cursor, self.object_hash) {
45 Ok(reference) => {
46 self.current_line += 1 + usize::from(reference.object.is_some());
47 if let Some(ref prefix) = self.prefix
48 && !reference.name.as_bstr().starts_with_str(prefix)
49 {
50 self.cursor = &[];
51 return None;
52 }
53 Some(Ok(reference))
54 }
55 Err(err) => {
56 self.cursor = start;
57 let (failed_line, next_cursor) = self
58 .cursor
59 .find_byte(b'\n')
60 .map_or((self.cursor, &[][..]), |pos| self.cursor.split_at(pos + 1));
61 self.cursor = next_cursor;
62 let line_number = self.current_line;
63 self.current_line += 1;
64
65 Some(Err(err.raise(
66 Message::new("Invalid packed reference")
67 .with("input", failed_line.strip_suffix(b"\n").unwrap_or(failed_line))
68 .with("line", line_number),
69 )))
70 }
71 }
72 }
73}
74
75impl<'a> packed::Iter<'a> {
76 pub fn new(packed: &'a [u8], object_hash: gix_hash::Kind) -> ExnMessageResult<Self> {
81 Self::new_with_prefix(packed, object_hash, None)
82 }
83
84 pub(in crate::store_impl::packed) fn new_with_prefix(
90 packed: &'a [u8],
91 object_hash: gix_hash::Kind,
92 prefix: Option<BString>,
93 ) -> ExnMessageResult<Self> {
94 if packed.is_empty() {
95 Ok(packed::Iter {
96 cursor: packed,
97 object_hash,
98 prefix,
99 current_line: 1,
100 })
101 } else if packed[0] == b'#' {
102 let mut input = packed;
103 decode::header(&mut input).map_err(|()| {
104 corruption("Invalid packed reference header")
105 .with("input", packed.lines().next().unwrap_or(packed))
106 .raise()
107 })?;
108 let refs = input;
109 Ok(packed::Iter {
110 cursor: refs,
111 object_hash,
112 prefix,
113 current_line: 2,
114 })
115 } else {
116 Ok(packed::Iter {
117 cursor: packed,
118 object_hash,
119 prefix,
120 current_line: 1,
121 })
122 }
123 }
124}