trie_db/nibble/
leftnibbleslice.rs1use crate::rstd::cmp::{self, Ordering};
16
17use crate::nibble::{
18 nibble_ops::{self, NIBBLE_PER_BYTE},
19 NibbleSlice,
20};
21
22pub struct LeftNibbleSlice<'a> {
27 bytes: &'a [u8],
28 len: usize,
29}
30
31impl<'a> LeftNibbleSlice<'a> {
32 pub fn new(bytes: &'a [u8]) -> Self {
34 LeftNibbleSlice { bytes, len: bytes.len() * NIBBLE_PER_BYTE }
35 }
36
37 pub fn len(&self) -> usize {
39 self.len
40 }
41
42 pub fn at(&self, index: usize) -> Option<u8> {
45 if index < self.len() {
46 Some(nibble_ops::left_nibble_at(self.bytes, index))
47 } else {
48 None
49 }
50 }
51
52 pub fn truncate(&self, len: usize) -> Self {
55 LeftNibbleSlice { bytes: self.bytes, len: cmp::min(len, self.len) }
56 }
57
58 pub fn starts_with(&self, prefix: &LeftNibbleSlice<'a>) -> bool {
60 self.truncate(prefix.len()) == *prefix
61 }
62
63 pub fn contains(&self, partial: &NibbleSlice, offset: usize) -> bool {
66 (0..partial.len()).all(|i| self.at(offset + i) == Some(partial.at(i)))
67 }
68
69 fn cmp(&self, other: &Self) -> Ordering {
70 let common_len = cmp::min(self.len(), other.len());
71 let common_byte_len = common_len / NIBBLE_PER_BYTE;
72
73 match self.bytes[..common_byte_len].cmp(&other.bytes[..common_byte_len]) {
75 Ordering::Equal => {},
76 ordering => return ordering,
77 }
78
79 for i in (common_byte_len * NIBBLE_PER_BYTE)..common_len {
81 let a = self.at(i).expect("i < len; len == self.len() qed");
82 let b = other.at(i).expect("i < len; len == other.len(); qed");
83 match a.cmp(&b) {
84 Ordering::Equal => {},
85 ordering => return ordering,
86 }
87 }
88
89 self.len().cmp(&other.len())
91 }
92}
93
94impl<'a> PartialEq for LeftNibbleSlice<'a> {
95 fn eq(&self, other: &Self) -> bool {
96 let len = self.len();
97 if other.len() != len {
98 return false
99 }
100
101 let byte_len = len / NIBBLE_PER_BYTE;
103 if self.bytes[..byte_len] != other.bytes[..byte_len] {
104 return false
105 }
106
107 for i in (byte_len * NIBBLE_PER_BYTE)..len {
109 let a = self.at(i).expect("i < len; len == self.len() qed");
110 let b = other.at(i).expect("i < len; len == other.len(); qed");
111 if a != b {
112 return false
113 }
114 }
115
116 true
117 }
118}
119
120impl<'a> Eq for LeftNibbleSlice<'a> {}
121
122impl<'a> PartialOrd for LeftNibbleSlice<'a> {
123 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
124 Some(self.cmp(other))
125 }
126}
127
128impl<'a> Ord for LeftNibbleSlice<'a> {
129 fn cmp(&self, other: &Self) -> Ordering {
130 self.cmp(other)
131 }
132}
133
134#[cfg(feature = "std")]
135impl<'a> std::fmt::Debug for LeftNibbleSlice<'a> {
136 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
137 for i in 0..self.len() {
138 let nibble = self.at(i).expect("i < self.len(); qed");
139 match i {
140 0 => write!(f, "{:01x}", nibble)?,
141 _ => write!(f, "'{:01x}", nibble)?,
142 }
143 }
144 Ok(())
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn test_len() {
154 assert_eq!(LeftNibbleSlice::new(&[]).len(), 0);
155 assert_eq!(LeftNibbleSlice::new(&b"hello"[..]).len(), 10);
156 assert_eq!(LeftNibbleSlice::new(&b"hello"[..]).truncate(7).len(), 7);
157 }
158
159 #[test]
160 fn test_at() {
161 let slice = LeftNibbleSlice::new(&b"\x01\x23\x45\x67"[..]).truncate(7);
162 assert_eq!(slice.at(0), Some(0));
163 assert_eq!(slice.at(6), Some(6));
164 assert_eq!(slice.at(7), None);
165 assert_eq!(slice.at(8), None);
166 }
167
168 #[test]
169 fn test_starts_with() {
170 assert!(
171 LeftNibbleSlice::new(b"hello").starts_with(&LeftNibbleSlice::new(b"heli").truncate(7))
172 );
173 assert!(
174 !LeftNibbleSlice::new(b"hello").starts_with(&LeftNibbleSlice::new(b"heli").truncate(8))
175 );
176 }
177
178 #[test]
179 fn test_contains() {
180 assert!(LeftNibbleSlice::new(b"hello").contains(&NibbleSlice::new_offset(b"ello", 0), 2));
181 assert!(LeftNibbleSlice::new(b"hello").contains(&NibbleSlice::new_offset(b"ello", 1), 3));
182 assert!(!LeftNibbleSlice::new(b"hello").contains(&NibbleSlice::new_offset(b"allo", 1), 3));
183 assert!(!LeftNibbleSlice::new(b"hello").contains(&NibbleSlice::new_offset(b"ello!", 1), 3));
184 }
185
186 #[test]
187 fn test_cmp() {
188 assert!(LeftNibbleSlice::new(b"hallo") < LeftNibbleSlice::new(b"hello"));
189 assert!(LeftNibbleSlice::new(b"hello") > LeftNibbleSlice::new(b"hallo"));
190 assert_eq!(
191 LeftNibbleSlice::new(b"hello").cmp(&LeftNibbleSlice::new(b"hello")),
192 Ordering::Equal
193 );
194
195 assert!(
196 LeftNibbleSlice::new(b"hello\x10") < LeftNibbleSlice::new(b"hello\x20").truncate(11)
197 );
198 assert!(
199 LeftNibbleSlice::new(b"hello\x20").truncate(11) > LeftNibbleSlice::new(b"hello\x10")
200 );
201
202 assert!(
203 LeftNibbleSlice::new(b"hello\x10").truncate(11) < LeftNibbleSlice::new(b"hello\x10")
204 );
205 assert!(
206 LeftNibbleSlice::new(b"hello\x10") > LeftNibbleSlice::new(b"hello\x10").truncate(11)
207 );
208 assert_eq!(
209 LeftNibbleSlice::new(b"hello\x10")
210 .truncate(11)
211 .cmp(&LeftNibbleSlice::new(b"hello\x10").truncate(11)),
212 Ordering::Equal
213 );
214 }
215}