1use std::cmp::*;
20use std::fmt;
21use elastic_array::ElasticArray36;
22
23#[derive(Copy, Clone, Eq, Ord)]
46pub struct NibbleSlice<'a> {
47 data: &'a [u8],
48 offset: usize,
49 data_encode_suffix: &'a [u8],
50 offset_encode_suffix: usize,
51}
52
53pub struct NibbleSliceIterator<'a> {
55 p: &'a NibbleSlice<'a>,
56 i: usize,
57}
58
59impl<'a> Iterator for NibbleSliceIterator<'a> {
60 type Item = u8;
61 fn next(&mut self) -> Option<u8> {
62 self.i += 1;
63 match self.i <= self.p.len() {
64 true => Some(self.p.at(self.i - 1)),
65 false => None,
66 }
67 }
68}
69
70impl<'a> NibbleSlice<'a> {
71 pub fn new(data: &'a [u8]) -> Self { NibbleSlice::new_offset(data, 0) }
73
74 pub fn new_offset(data: &'a [u8], offset: usize) -> Self {
76 NibbleSlice {
77 data,
78 offset,
79 data_encode_suffix: &b""[..],
80 offset_encode_suffix: 0
81 }
82 }
83
84 pub fn new_composed(a: &NibbleSlice<'a>, b: &NibbleSlice<'a>) -> Self {
86 NibbleSlice {
87 data: a.data,
88 offset: a.offset,
89 data_encode_suffix: b.data,
90 offset_encode_suffix: b.offset
91 }
92 }
93
94 pub fn iter(&'a self) -> NibbleSliceIterator<'a> {
96 NibbleSliceIterator { p: self, i: 0 }
97 }
98
99 pub fn from_encoded(data: &'a [u8]) -> (NibbleSlice, bool) {
101 (Self::new_offset(data, if data[0] & 16 == 16 {1} else {2}), data[0] & 32 == 32)
102 }
103
104 pub fn is_empty(&self) -> bool { self.len() == 0 }
106
107 #[inline]
109 pub fn len(&self) -> usize { (self.data.len() + self.data_encode_suffix.len()) * 2 - self.offset - self.offset_encode_suffix }
110
111 #[inline(always)]
113 pub fn at(&self, i: usize) -> u8 {
114 let l = self.data.len() * 2 - self.offset;
115 if i < l {
116 if (self.offset + i) & 1 == 1 {
117 self.data[(self.offset + i) / 2] & 15u8
118 }
119 else {
120 self.data[(self.offset + i) / 2] >> 4
121 }
122 }
123 else {
124 let i = i - l;
125 if (self.offset_encode_suffix + i) & 1 == 1 {
126 self.data_encode_suffix[(self.offset_encode_suffix + i) / 2] & 15u8
127 }
128 else {
129 self.data_encode_suffix[(self.offset_encode_suffix + i) / 2] >> 4
130 }
131 }
132 }
133
134 pub fn mid(&self, i: usize) -> NibbleSlice<'a> {
136 NibbleSlice {
137 data: self.data,
138 offset: self.offset + i,
139 data_encode_suffix: &b""[..],
140 offset_encode_suffix: 0
141 }
142 }
143
144 pub fn starts_with(&self, them: &Self) -> bool { self.common_prefix(them) == them.len() }
146
147 pub fn common_prefix(&self, them: &Self) -> usize {
149 let s = min(self.len(), them.len());
150 let mut i = 0usize;
151 while i < s {
152 if self.at(i) != them.at(i) { break; }
153 i += 1;
154 }
155 i
156 }
157
158 #[inline]
160 pub fn encoded(&self, is_leaf: bool) -> ElasticArray36<u8> {
161 let l = self.len();
162 let mut r = ElasticArray36::new();
163 let mut i = l % 2;
164 r.push(if i == 1 {0x10 + self.at(0)} else {0} + if is_leaf {0x20} else {0});
165 while i < l {
166 r.push(self.at(i) * 16 + self.at(i + 1));
167 i += 2;
168 }
169 r
170 }
171
172 pub fn encoded_leftmost(&self, n: usize, is_leaf: bool) -> ElasticArray36<u8> {
175 let l = min(self.len(), n);
176 let mut r = ElasticArray36::new();
177 let mut i = l % 2;
178 r.push(if i == 1 {0x10 + self.at(0)} else {0} + if is_leaf {0x20} else {0});
179 while i < l {
180 r.push(self.at(i) * 16 + self.at(i + 1));
181 i += 2;
182 }
183 r
184 }
185}
186
187impl<'a> PartialEq for NibbleSlice<'a> {
188 fn eq(&self, them: &Self) -> bool {
189 self.len() == them.len() && self.starts_with(them)
190 }
191}
192
193impl<'a> PartialOrd for NibbleSlice<'a> {
194 fn partial_cmp(&self, them: &Self) -> Option<Ordering> {
195 let s = min(self.len(), them.len());
196 let mut i = 0usize;
197 while i < s {
198 match self.at(i).partial_cmp(&them.at(i)).unwrap() {
199 Ordering::Less => return Some(Ordering::Less),
200 Ordering::Greater => return Some(Ordering::Greater),
201 _ => i += 1,
202 }
203 }
204 self.len().partial_cmp(&them.len())
205 }
206}
207
208impl<'a> fmt::Debug for NibbleSlice<'a> {
209 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
210 for i in 0..self.len() {
211 match i {
212 0 => write!(f, "{:01x}", self.at(i))?,
213 _ => write!(f, "'{:01x}", self.at(i))?,
214 }
215 }
216 Ok(())
217 }
218}
219
220#[cfg(test)]
221mod tests {
222 use super::NibbleSlice;
223 use elastic_array::ElasticArray36;
224 static D: &'static [u8;3] = &[0x01u8, 0x23, 0x45];
225
226 #[test]
227 fn basics() {
228 let n = NibbleSlice::new(D);
229 assert_eq!(n.len(), 6);
230 assert!(!n.is_empty());
231
232 let n = NibbleSlice::new_offset(D, 6);
233 assert!(n.is_empty());
234
235 let n = NibbleSlice::new_offset(D, 3);
236 assert_eq!(n.len(), 3);
237 for i in 0..3 {
238 assert_eq!(n.at(i), i as u8 + 3);
239 }
240 }
241
242 #[test]
243 fn iterator() {
244 let n = NibbleSlice::new(D);
245 let mut nibbles: Vec<u8> = vec![];
246 nibbles.extend(n.iter());
247 assert_eq!(nibbles, (0u8..6).collect::<Vec<_>>())
248 }
249
250 #[test]
251 fn mid() {
252 let n = NibbleSlice::new(D);
253 let m = n.mid(2);
254 for i in 0..4 {
255 assert_eq!(m.at(i), i as u8 + 2);
256 }
257 let m = n.mid(3);
258 for i in 0..3 {
259 assert_eq!(m.at(i), i as u8 + 3);
260 }
261 }
262
263 #[test]
264 fn encoded() {
265 let n = NibbleSlice::new(D);
266 assert_eq!(n.encoded(false), ElasticArray36::from_slice(&[0x00, 0x01, 0x23, 0x45]));
267 assert_eq!(n.encoded(true), ElasticArray36::from_slice(&[0x20, 0x01, 0x23, 0x45]));
268 assert_eq!(n.mid(1).encoded(false), ElasticArray36::from_slice(&[0x11, 0x23, 0x45]));
269 assert_eq!(n.mid(1).encoded(true), ElasticArray36::from_slice(&[0x31, 0x23, 0x45]));
270 }
271
272 #[test]
273 fn from_encoded() {
274 let n = NibbleSlice::new(D);
275 assert_eq!((n, false), NibbleSlice::from_encoded(&[0x00, 0x01, 0x23, 0x45]));
276 assert_eq!((n, true), NibbleSlice::from_encoded(&[0x20, 0x01, 0x23, 0x45]));
277 assert_eq!((n.mid(1), false), NibbleSlice::from_encoded(&[0x11, 0x23, 0x45]));
278 assert_eq!((n.mid(1), true), NibbleSlice::from_encoded(&[0x31, 0x23, 0x45]));
279 }
280
281 #[test]
282 fn find_length_of_common_prefix() {
283 let n = NibbleSlice::new(D);
284
285 let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45, 0x67];
286 let m = NibbleSlice::new(other);
287
288 assert_eq!(n.common_prefix(&m), 4);
289 assert_eq!(m.common_prefix(&n), 4);
290 assert_eq!(n.mid(1).common_prefix(&m.mid(1)), 3);
291 assert_eq!(n.mid(1).common_prefix(&m.mid(2)), 0);
292 assert_eq!(n.common_prefix(&m.mid(4)), 6);
293 assert!(!n.starts_with(&m.mid(4)));
294 assert!(m.mid(4).starts_with(&n));
295 }
296
297 #[test]
298 fn compare_sizes() {
299 let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45];
300 let n = NibbleSlice::new(D);
301 let m = NibbleSlice::new(other);
302
303 assert!(n != m);
304 assert!(n > m);
305 assert!(m < n);
306
307 assert!(n == m.mid(4));
308 assert!(n >= m.mid(4));
309 assert!(n <= m.mid(4));
310 }
311
312 #[test]
313 fn common_prefix_for_concatenated_slices() {
314 let first = NibbleSlice::new(&[0x01u8, 0x23, 0x45]); let first_ext = NibbleSlice::new(&[0x22u8, 0x44, 0x55]); let concat = NibbleSlice::new_composed(&first, &first_ext);
317 assert!(concat.len() == first.len() + first_ext.len());
318
319 let second = NibbleSlice::new(&[0x01u8, 0x23, 0x45, 0x22, 0x99, 0x55]);
321
322 let common_prefix_length = first.common_prefix(&second);
323 assert_eq!(common_prefix_length, 6);
324
325 let common_prefix_length = concat.common_prefix(&second);
326 assert_eq!(common_prefix_length, 8);
327 }
328}