rc_zip_sync/
entry_reader.rs1use rc_zip::{
2 fsm::{EntryFsm, FsmResult},
3 parse::Entry,
4};
5use std::io;
6use tracing::trace;
7
8pub struct EntryReader<R>
10where
11 R: io::Read,
12{
13 rd: R,
14 fsm: Option<EntryFsm>,
15}
16
17impl<R> EntryReader<R>
18where
19 R: io::Read,
20{
21 pub(crate) fn new(entry: &Entry, rd: R) -> Self {
22 Self {
23 rd,
24 fsm: Some(EntryFsm::new(Some(entry.clone()), None)),
25 }
26 }
27}
28
29impl<R> io::Read for EntryReader<R>
30where
31 R: io::Read,
32{
33 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
34 loop {
35 let mut fsm = match self.fsm.take() {
36 Some(fsm) => fsm,
37 None => return Ok(0),
38 };
39
40 #[allow(clippy::needless_late_init)] let filled_bytes;
42 if fsm.wants_read() {
43 tracing::trace!(space_avail = fsm.space().len(), "fsm wants read");
44 let n = self.rd.read(fsm.space())?;
45 fsm.fill(n);
46 filled_bytes = n;
47 } else {
48 trace!("fsm does not want read");
49 filled_bytes = 0;
50 }
51
52 match fsm.process(buf)? {
53 FsmResult::Continue((fsm, outcome)) => {
54 self.fsm = Some(fsm);
55
56 if outcome.bytes_written > 0 {
57 tracing::trace!("wrote {} bytes", outcome.bytes_written);
58 return Ok(outcome.bytes_written);
59 } else if filled_bytes > 0 || outcome.bytes_read > 0 {
60 continue;
62 } else {
63 return Err(io::Error::new(
64 io::ErrorKind::Other,
65 "entry reader: no progress",
66 ));
67 }
68 }
69 FsmResult::Done(_) => {
70 return Ok(0);
72 }
73 }
74 }
75 }
76}