drawbridge_type/digest/
algorithms.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use super::{Algorithm, ContentDigest, Reader, Writer};
4
5use std::collections::BTreeSet;
6use std::ops::{Deref, DerefMut};
7
8use futures::io::{self, copy, sink, AsyncRead};
9use serde::{Deserialize, Serialize};
10
11/// A set of hashing algorithms
12#[derive(Clone, Debug, Serialize, Deserialize)]
13pub struct Algorithms(BTreeSet<Algorithm>);
14
15impl Default for Algorithms {
16    fn default() -> Self {
17        let mut set = BTreeSet::new();
18        assert!(set.insert(Algorithm::Sha224));
19        assert!(set.insert(Algorithm::Sha256));
20        assert!(set.insert(Algorithm::Sha384));
21        assert!(set.insert(Algorithm::Sha512));
22        Self(set)
23    }
24}
25
26impl From<BTreeSet<Algorithm>> for Algorithms {
27    fn from(value: BTreeSet<Algorithm>) -> Self {
28        Self(value)
29    }
30}
31
32impl Deref for Algorithms {
33    type Target = BTreeSet<Algorithm>;
34
35    fn deref(&self) -> &Self::Target {
36        &self.0
37    }
38}
39
40impl DerefMut for Algorithms {
41    fn deref_mut(&mut self) -> &mut Self::Target {
42        &mut self.0
43    }
44}
45
46impl Algorithms {
47    /// Creates a reader instance
48    pub fn reader<T>(&self, reader: T) -> Reader<T> {
49        Reader::new(reader, self.iter().cloned())
50    }
51
52    /// Creates a writer instance
53    pub fn writer<T>(&self, writer: T) -> Writer<T> {
54        Writer::new(writer, self.iter().cloned())
55    }
56
57    /// Calculates a digest from an async reader
58    pub async fn read(&self, reader: impl Unpin + AsyncRead) -> io::Result<(u64, ContentDigest)> {
59        let mut r = self.reader(reader);
60        let n = copy(&mut r, &mut sink()).await?;
61        Ok((n, r.digests()))
62    }
63
64    /// Calculates a digest from a sync reader
65    pub fn read_sync(&self, reader: impl std::io::Read) -> io::Result<(u64, ContentDigest)> {
66        let mut r = self.reader(reader);
67        let n = std::io::copy(&mut r, &mut std::io::sink())?;
68        Ok((n, r.digests()))
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[async_std::test]
77    async fn digest() {
78        let algorithms = Algorithms::default();
79        let rdr = &b"foo"[..];
80        let content_digest = "sha-224=:CAj2TmDViXn8tnbJbsk4Jw3qQkRa7vzTpOb42w==:,sha-256=:LCa0a2j/xo/5m0U8HTBBNBNCLXBkg7+g+YpeiGJm564=:,sha-384=:mMEf/f3VQGdrGhN8saIrKnA1DJpEFx1rEYDGvly7LuP3nVMsih3Z7y6OCOdSo7q7:,sha-512=:9/u6bgY2+JDlb7vzKD5STG+jIErimDgtYkdB0NxmODJuKCxBvl5CVNiCB3LFUYosWowMf37aGVlKfrU5RT4e1w==:"
81                .parse::<ContentDigest>()
82                .unwrap();
83        assert_eq!(
84            algorithms.read(rdr).await.unwrap(),
85            ("foo".len() as _, content_digest.clone())
86        );
87        assert_eq!(
88            algorithms.read_sync(rdr).unwrap(),
89            ("foo".len() as _, content_digest)
90        );
91    }
92}