1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use core::hash::{self, Hash as _, Hasher as _};

#[cfg(feature = "alloc")]
use crate::alloc;
use crate::hash::{Hash, TYPE};
use crate::item::{IntoComponent, ItemBuf};

/// Helper trait used to convert a type into a type hash.
///
/// This is used by [`Hash::type_hash`][crate::hash::Hash::type_hash] to get the
/// type hash of an object.
pub trait ToTypeHash {
    /// Generate a function hash.
    #[doc(hidden)]
    fn to_type_hash(&self) -> Hash;

    /// Optionally convert into an item, if appropriate.
    #[doc(hidden)]
    #[cfg(feature = "alloc")]
    fn to_item(&self) -> alloc::Result<Option<ItemBuf>>;

    /// Hash the current value in-place.
    #[doc(hidden)]
    fn hash_type<H>(&self, hasher: &mut H)
    where
        H: hash::Hasher;
}

impl<I> ToTypeHash for I
where
    I: Copy + IntoIterator,
    I::Item: IntoComponent,
{
    #[inline]
    fn to_type_hash(&self) -> Hash {
        let mut hasher = Hash::new_hasher();
        self.hash_type(&mut hasher);
        Hash::new(hasher.finish())
    }

    #[inline]
    #[cfg(feature = "alloc")]
    fn to_item(&self) -> alloc::Result<Option<ItemBuf>> {
        Ok(Some(ItemBuf::with_item(*self)?))
    }

    #[inline]
    fn hash_type<H>(&self, hasher: &mut H)
    where
        H: hash::Hasher,
    {
        TYPE.hash(hasher);

        for c in *self {
            c.hash_component(hasher);
        }
    }
}

impl ToTypeHash for Hash {
    #[inline]
    fn to_type_hash(&self) -> Hash {
        *self
    }

    #[inline]
    #[cfg(feature = "alloc")]
    fn to_item(&self) -> alloc::Result<Option<ItemBuf>> {
        Ok(None)
    }

    #[inline]
    fn hash_type<H>(&self, hasher: &mut H)
    where
        H: hash::Hasher,
    {
        self.hash(hasher);
    }
}