Skip to main content

fetch/
lib.rs

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}