1mod cancel;
2mod error;
3mod fetcher;
4mod poll;
5mod spec;
6
7use std::fmt::Write as _;
8
9use sha2::{Digest, Sha256};
10
11pub use cancel::CancelToken;
12pub use error::FetchError;
13pub use fetcher::{Fetcher, Timings};
14pub use spec::{FetchProgress, FetchSpec, Request};
15
16pub fn sha256_hex(data: &[u8]) -> String {
17 digest_hex(&Sha256::digest(data))
18}
19
20pub struct StreamHasher(Sha256);
21
22impl StreamHasher {
23 pub fn new() -> Self {
24 StreamHasher(Sha256::new())
25 }
26
27 pub fn update(&mut self, data: &[u8]) {
28 self.0.update(data);
29 }
30
31 pub fn finalize_hex(self) -> String {
32 digest_hex(&self.0.finalize())
33 }
34}
35
36pub(crate) fn digest_hex(bytes: &[u8]) -> String {
37 let mut out = String::with_capacity(bytes.len() * 2);
38 for byte in bytes {
39 write!(out, "{byte:02x}").expect("writing to a String is infallible");
40 }
41 out
42}
43
44impl Default for StreamHasher {
45 fn default() -> Self {
46 Self::new()
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn stream_hasher_matches_whole_input_digest() {
56 let data = payload(500_000);
57 let mut streamed = StreamHasher::new();
58 for chunk in data.chunks(4096) {
59 streamed.update(chunk);
60 }
61 assert_eq!(streamed.finalize_hex(), sha256_hex(&data));
62 }
63
64 fn payload(len: usize) -> Vec<u8> {
65 (0..len)
66 .map(|i| ((i as u32).wrapping_mul(2_654_435_761) >> 16) as u8)
67 .collect()
68 }
69}