git_internal/internal/pack/
wrapper.rs1use std::io::{self, BufRead, Read};
5
6use sha1::{Digest, Sha1};
7
8use crate::{
9 hash::{HashKind, ObjectHash, get_hash_kind},
10 utils::HashAlgorithm,
11};
12pub struct Wrapper<R> {
22 inner: R,
23 hash: Option<HashAlgorithm>,
24 bytes_read: usize,
25}
26
27impl<R> Wrapper<R>
28where
29 R: BufRead,
30{
31 pub fn new(inner: R) -> Self {
36 Self {
37 inner,
38 hash: Some(match get_hash_kind() {
39 HashKind::Sha1 => HashAlgorithm::Sha1(Sha1::new()),
40 HashKind::Sha256 => HashAlgorithm::Sha256(sha2::Sha256::new()),
41 }), bytes_read: 0,
43 }
44 }
45
46 pub fn new_without_hash(inner: R) -> Self {
48 Self {
49 inner,
50 hash: None,
51 bytes_read: 0,
52 }
53 }
54
55 pub fn bytes_read(&self) -> usize {
57 self.bytes_read
58 }
59
60 pub fn final_hash(&self) -> ObjectHash {
64 match &self
65 .hash
66 .clone()
67 .expect("Wrapper::final_hash called while hash tracking is disabled")
68 {
69 HashAlgorithm::Sha1(hasher) => {
70 let re: [u8; 20] = hasher.clone().finalize().into(); ObjectHash::from_bytes(&re).unwrap()
72 }
73 HashAlgorithm::Sha256(hasher) => {
74 let re: [u8; 32] = hasher.clone().finalize().into(); ObjectHash::from_bytes(&re).unwrap()
76 }
77 }
78 }
79}
80
81impl<R> BufRead for Wrapper<R>
82where
83 R: BufRead,
84{
85 fn fill_buf(&mut self) -> io::Result<&[u8]> {
87 self.inner.fill_buf() }
89
90 fn consume(&mut self, amt: usize) {
95 let buffer = self.inner.fill_buf().expect("Failed to fill buffer");
96 if let Some(hash) = &mut self.hash {
97 match hash {
98 HashAlgorithm::Sha1(hasher) => hasher.update(&buffer[..amt]), HashAlgorithm::Sha256(hasher) => hasher.update(&buffer[..amt]), }
101 }
102 self.inner.consume(amt); self.bytes_read += amt;
104 }
105}
106
107impl<R> Read for Wrapper<R>
108where
109 R: BufRead,
110{
111 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
120 let o = self.inner.read(buf)?; if let Some(hash) = &mut self.hash {
122 match hash {
123 HashAlgorithm::Sha1(hasher) => hasher.update(&buf[..o]), HashAlgorithm::Sha256(hasher) => hasher.update(&buf[..o]), }
126 }
127 self.bytes_read += o;
128 Ok(o) }
130}
131
132#[cfg(test)]
133mod tests {
134 use std::io::{self, BufReader, Cursor, Read};
135
136 use sha1::{Digest, Sha1};
137
138 use crate::{
139 hash::{HashKind, ObjectHash, set_hash_kind_for_test},
140 internal::pack::wrapper::Wrapper,
141 };
142
143 fn wrapper_read(kind: HashKind) {
145 let _guard = set_hash_kind_for_test(kind);
146 let data = b"Hello, world!"; let cursor = Cursor::new(data.as_ref());
148 let buf_reader = BufReader::new(cursor);
149 let mut wrapper = Wrapper::new(buf_reader);
150
151 let mut buffer = vec![0; data.len()];
152 wrapper.read_exact(&mut buffer).unwrap();
153
154 assert_eq!(buffer, data);
155 }
156
157 #[test]
159 fn test_wrapper_read() {
160 wrapper_read(HashKind::Sha1);
161 wrapper_read(HashKind::Sha256);
162 }
163
164 fn wrapper_hash_with_kind(kind: HashKind) -> io::Result<()> {
166 let _guard = set_hash_kind_for_test(kind);
167 let data = b"Hello, world!";
168 let cursor = Cursor::new(data.as_ref());
169 let buf_reader = BufReader::new(cursor);
170 let mut wrapper = Wrapper::new(buf_reader);
171
172 let mut buffer = vec![0; data.len()];
173 wrapper.read_exact(&mut buffer)?;
174
175 let hash_result = wrapper.final_hash();
176 let expected_hash = match kind {
177 HashKind::Sha1 => ObjectHash::from_bytes(&Sha1::digest(data)).unwrap(),
178 HashKind::Sha256 => ObjectHash::from_bytes(&sha2::Sha256::digest(data)).unwrap(),
179 };
180
181 assert_eq!(hash_result, expected_hash);
182 Ok(())
183 }
184 #[test]
185 fn test_wrapper_hash() -> io::Result<()> {
186 wrapper_hash_with_kind(HashKind::Sha1)?;
187 wrapper_hash_with_kind(HashKind::Sha256)?;
188 Ok(())
189 }
190}