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
use std::{
    hash::{Hash, Hasher},
    mem::{discriminant, Discriminant},
};

/// This trait works similarly to [std::hash::Hash] but it gives the liberty of hashing
/// the object's content loosely. This would mean the implementor can skip some parts of
/// the content while calculating the hash.
///
/// As an example, In AST types we ignore fields such as [crate::Span].
pub trait ContentHash {
    fn content_hash<H: Hasher>(&self, state: &mut H);

    /// The default implementation is usually sufficient.
    fn content_hash_slice<H: Hasher>(data: &[Self], state: &mut H)
    where
        Self: Sized,
    {
        for piece in data {
            piece.content_hash(state);
        }
    }
}

/// Short-Circuting implementation for [Discriminant] since it is used to hash enums.
impl<T> ContentHash for Discriminant<T> {
    fn content_hash<H: Hasher>(&self, state: &mut H) {
        Hash::hash(self, state);
    }
}

impl<T: ContentHash> ContentHash for Option<T> {
    fn content_hash<H: Hasher>(&self, state: &mut H) {
        ContentHash::content_hash(&discriminant(self), state);
        if let Some(it) = self {
            ContentHash::content_hash(it, state);
        }
    }
}

impl<'a, T: ContentHash> ContentHash for oxc_allocator::Box<'a, T> {
    fn content_hash<H: Hasher>(&self, state: &mut H) {
        ContentHash::content_hash(self.as_ref(), state);
    }
}

impl<'a, T: ContentHash> ContentHash for oxc_allocator::Vec<'a, T> {
    fn content_hash<H: Hasher>(&self, state: &mut H) {
        ContentHash::content_hash_slice(self.as_slice(), state);
    }
}

mod auto_impl_content_hash {
    use super::ContentHash;

    macro_rules! impl_content_hash {
        ($($t:ty)*) => {
            $(
                impl ContentHash for $t {
                    fn content_hash<H: std::hash::Hasher>(&self, state: &mut H) {
                        std::hash::Hash::hash(self, state);
                    }
                }
            )*
        };
    }

    impl_content_hash! {
        char &str
        bool isize usize
        u8 u16 u32 u64 u128
        i8 i16 i32 i64 i128
    }
}