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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use crate::{CompressedSchema, Number, Schema, SchemaValue, ToNode};
use anchor_lang::{prelude::*, solana_program::keccak};
use spl_account_compression::Node;
use std::collections::HashMap;

impl ToNode for u64 {
    fn to_node(&self) -> Node {
        let bytes = self.clone().to_le_bytes();
        keccak::hashv(&[bytes.as_ref()][..]).to_bytes()
    }
}

impl CompressedSchema for u64 {
    fn schema() -> Schema {
        Schema::Number
    }

    fn schema_value(&self) -> SchemaValue {
        SchemaValue::Number(Number::U64(self.clone()))
    }
}

impl ToNode for String {
    fn to_node(&self) -> Node {
        keccak::hashv(&[self.clone().as_bytes()][..]).to_bytes()
    }
}

impl CompressedSchema for String {
    fn schema() -> Schema {
        Schema::String
    }

    fn schema_value(&self) -> SchemaValue {
        SchemaValue::String(self.clone())
    }
}

impl<T: ToNode> ToNode for Vec<T> {
    fn to_node(&self) -> Node {
        let mut seeds: Vec<[u8; 32]> = vec![];
        for item in self {
            let node = item.to_node();
            seeds.push(node);
        }
        let seeds_refs: Vec<&[u8]> = seeds.iter().map(|node| &node[..]).collect();
        keccak::hashv(&seeds_refs[..]).to_bytes()
    }
}

impl<T: CompressedSchema> CompressedSchema for Vec<T> {
    fn schema() -> Schema {
        Schema::Array(Box::new(T::schema()))
    }

    fn schema_value(&self) -> SchemaValue {
        SchemaValue::Array(self.clone().into_iter().map(|i| i.schema_value()).collect())
    }
}

impl ToNode for Pubkey {
    fn to_node(&self) -> Node {
        self.to_bytes()
    }
}

impl CompressedSchema for Pubkey {
    fn schema() -> Schema {
        Schema::Pubkey
    }

    fn schema_value(&self) -> SchemaValue {
        SchemaValue::Pubkey(self.clone())
    }
}

impl ToNode for bool {
    fn to_node(&self) -> Node {
        let bytes = self.clone().try_to_vec().unwrap();
        keccak::hashv(&[bytes.as_ref()][..]).to_bytes()
    }
}

impl CompressedSchema for bool {
    fn schema() -> Schema {
        Schema::Bool
    }

    fn schema_value(&self) -> SchemaValue {
        SchemaValue::Bool(self.clone())
    }
}

impl<T: ToNode> ToNode for Option<T> {
    fn to_node(&self) -> Node {
        match self {
            Some(value) => value.to_node(),
            None => keccak::hashv(&[&[0u8][..]][..]).to_bytes(),
        }
    }
}

impl<T: CompressedSchema> CompressedSchema for Option<T> {
    fn schema() -> Schema {
        Schema::Array(Box::new(T::schema()))
    }

    fn schema_value(&self) -> SchemaValue {
        SchemaValue::Option(Box::new(if self.is_some() {
            self.as_ref().unwrap().schema_value()
        } else {
            SchemaValue::Null
        }))
    }
}

impl<V: ToNode> ToNode for HashMap<String, V> {
    fn to_node(&self) -> Node {
        let mut seeds: Vec<[u8; 32]> = vec![];
        for (key, value) in self {
            let key_node = key.to_node();
            let value_node = value.to_node();
            seeds.push(keccak::hashv(&[&key_node[..]][..]).to_bytes());
            seeds.push(keccak::hashv(&[&value_node[..]][..]).to_bytes());
        }
        let seeds_refs: Vec<&[u8]> = seeds.iter().map(|node| &node[..]).collect();
        keccak::hashv(&seeds_refs[..]).to_bytes()
    }
}

impl<K: ToString, V: CompressedSchema> CompressedSchema for HashMap<K, V> {
    fn schema() -> Schema {
        Schema::HashMap(Box::new(Schema::String), Box::new(V::schema()))
    }

    fn schema_value(&self) -> SchemaValue {
        let mut schema = HashMap::new();
        self.iter().for_each(|(key, value)| {
            schema.insert(key.to_string(), value.schema_value());
        });
        SchemaValue::HashMap(schema)
    }
}