Skip to main content

tiedcrossing_type/digest/
algorithms.rs

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