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