Skip to main content

tiedcrossing_type/digest/
algorithm.rs

1// SPDX-FileCopyrightText: 2022 Profian Inc. <opensource@profian.com>
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use super::{Error, Reader, Writer};
5
6use std::str::FromStr;
7
8use serde::{de::Visitor, Deserialize, Serialize};
9use sha2::{digest::DynDigest, Digest as _, Sha224, Sha256, Sha384, Sha512};
10
11/// A hashing algorithm
12#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[non_exhaustive]
14pub enum Algorithm {
15    Sha224,
16    Sha256,
17    Sha384,
18    Sha512,
19}
20
21impl AsRef<str> for Algorithm {
22    fn as_ref(&self) -> &str {
23        match self {
24            Self::Sha224 => "sha-224",
25            Self::Sha256 => "sha-256",
26            Self::Sha384 => "sha-384",
27            Self::Sha512 => "sha-512",
28        }
29    }
30}
31
32impl std::fmt::Display for Algorithm {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        f.write_str(self.as_ref())
35    }
36}
37
38impl FromStr for Algorithm {
39    type Err = Error;
40
41    fn from_str(s: &str) -> Result<Self, Self::Err> {
42        match &*s.to_ascii_lowercase() {
43            "sha-224" => Ok(Self::Sha224),
44            "sha-256" => Ok(Self::Sha256),
45            "sha-384" => Ok(Self::Sha384),
46            "sha-512" => Ok(Self::Sha512),
47            _ => Err(Error::UnknownAlgorithm),
48        }
49    }
50}
51
52impl Serialize for Algorithm {
53    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
54        self.as_ref().serialize(serializer)
55    }
56}
57
58impl<'de> Deserialize<'de> for Algorithm {
59    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
60        struct StrVisitor;
61
62        impl<'de> Visitor<'de> for StrVisitor {
63            type Value = Algorithm;
64
65            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66                formatter.write_str("a Content-Digest algorithm name")
67            }
68
69            fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
70                v.parse().map_err(|_| E::custom("unknown algorithm"))
71            }
72
73            fn visit_string<E: serde::de::Error>(self, v: String) -> Result<Self::Value, E> {
74                v.parse().map_err(|_| E::custom("unknown algorithm"))
75            }
76        }
77
78        deserializer.deserialize_str(StrVisitor)
79    }
80}
81
82impl Algorithm {
83    pub(crate) fn hasher(self) -> Box<dyn DynDigest> {
84        match self {
85            Self::Sha224 => Box::new(Sha224::new()),
86            Self::Sha256 => Box::new(Sha256::new()),
87            Self::Sha384 => Box::new(Sha384::new()),
88            Self::Sha512 => Box::new(Sha512::new()),
89        }
90    }
91
92    /// Creates a reader instance
93    pub fn reader<T>(&self, reader: T) -> Reader<T> {
94        Reader::new(reader, [*self])
95    }
96
97    /// Creates a writer instance
98    pub fn writer<T>(&self, writer: T) -> Writer<T> {
99        Writer::new(writer, [*self])
100    }
101}