async_sevenz/writer/
source_reader.rs

1use futures_lite::io::AsyncRead;
2
3use crc32fast::Hasher;
4
5/// A wrapper around a reader that tracks read count and CRC32.
6///
7/// Used during compression to track how much data has been read and compute
8/// the CRC32 checksum of the data.
9pub struct SourceReader<R> {
10    reader: R,
11    size: usize,
12    crc: Hasher,
13    crc_value: u32,
14}
15
16impl<R> From<R> for SourceReader<R> {
17    fn from(value: R) -> Self {
18        Self::new(value)
19    }
20}
21
22impl<R: AsyncRead + Unpin> AsyncRead for SourceReader<R> {
23    fn poll_read(
24        mut self: std::pin::Pin<&mut Self>,
25        cx: &mut std::task::Context<'_>,
26        buf: &mut [u8],
27    ) -> std::task::Poll<std::io::Result<usize>> {
28        let poll = std::pin::Pin::new(&mut self.reader).poll_read(cx, buf);
29        if let std::task::Poll::Ready(Ok(n)) = &poll {
30            if self.crc_value == 0 {
31                if *n > 0 {
32                    self.size += *n;
33                    self.crc.update(&buf[..*n]);
34                } else {
35                    let crc = std::mem::replace(&mut self.crc, Hasher::new());
36                    self.crc_value = crc.finalize();
37                }
38            }
39        }
40        poll
41    }
42}
43
44impl<R> SourceReader<R> {
45    /// Creates a new source reader wrapper.
46    ///
47    /// # Arguments
48    /// * `reader` - The underlying reader to wrap
49    pub fn new(reader: R) -> Self {
50        Self {
51            reader,
52            size: 0,
53            crc: Hasher::new(),
54            crc_value: 0,
55        }
56    }
57
58    /// Returns the total number of bytes read so far.
59    pub fn read_count(&self) -> usize {
60        self.size
61    }
62
63    /// Returns the CRC32 value of all data read.
64    ///
65    /// The CRC is only computed once all data has been read (when read returns 0).
66    pub fn crc_value(&self) -> u32 {
67        self.crc_value
68    }
69}