reth_trie_common/
nibbles.rs

1use derive_more::Deref;
2pub use nybbles::Nibbles;
3
4/// The representation of nibbles of the merkle trie stored in the database.
5#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, derive_more::Index)]
6#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
7#[cfg_attr(feature = "test-utils", derive(arbitrary::Arbitrary))]
8pub struct StoredNibbles(pub Nibbles);
9
10impl From<Nibbles> for StoredNibbles {
11    #[inline]
12    fn from(value: Nibbles) -> Self {
13        Self(value)
14    }
15}
16
17impl From<Vec<u8>> for StoredNibbles {
18    #[inline]
19    fn from(value: Vec<u8>) -> Self {
20        Self(Nibbles::from_nibbles_unchecked(value))
21    }
22}
23
24impl PartialEq<[u8]> for StoredNibbles {
25    #[inline]
26    fn eq(&self, other: &[u8]) -> bool {
27        self.0.as_slice() == other
28    }
29}
30
31impl PartialOrd<[u8]> for StoredNibbles {
32    #[inline]
33    fn partial_cmp(&self, other: &[u8]) -> Option<std::cmp::Ordering> {
34        self.0.as_slice().partial_cmp(other)
35    }
36}
37
38impl core::borrow::Borrow<[u8]> for StoredNibbles {
39    #[inline]
40    fn borrow(&self) -> &[u8] {
41        self.0.as_slice()
42    }
43}
44
45#[cfg(any(test, feature = "reth-codec"))]
46impl reth_codecs::Compact for StoredNibbles {
47    fn to_compact<B>(&self, buf: &mut B) -> usize
48    where
49        B: bytes::BufMut + AsMut<[u8]>,
50    {
51        buf.put_slice(self.0.as_slice());
52        self.0.len()
53    }
54
55    fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
56        use bytes::Buf;
57
58        let nibbles = &buf[..len];
59        buf.advance(len);
60        (Self(Nibbles::from_nibbles_unchecked(nibbles)), buf)
61    }
62}
63
64/// The representation of nibbles of the merkle trie stored in the database.
65#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deref)]
66#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
67#[cfg_attr(feature = "test-utils", derive(arbitrary::Arbitrary))]
68pub struct StoredNibblesSubKey(pub Nibbles);
69
70impl From<Nibbles> for StoredNibblesSubKey {
71    #[inline]
72    fn from(value: Nibbles) -> Self {
73        Self(value)
74    }
75}
76
77impl From<Vec<u8>> for StoredNibblesSubKey {
78    #[inline]
79    fn from(value: Vec<u8>) -> Self {
80        Self(Nibbles::from_nibbles_unchecked(value))
81    }
82}
83
84impl From<StoredNibblesSubKey> for Nibbles {
85    #[inline]
86    fn from(value: StoredNibblesSubKey) -> Self {
87        value.0
88    }
89}
90
91#[cfg(any(test, feature = "reth-codec"))]
92impl reth_codecs::Compact for StoredNibblesSubKey {
93    fn to_compact<B>(&self, buf: &mut B) -> usize
94    where
95        B: bytes::BufMut + AsMut<[u8]>,
96    {
97        assert!(self.0.len() <= 64);
98
99        // right-pad with zeros
100        buf.put_slice(&self.0[..]);
101        static ZERO: &[u8; 64] = &[0; 64];
102        buf.put_slice(&ZERO[self.0.len()..]);
103
104        buf.put_u8(self.0.len() as u8);
105        64 + 1
106    }
107
108    fn from_compact(buf: &[u8], _len: usize) -> (Self, &[u8]) {
109        let len = buf[64] as usize;
110        (Self(Nibbles::from_nibbles_unchecked(&buf[..len])), &buf[65..])
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117    use bytes::BytesMut;
118    use reth_codecs::Compact;
119
120    #[test]
121    fn test_stored_nibbles_from_nibbles() {
122        let nibbles = Nibbles::from_nibbles_unchecked(vec![0x12, 0x34, 0x56]);
123        let stored = StoredNibbles::from(nibbles.clone());
124        assert_eq!(stored.0, nibbles);
125    }
126
127    #[test]
128    fn test_stored_nibbles_from_vec() {
129        let bytes = vec![0x12, 0x34, 0x56];
130        let stored = StoredNibbles::from(bytes.clone());
131        assert_eq!(stored.0.as_slice(), bytes.as_slice());
132    }
133
134    #[test]
135    fn test_stored_nibbles_equality() {
136        let bytes = vec![0x12, 0x34];
137        let stored = StoredNibbles::from(bytes.clone());
138        assert_eq!(stored, *bytes.as_slice());
139    }
140
141    #[test]
142    fn test_stored_nibbles_partial_cmp() {
143        let stored = StoredNibbles::from(vec![0x12, 0x34]);
144        let other = vec![0x12, 0x35];
145        assert!(stored < *other.as_slice());
146    }
147
148    #[test]
149    fn test_stored_nibbles_to_compact() {
150        let stored = StoredNibbles::from(vec![0x12, 0x34]);
151        let mut buf = BytesMut::with_capacity(10);
152        let len = stored.to_compact(&mut buf);
153        assert_eq!(len, 2);
154        assert_eq!(buf, &vec![0x12, 0x34][..]);
155    }
156
157    #[test]
158    fn test_stored_nibbles_from_compact() {
159        let buf = vec![0x12, 0x34, 0x56];
160        let (stored, remaining) = StoredNibbles::from_compact(&buf, 2);
161        assert_eq!(stored.0.as_slice(), &[0x12, 0x34]);
162        assert_eq!(remaining, &[0x56]);
163    }
164
165    #[test]
166    fn test_stored_nibbles_subkey_from_nibbles() {
167        let nibbles = Nibbles::from_nibbles_unchecked(vec![0x12, 0x34]);
168        let subkey = StoredNibblesSubKey::from(nibbles.clone());
169        assert_eq!(subkey.0, nibbles);
170    }
171
172    #[test]
173    fn test_stored_nibbles_subkey_to_compact() {
174        let subkey = StoredNibblesSubKey::from(vec![0x12, 0x34]);
175        let mut buf = BytesMut::with_capacity(65);
176        let len = subkey.to_compact(&mut buf);
177        assert_eq!(len, 65);
178        assert_eq!(buf[..2], [0x12, 0x34]);
179        assert_eq!(buf[64], 2); // Length byte
180    }
181
182    #[test]
183    fn test_stored_nibbles_subkey_from_compact() {
184        let mut buf = vec![0x12, 0x34];
185        buf.resize(65, 0);
186        buf[64] = 2;
187        let (subkey, remaining) = StoredNibblesSubKey::from_compact(&buf, 65);
188        assert_eq!(subkey.0.as_slice(), &[0x12, 0x34]);
189        assert_eq!(remaining, &[] as &[u8]);
190    }
191
192    #[test]
193    fn test_serialization_stored_nibbles() {
194        let stored = StoredNibbles::from(vec![0x12, 0x34]);
195        let serialized = serde_json::to_string(&stored).unwrap();
196        let deserialized: StoredNibbles = serde_json::from_str(&serialized).unwrap();
197        assert_eq!(stored, deserialized);
198    }
199
200    #[test]
201    fn test_serialization_stored_nibbles_subkey() {
202        let subkey = StoredNibblesSubKey::from(vec![0x12, 0x34]);
203        let serialized = serde_json::to_string(&subkey).unwrap();
204        let deserialized: StoredNibblesSubKey = serde_json::from_str(&serialized).unwrap();
205        assert_eq!(subkey, deserialized);
206    }
207}