gitoid/
hash_algorithm.rs

1//! Trait specifying valid [`GitOid`] hash algorithms.
2
3use crate::sealed::Sealed;
4use core::{fmt::Debug, hash::Hash, ops::Deref};
5use digest::{block_buffer::generic_array::GenericArray, Digest, OutputSizeUser};
6
7#[cfg(doc)]
8use crate::GitOid;
9
10/// Hash algorithms that can be used to make a [`GitOid`].
11///
12/// This is a sealed trait to ensure it's only used for hash
13/// algorithms which are actually supported by Git.
14///
15/// For more information on sealed traits, read Predrag
16/// Gruevski's ["A Definitive Guide to Sealed Traits in Rust"][1].
17///
18/// [1]: https://predr.ag/blog/definitive-guide-to-sealed-traits-in-rust/
19pub trait HashAlgorithm: Sealed {
20    /// The name of the hash algorithm in lowercase ASCII.
21    #[doc(hidden)]
22    const NAME: &'static str;
23
24    /// The actual digest type used by the algorithm.
25    #[doc(hidden)]
26    type Alg: Digest;
27
28    /// The array type generated by the hash.
29    #[doc(hidden)]
30    type Array: Copy + PartialEq + Ord + Hash + Debug + Deref<Target = [u8]>;
31
32    /// Helper function to convert the GenericArray type to Self::Array
33    #[doc(hidden)]
34    fn array_from_generic(
35        arr: GenericArray<u8, <Self::Alg as OutputSizeUser>::OutputSize>,
36    ) -> Self::Array;
37
38    /// Get an instance of the digester.
39    #[doc(hidden)]
40    fn new() -> Self::Alg;
41}
42
43#[doc(hidden)]
44#[macro_export]
45#[allow(unused_macros)]
46macro_rules! impl_hash_algorithm {
47    ( $type:ident, $alg_ty:ty, $name:literal ) => {
48        impl Sealed for $type {}
49
50        impl HashAlgorithm for $type {
51            const NAME: &'static str = $name;
52
53            type Alg = $alg_ty;
54
55            type Array = GenericArray<u8, <Self::Alg as OutputSizeUser>::OutputSize>;
56
57            fn array_from_generic(
58                arr: GenericArray<u8, <Self::Alg as OutputSizeUser>::OutputSize>,
59            ) -> Self::Array {
60                arr
61            }
62
63            fn new() -> Self::Alg {
64                Self::Alg::new()
65            }
66        }
67    };
68}