git_odb/
sink.rs

1use std::{
2    cell::RefCell,
3    convert::TryInto,
4    io::{self, Write},
5};
6
7use git_features::zlib::stream::deflate;
8
9use crate::Sink;
10
11impl Sink {
12    /// Enable or disable compression. Compression is disabled by default
13    pub fn compress(mut self, enable: bool) -> Self {
14        if enable {
15            self.compressor = Some(RefCell::new(deflate::Write::new(io::sink())));
16        } else {
17            self.compressor = None;
18        }
19        self
20    }
21}
22
23impl crate::traits::Write for Sink {
24    type Error = io::Error;
25
26    fn write_stream(
27        &self,
28        kind: git_object::Kind,
29        size: u64,
30        mut from: impl io::Read,
31    ) -> Result<git_hash::ObjectId, Self::Error> {
32        let mut size = size.try_into().expect("object size to fit into usize");
33        use git_features::hash::Sha1;
34        let mut buf = [0u8; 8096];
35        let header = git_object::encode::loose_header(kind, size);
36
37        let possibly_compress = |buf: &[u8]| -> io::Result<()> {
38            if let Some(compressor) = self.compressor.as_ref() {
39                compressor.try_borrow_mut().expect("no recursion").write_all(buf)?;
40            }
41            Ok(())
42        };
43        match self.object_hash {
44            git_hash::Kind::Sha1 => {
45                let mut hasher = Sha1::default();
46                hasher.update(&header);
47                possibly_compress(&header)?;
48
49                while size != 0 {
50                    let bytes = size.min(buf.len());
51                    from.read_exact(&mut buf[..bytes])?;
52                    hasher.update(&buf[..bytes]);
53                    possibly_compress(&buf[..bytes])?;
54                    size -= bytes;
55                }
56                if let Some(compressor) = self.compressor.as_ref() {
57                    let mut c = compressor.borrow_mut();
58                    c.flush()?;
59                    c.reset();
60                }
61
62                Ok(hasher.digest().into())
63            }
64        }
65    }
66}