socket_patch_core/hash/
git_sha256.rs1use sha2::{Digest, Sha256};
2use std::io;
3use tokio::io::AsyncReadExt;
4
5pub fn compute_git_sha256_from_bytes(data: &[u8]) -> String {
9 let mut hasher = Sha256::new();
10 let header = format!("blob {}\0", data.len());
11 hasher.update(header.as_bytes());
12 hasher.update(data);
13 hex::encode(hasher.finalize())
14}
15
16pub async fn compute_git_sha256_from_reader<R: tokio::io::AsyncRead + Unpin>(
20 size: u64,
21 mut reader: R,
22) -> io::Result<String> {
23 let mut hasher = Sha256::new();
24 let header = format!("blob {}\0", size);
25 hasher.update(header.as_bytes());
26
27 let mut buf = [0u8; 8192];
28 loop {
29 let n = reader.read(&mut buf).await?;
30 if n == 0 {
31 break;
32 }
33 hasher.update(&buf[..n]);
34 }
35
36 Ok(hex::encode(hasher.finalize()))
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42
43 #[test]
44 fn test_empty_content() {
45 let hash = compute_git_sha256_from_bytes(b"");
46 assert_eq!(hash.len(), 64);
48 assert_eq!(hash, compute_git_sha256_from_bytes(b""));
50 }
51
52 #[test]
53 fn test_hello_world() {
54 let content = b"Hello, World!";
55 let hash = compute_git_sha256_from_bytes(content);
56 assert_eq!(hash.len(), 64);
57
58 use sha2::{Digest, Sha256};
60 let mut expected_hasher = Sha256::new();
61 expected_hasher.update(b"blob 13\0Hello, World!");
62 let expected = hex::encode(expected_hasher.finalize());
63 assert_eq!(hash, expected);
64 }
65
66 #[test]
67 fn test_known_vector() {
68 use sha2::{Digest, Sha256};
70 let mut hasher = Sha256::new();
71 hasher.update(b"blob 0\0");
72 let expected = hex::encode(hasher.finalize());
73 assert_eq!(compute_git_sha256_from_bytes(b""), expected);
74 }
75
76 #[tokio::test]
77 async fn test_async_reader_matches_sync() {
78 let content = b"test content for async hashing";
79 let sync_hash = compute_git_sha256_from_bytes(content);
80
81 let cursor = tokio::io::BufReader::new(&content[..]);
82 let async_hash =
83 compute_git_sha256_from_reader(content.len() as u64, cursor)
84 .await
85 .unwrap();
86
87 assert_eq!(sync_hash, async_hash);
88 }
89}