Skip to main content

gix_pack/data/input/
entry.rs

1use std::io::Write;
2
3use crate::data::{entry::Header, input};
4
5impl input::Entry {
6    /// Create a new input entry from a given data `obj` set to be placed at the given `pack_offset`,
7    /// deflating its data with `compression`.
8    ///
9    /// This method is useful when arbitrary base entries are created
10    pub fn from_data_obj(
11        obj: &gix_object::Data<'_>,
12        pack_offset: u64,
13        compression: gix_zlib::Compression,
14    ) -> Result<Self, input::Error> {
15        let header = to_header(obj.kind);
16        let compressed = compress_data(obj, compression)?;
17        let compressed_size = compressed.len() as u64;
18        let mut entry = input::Entry {
19            header,
20            header_size: header.size(obj.data.len() as u64) as u16,
21            pack_offset,
22            compressed: Some(compressed),
23            compressed_size,
24            crc32: None,
25            decompressed_size: obj.data.len() as u64,
26            trailer: None,
27        };
28        entry.crc32 = Some(entry.compute_crc32());
29        Ok(entry)
30    }
31    /// The amount of bytes this entry may consume in a pack data file
32    pub fn bytes_in_pack(&self) -> u64 {
33        u64::from(self.header_size) + self.compressed_size
34    }
35
36    /// Update our CRC value by recalculating it from our header and compressed data.
37    pub fn compute_crc32(&self) -> u32 {
38        let mut header_buf = [0u8; 12 + gix_hash::Kind::longest().len_in_bytes()];
39        let header_len = self
40            .header
41            .write_to(self.decompressed_size, &mut header_buf.as_mut())
42            .expect("write to memory will not fail");
43        let state = gix_features::hash::crc32_update(0, &header_buf[..header_len]);
44        gix_features::hash::crc32_update(state, self.compressed.as_ref().expect("we always set it"))
45    }
46}
47
48fn to_header(kind: gix_object::Kind) -> Header {
49    use gix_object::Kind::*;
50    match kind {
51        Tree => Header::Tree,
52        Blob => Header::Blob,
53        Commit => Header::Commit,
54        Tag => Header::Tag,
55    }
56}
57
58fn compress_data(obj: &gix_object::Data<'_>, compression: gix_zlib::Compression) -> Result<Vec<u8>, input::Error> {
59    let mut out = gix_zlib::stream::deflate::Write::new(Vec::new(), compression);
60    if let Err(err) = std::io::copy(&mut &*obj.data, &mut out) {
61        match err.kind() {
62            std::io::ErrorKind::Other => return Err(input::Error::Io(err.into())),
63            err => {
64                unreachable!("Should never see other errors than zlib, but got {:?}", err)
65            }
66        }
67    }
68    out.flush().expect("zlib flush should never fail");
69    Ok(out.into_inner())
70}