gix_worktree_stream/
entry.rs1use std::{
2 io::{ErrorKind, Read},
3 path::PathBuf,
4};
5
6use gix_error::ErrorExt;
7use gix_object::bstr::BStr;
8
9use crate::{protocol, Entry, Stream};
10
11pub type Error = gix_error::Exn<gix_error::Message>;
13
14impl Stream {
15 pub fn next_entry(&mut self) -> Result<Option<Entry<'_>>, Error> {
17 assert!(
18 self.path_buf.is_some(),
19 "BUG: must consume and drop entry before getting the next one"
20 );
21 self.extra_entries.take();
22 let res = protocol::read_entry_info(
23 &mut self.read,
24 self.path_buf.as_mut().expect("set while producing an entry"),
25 );
26 match res {
27 Ok((remaining, mode, id)) => {
28 if let Some(err) = self.err.lock().take() {
29 return Err(err);
30 }
31 Ok(Some(Entry {
32 path_buf: self.path_buf.take(),
33 parent: self,
34 id,
35 mode,
36 remaining,
37 }))
38 }
39 Err(err) => {
40 if let Some(err) = self.err.lock().take() {
41 return Err(err);
42 }
43 if err.kind() == ErrorKind::UnexpectedEof {
45 return Ok(None);
46 }
47 Err(err.and_raise(gix_error::message("Could not read stream entry")))
48 }
49 }
50 }
51}
52
53pub enum Source {
55 Null,
57 Path(PathBuf),
59 Memory(Vec<u8>),
61}
62
63impl Source {
64 pub(crate) fn len(&self) -> Option<usize> {
65 match self {
66 Source::Null => Some(0),
67 Source::Path(_) => None,
68 Source::Memory(buf) => Some(buf.len()),
69 }
70 }
71}
72
73impl std::fmt::Debug for Entry<'_> {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 f.debug_struct("Entry")
76 .field("path_buf", &self.relative_path())
77 .field("mode", &self.mode)
78 .field("id", &self.id)
79 .field("remaining", &self.remaining)
80 .finish()
81 }
82}
83
84impl Entry<'_> {
85 pub fn relative_path(&self) -> &BStr {
87 self.path_buf.as_ref().expect("always set during our lifetime").as_ref()
88 }
89
90 pub fn bytes_remaining(&self) -> Option<usize> {
94 self.remaining
95 }
96}
97
98impl Drop for Entry<'_> {
99 fn drop(&mut self) {
100 if self.remaining == Some(0) {
101 self.parent.path_buf = self.path_buf.take();
102 }
103 }
104}
105
106impl Entry<'_> {
107 fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
108 if self.parent.pos >= self.parent.filled {
109 let mut u16_buf = [0; 2];
110 self.parent.read.read_exact(&mut u16_buf)?;
111 let nb = u16::from_le_bytes(u16_buf) as usize;
112
113 if nb != 0 {
114 self.parent.read.read_exact(&mut self.parent.buf[..nb])?;
115 }
116 self.parent.filled = nb;
117 self.parent.pos = 0;
118 }
119 Ok(&self.parent.buf[self.parent.pos..self.parent.filled])
120 }
121}
122
123impl std::io::Read for Entry<'_> {
124 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
125 let buf_len = buf.len();
126 if let Some(err) = self.parent.err.lock().take() {
127 return Err(std::io::Error::other(err.into_error()));
128 }
129 let bytes_read = match self.remaining.as_mut() {
130 None => {
131 let input = self.fill_buf()?;
134 let nb = input.len().min(buf.len());
135 buf[..nb].copy_from_slice(&input[..nb]);
136 self.parent.pos += nb;
137 nb
138 }
139 Some(remaining) => {
140 let bytes_read = self.parent.read.read(&mut buf[..buf_len.min(*remaining)])?;
141 *remaining -= bytes_read;
142 bytes_read
143 }
144 };
145 if bytes_read == 0 {
146 self.remaining = Some(0);
147 }
148 Ok(bytes_read)
149 }
150}