1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
use git_object::borrowed;

pub struct Object<'a> {
    pub kind: git_object::Kind,
    pub data: &'a [u8],
}

impl<'a> Object<'a> {
    pub fn decode(&self) -> Result<borrowed::Object, borrowed::Error> {
        Ok(match self.kind {
            git_object::Kind::Tree => borrowed::Object::Tree(borrowed::Tree::from_bytes(self.data)?),
            git_object::Kind::Blob => borrowed::Object::Blob(borrowed::Blob { data: self.data }),
            git_object::Kind::Commit => borrowed::Object::Commit(borrowed::Commit::from_bytes(self.data)?),
            git_object::Kind::Tag => borrowed::Object::Tag(borrowed::Tag::from_bytes(self.data)?),
        })
    }
}

pub mod verify {
    use crate::{hash, loose, pack};
    use git_object::{borrowed, owned};
    use quick_error::quick_error;
    use std::io;

    quick_error! {
        #[derive(Debug)]
        pub enum Error {
            ChecksumMismatch(desired: owned::Id, actual: owned::Id) {
                display("Object expected to have id {}, but actual id was {}", desired, actual)
            }
        }
    }

    impl pack::Object<'_> {
        pub fn verify_checksum(&self, desired: borrowed::Id) -> Result<(), Error> {
            let mut sink = hash::Write::new(io::sink(), desired.kind());

            loose::object::header::encode(self.kind, self.data.len() as u64, &mut sink).expect("hash to always work");
            sink.hash.update(&self.data);

            let actual_id = owned::Id::from(sink.hash.digest());
            if desired != actual_id.to_borrowed() {
                return Err(Error::ChecksumMismatch(desired.into(), actual_id));
            }
            Ok(())
        }
    }
}