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 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}