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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use std::hash::{Hash, Hasher};

use crate::block::Block;
use crate::class::Class;
use crate::instance::Instance;
use crate::method::Method;
use crate::value::Value;

impl Hash for Value {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        match self {
            Value::Nil => {
                hasher.write(b"#nil#");
            }
            Value::System => {
                hasher.write(b"#system#");
            }
            Value::Boolean(value) => {
                hasher.write(b"#bool#");
                value.hash(hasher);
            }
            Value::Integer(value) => {
                hasher.write(b"#int#");
                value.hash(hasher);
            }
            Value::BigInteger(value) => {
                hasher.write(b"#bigint#");
                value.hash(hasher);
            }
            Value::Double(value) => {
                hasher.write(b"#double#");
                let raw_bytes: &[u8] = unsafe {
                    std::slice::from_raw_parts(
                        (value as *const f64) as *const u8,
                        std::mem::size_of::<f64>(),
                    )
                };
                hasher.write(raw_bytes);
            }
            Value::Symbol(value) => {
                hasher.write(b"#sym#");
                value.hash(hasher);
            }
            Value::String(value) => {
                hasher.write(b"#string#");
                value.hash(hasher);
            }
            Value::Array(value) => {
                hasher.write(b"#arr#");
                for value in value.borrow().iter() {
                    value.hash(hasher);
                }
            }
            Value::Block(value) => {
                hasher.write(b"#blk#");
                value.hash(hasher);
            }
            Value::Class(value) => {
                hasher.write(b"#cls#");
                value.borrow().hash(hasher);
            }
            Value::Instance(value) => {
                hasher.write(b"#inst#");
                value.borrow().hash(hasher);
            }
            Value::Invokable(value) => {
                hasher.write(b"#mthd#");
                value.hash(hasher);
            }
        }
    }
}

impl Hash for Class {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.name.hash(hasher);
        self.locals.iter().for_each(|value| {
            value.hash(hasher);
        });
    }
}

impl Hash for Instance {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.class.borrow().hash(hasher);
        self.locals.iter().for_each(|value| {
            value.hash(hasher);
        });
    }
}

impl Hash for Block {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.blk_info.literals.iter().for_each(|it| it.hash(hasher));
        self.blk_info.locals.iter().for_each(|it| it.hash(hasher));
        self.blk_info.nb_params.hash(hasher);
        self.blk_info.body.iter().for_each(|it| it.hash(hasher));
    }
}

impl Hash for Method {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        if let Some(holder) = self.holder().upgrade() {
            holder.borrow().hash(hasher);
        } else {
            hasher.write(b"??");
        }
        hasher.write(b">>");
        self.signature.hash(hasher);
    }
}