Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 30 additions & 18 deletions mercury/src/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! location in the Git internal and mega database.
//!

use std::fmt::Display;
use std::{fmt::Display, io};

use colored::Colorize;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -44,7 +44,7 @@ impl Display for SHA1 {
write!(f, "{}", hex::encode(self.0))
}
}
impl AsRef<[u8]> for SHA1{
impl AsRef<[u8]> for SHA1 {
fn as_ref(&self) -> &[u8] {
&self.0
}
Expand Down Expand Up @@ -96,6 +96,9 @@ impl std::str::FromStr for SHA1 {
/// These method naming conventions (`new`, `from`, `to`) provide clarity and predictability in the API, making it easier for users
/// to understand the intended use and functionality of each method within the `SHA1` struct.
impl SHA1 {
// The size of the SHA-1 hash value in bytes
pub const SIZE: usize = 20;

/// Calculate the SHA-1 hash of `Vec<u8>` data, then create a Hash value
pub fn new(data: &Vec<u8>) -> SHA1 {
// Create a Sha1 object for calculating the SHA-1 hash
Expand All @@ -122,11 +125,18 @@ impl SHA1 {
pub fn from_bytes(bytes: &[u8]) -> SHA1 {
let mut h = SHA1::default();
h.0.copy_from_slice(bytes);

h
}

/// Export sha1 value to String with the color
/// Read the Hash value from the stream
/// This function will read exactly 20 bytes from the stream
pub fn from_stream(data: &mut impl io::Read) -> io::Result<SHA1> {
let mut h = SHA1::default();
data.read_exact(&mut h.0)?;
Ok(h)
}

/// Export sha1 value to String with the color
pub fn to_color_str(self) -> String {
self.to_string().red().bold().to_string()
}
Expand All @@ -139,7 +149,7 @@ impl SHA1 {

#[cfg(test)]
mod tests {

use std::io::BufReader;
use std::io::Read;
use std::io::Seek;
Expand Down Expand Up @@ -188,10 +198,18 @@ mod tests {
0xf2, 0x56, 0x7c, 0x36, 0xda, 0x6d,
]);

assert_eq!(
sha1.to_string(),
"8ab686eafeb1f44702738c8b0f24f2567c36da6d"
);
assert_eq!(sha1.to_string(), "8ab686eafeb1f44702738c8b0f24f2567c36da6d");
}

#[test]
fn test_from_stream() {
let source = [
0x8a, 0xb6, 0x86, 0xea, 0xfe, 0xb1, 0xf4, 0x47, 0x02, 0x73, 0x8c, 0x8b, 0x0f, 0x24,
0xf2, 0x56, 0x7c, 0x36, 0xda, 0x6d,
];
let mut reader = std::io::Cursor::new(source);
let sha1 = SHA1::from_stream(&mut reader).unwrap();
assert_eq!(sha1.to_string(), "8ab686eafeb1f44702738c8b0f24f2567c36da6d");
}

#[test]
Expand All @@ -200,10 +218,7 @@ mod tests {

match SHA1::from_str(hash_str) {
Ok(hash) => {
assert_eq!(
hash.to_string(),
"8ab686eafeb1f44702738c8b0f24f2567c36da6d"
);
assert_eq!(hash.to_string(), "8ab686eafeb1f44702738c8b0f24f2567c36da6d");
}
Err(e) => println!("Error: {}", e),
}
Expand All @@ -215,10 +230,7 @@ mod tests {

match SHA1::from_str(hash_str) {
Ok(hash) => {
assert_eq!(
hash.to_string(),
"8ab686eafeb1f44702738c8b0f24f2567c36da6d"
);
assert_eq!(hash.to_string(), "8ab686eafeb1f44702738c8b0f24f2567c36da6d");
}
Err(e) => println!("Error: {}", e),
}
Expand All @@ -227,7 +239,7 @@ mod tests {
#[test]
fn test_sha1_to_data() {
let hash_str = "8ab686eafeb1f44702738c8b0f24f2567c36da6d";

match SHA1::from_str(hash_str) {
Ok(hash) => {
assert_eq!(
Expand Down
2 changes: 1 addition & 1 deletion mercury/src/internal/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ impl Index {
}

// Extensions
while file.bytes_read() + utils::SHA1_SIZE < total_size as usize {
while file.bytes_read() + SHA1::SIZE < total_size as usize {
// The remaining 20 bytes must be checksum
let sign = utils::read_bytes(file, 4)?;
println!("{:?}", String::from_utf8(sign.clone())?);
Expand Down
10 changes: 3 additions & 7 deletions mercury/src/internal/pack/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,11 +301,9 @@ impl Pack {
},
ObjectType::HashDelta => {
// Read 20 bytes to get the reference object SHA1 hash
let mut buf_ref = [0; 20];
pack.read_exact(&mut buf_ref).unwrap();
let ref_sha1 = SHA1::from_bytes(buf_ref.as_ref()); //TODO SHA1::from_stream()
let ref_sha1 = SHA1::from_stream(pack).unwrap();
// Offset is incremented by 20 bytes
*offset += 20; //TODO 改为常量
*offset += SHA1::SIZE;

let (data, raw_size) = self.decompress_data(pack, size)?;
*offset += raw_size;
Expand Down Expand Up @@ -426,9 +424,7 @@ impl Pack {
}
log_info(i, self);
let render_hash = reader.final_hash();
let mut trailer_buf = [0; 20];
reader.read_exact(&mut trailer_buf).unwrap();
self.signature = SHA1::from_bytes(trailer_buf.as_ref());
self.signature = SHA1::from_stream(&mut reader).unwrap();

if render_hash != self.signature {
return Err(GitError::InvalidPackFile(format!(
Expand Down
6 changes: 1 addition & 5 deletions mercury/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@ use std::io::Read;

use crate::hash::SHA1;

pub const SHA1_SIZE: usize = 20;

pub fn read_bytes(file: &mut impl Read, len: usize) -> io::Result<Vec<u8>> {
let mut buf = vec![0; len];
file.read_exact(&mut buf)?;
Ok(buf)
}

pub fn read_sha1(file: &mut impl Read) -> io::Result<SHA1> {
let mut buf = [0; 20];
file.read_exact(&mut buf)?;
Ok(SHA1::from_bytes(&buf))
SHA1::from_stream(file)
}