##// END OF EJS Templates
rust: Exclude empty node prefixes...
Simon Sapin -
r47157:e61c2dc6 default
parent child Browse files
Show More
@@ -1,412 +1,408
1 // Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
1 // Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
2 //
2 //
3 // This software may be used and distributed according to the terms of the
3 // This software may be used and distributed according to the terms of the
4 // GNU General Public License version 2 or any later version.
4 // GNU General Public License version 2 or any later version.
5
5
6 //! Definitions and utilities for Revision nodes
6 //! Definitions and utilities for Revision nodes
7 //!
7 //!
8 //! In Mercurial code base, it is customary to call "a node" the binary SHA
8 //! In Mercurial code base, it is customary to call "a node" the binary SHA
9 //! of a revision.
9 //! of a revision.
10
10
11 use bytes_cast::BytesCast;
11 use bytes_cast::BytesCast;
12 use hex::{self, FromHex};
12 use hex::{self, FromHex};
13 use std::convert::TryFrom;
13 use std::convert::TryFrom;
14 use std::fmt;
14 use std::fmt;
15
15
16 /// The length in bytes of a `Node`
16 /// The length in bytes of a `Node`
17 ///
17 ///
18 /// This constant is meant to ease refactors of this module, and
18 /// This constant is meant to ease refactors of this module, and
19 /// are private so that calling code does not expect all nodes have
19 /// are private so that calling code does not expect all nodes have
20 /// the same size, should we support several formats concurrently in
20 /// the same size, should we support several formats concurrently in
21 /// the future.
21 /// the future.
22 pub const NODE_BYTES_LENGTH: usize = 20;
22 pub const NODE_BYTES_LENGTH: usize = 20;
23
23
24 /// Id of the null node.
24 /// Id of the null node.
25 ///
25 ///
26 /// Used to indicate the absence of node.
26 /// Used to indicate the absence of node.
27 pub const NULL_NODE_ID: [u8; NODE_BYTES_LENGTH] = [0u8; NODE_BYTES_LENGTH];
27 pub const NULL_NODE_ID: [u8; NODE_BYTES_LENGTH] = [0u8; NODE_BYTES_LENGTH];
28
28
29 /// The length in bytes of a `Node`
29 /// The length in bytes of a `Node`
30 ///
30 ///
31 /// see also `NODES_BYTES_LENGTH` about it being private.
31 /// see also `NODES_BYTES_LENGTH` about it being private.
32 const NODE_NYBBLES_LENGTH: usize = 2 * NODE_BYTES_LENGTH;
32 const NODE_NYBBLES_LENGTH: usize = 2 * NODE_BYTES_LENGTH;
33
33
34 /// Private alias for readability and to ease future change
34 /// Private alias for readability and to ease future change
35 type NodeData = [u8; NODE_BYTES_LENGTH];
35 type NodeData = [u8; NODE_BYTES_LENGTH];
36
36
37 /// Binary revision SHA
37 /// Binary revision SHA
38 ///
38 ///
39 /// ## Future changes of hash size
39 /// ## Future changes of hash size
40 ///
40 ///
41 /// To accomodate future changes of hash size, Rust callers
41 /// To accomodate future changes of hash size, Rust callers
42 /// should use the conversion methods at the boundaries (FFI, actual
42 /// should use the conversion methods at the boundaries (FFI, actual
43 /// computation of hashes and I/O) only, and only if required.
43 /// computation of hashes and I/O) only, and only if required.
44 ///
44 ///
45 /// All other callers outside of unit tests should just handle `Node` values
45 /// All other callers outside of unit tests should just handle `Node` values
46 /// and never make any assumption on the actual length, using [`nybbles_len`]
46 /// and never make any assumption on the actual length, using [`nybbles_len`]
47 /// if they need a loop boundary.
47 /// if they need a loop boundary.
48 ///
48 ///
49 /// All methods that create a `Node` either take a type that enforces
49 /// All methods that create a `Node` either take a type that enforces
50 /// the size or return an error at runtime.
50 /// the size or return an error at runtime.
51 ///
51 ///
52 /// [`nybbles_len`]: #method.nybbles_len
52 /// [`nybbles_len`]: #method.nybbles_len
53 #[derive(Clone, Debug, PartialEq, BytesCast)]
53 #[derive(Clone, Debug, PartialEq, BytesCast)]
54 #[repr(transparent)]
54 #[repr(transparent)]
55 pub struct Node {
55 pub struct Node {
56 data: NodeData,
56 data: NodeData,
57 }
57 }
58
58
59 /// The node value for NULL_REVISION
59 /// The node value for NULL_REVISION
60 pub const NULL_NODE: Node = Node {
60 pub const NULL_NODE: Node = Node {
61 data: [0; NODE_BYTES_LENGTH],
61 data: [0; NODE_BYTES_LENGTH],
62 };
62 };
63
63
64 impl From<NodeData> for Node {
64 impl From<NodeData> for Node {
65 fn from(data: NodeData) -> Node {
65 fn from(data: NodeData) -> Node {
66 Node { data }
66 Node { data }
67 }
67 }
68 }
68 }
69
69
70 /// Return an error if the slice has an unexpected length
70 /// Return an error if the slice has an unexpected length
71 impl<'a> TryFrom<&'a [u8]> for &'a Node {
71 impl<'a> TryFrom<&'a [u8]> for &'a Node {
72 type Error = ();
72 type Error = ();
73
73
74 #[inline]
74 #[inline]
75 fn try_from(bytes: &'a [u8]) -> Result<&'a Node, Self::Error> {
75 fn try_from(bytes: &'a [u8]) -> Result<&'a Node, Self::Error> {
76 match Node::from_bytes(bytes) {
76 match Node::from_bytes(bytes) {
77 Ok((node, rest)) if rest.is_empty() => Ok(node),
77 Ok((node, rest)) if rest.is_empty() => Ok(node),
78 _ => Err(()),
78 _ => Err(()),
79 }
79 }
80 }
80 }
81 }
81 }
82
82
83 impl fmt::LowerHex for Node {
83 impl fmt::LowerHex for Node {
84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85 for &byte in &self.data {
85 for &byte in &self.data {
86 write!(f, "{:02x}", byte)?
86 write!(f, "{:02x}", byte)?
87 }
87 }
88 Ok(())
88 Ok(())
89 }
89 }
90 }
90 }
91
91
92 #[derive(Debug)]
92 #[derive(Debug)]
93 pub struct FromHexError;
93 pub struct FromHexError;
94
94
95 /// Low level utility function, also for prefixes
95 /// Low level utility function, also for prefixes
96 fn get_nybble(s: &[u8], i: usize) -> u8 {
96 fn get_nybble(s: &[u8], i: usize) -> u8 {
97 if i % 2 == 0 {
97 if i % 2 == 0 {
98 s[i / 2] >> 4
98 s[i / 2] >> 4
99 } else {
99 } else {
100 s[i / 2] & 0x0f
100 s[i / 2] & 0x0f
101 }
101 }
102 }
102 }
103
103
104 impl Node {
104 impl Node {
105 /// Retrieve the `i`th half-byte of the binary data.
105 /// Retrieve the `i`th half-byte of the binary data.
106 ///
106 ///
107 /// This is also the `i`th hexadecimal digit in numeric form,
107 /// This is also the `i`th hexadecimal digit in numeric form,
108 /// also called a [nybble](https://en.wikipedia.org/wiki/Nibble).
108 /// also called a [nybble](https://en.wikipedia.org/wiki/Nibble).
109 pub fn get_nybble(&self, i: usize) -> u8 {
109 pub fn get_nybble(&self, i: usize) -> u8 {
110 get_nybble(&self.data, i)
110 get_nybble(&self.data, i)
111 }
111 }
112
112
113 /// Length of the data, in nybbles
113 /// Length of the data, in nybbles
114 pub fn nybbles_len(&self) -> usize {
114 pub fn nybbles_len(&self) -> usize {
115 // public exposure as an instance method only, so that we can
115 // public exposure as an instance method only, so that we can
116 // easily support several sizes of hashes if needed in the future.
116 // easily support several sizes of hashes if needed in the future.
117 NODE_NYBBLES_LENGTH
117 NODE_NYBBLES_LENGTH
118 }
118 }
119
119
120 /// Convert from hexadecimal string representation
120 /// Convert from hexadecimal string representation
121 ///
121 ///
122 /// Exact length is required.
122 /// Exact length is required.
123 ///
123 ///
124 /// To be used in FFI and I/O only, in order to facilitate future
124 /// To be used in FFI and I/O only, in order to facilitate future
125 /// changes of hash format.
125 /// changes of hash format.
126 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Node, FromHexError> {
126 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Node, FromHexError> {
127 Ok(NodeData::from_hex(hex.as_ref())
127 Ok(NodeData::from_hex(hex.as_ref())
128 .map_err(|_| FromHexError)?
128 .map_err(|_| FromHexError)?
129 .into())
129 .into())
130 }
130 }
131
131
132 /// Provide access to binary data
132 /// Provide access to binary data
133 ///
133 ///
134 /// This is needed by FFI layers, for instance to return expected
134 /// This is needed by FFI layers, for instance to return expected
135 /// binary values to Python.
135 /// binary values to Python.
136 pub fn as_bytes(&self) -> &[u8] {
136 pub fn as_bytes(&self) -> &[u8] {
137 &self.data
137 &self.data
138 }
138 }
139 }
139 }
140
140
141 /// The beginning of a binary revision SHA.
141 /// The beginning of a binary revision SHA.
142 ///
142 ///
143 /// Since it can potentially come from an hexadecimal representation with
143 /// Since it can potentially come from an hexadecimal representation with
144 /// odd length, it needs to carry around whether the last 4 bits are relevant
144 /// odd length, it needs to carry around whether the last 4 bits are relevant
145 /// or not.
145 /// or not.
146 #[derive(Debug, PartialEq)]
146 #[derive(Debug, PartialEq)]
147 pub struct NodePrefix {
147 pub struct NodePrefix {
148 buf: Vec<u8>,
148 buf: Vec<u8>,
149 is_odd: bool,
149 is_odd: bool,
150 }
150 }
151
151
152 impl NodePrefix {
152 impl NodePrefix {
153 /// Convert from hexadecimal string representation
153 /// Convert from hexadecimal string representation
154 ///
154 ///
155 /// Similarly to `hex::decode`, can be used with Unicode string types
155 /// Similarly to `hex::decode`, can be used with Unicode string types
156 /// (`String`, `&str`) as well as bytes.
156 /// (`String`, `&str`) as well as bytes.
157 ///
157 ///
158 /// To be used in FFI and I/O only, in order to facilitate future
158 /// To be used in FFI and I/O only, in order to facilitate future
159 /// changes of hash format.
159 /// changes of hash format.
160 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Self, FromHexError> {
160 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Self, FromHexError> {
161 let hex = hex.as_ref();
161 let hex = hex.as_ref();
162 let len = hex.len();
162 let len = hex.len();
163 if len > NODE_NYBBLES_LENGTH {
163 if len > NODE_NYBBLES_LENGTH || len == 0 {
164 return Err(FromHexError);
164 return Err(FromHexError);
165 }
165 }
166
166
167 let is_odd = len % 2 == 1;
167 let is_odd = len % 2 == 1;
168 let even_part = if is_odd { &hex[..len - 1] } else { hex };
168 let even_part = if is_odd { &hex[..len - 1] } else { hex };
169 let mut buf: Vec<u8> =
169 let mut buf: Vec<u8> =
170 Vec::from_hex(&even_part).map_err(|_| FromHexError)?;
170 Vec::from_hex(&even_part).map_err(|_| FromHexError)?;
171
171
172 if is_odd {
172 if is_odd {
173 let latest_char = char::from(hex[len - 1]);
173 let latest_char = char::from(hex[len - 1]);
174 let latest_nybble =
174 let latest_nybble =
175 latest_char.to_digit(16).ok_or_else(|| FromHexError)? as u8;
175 latest_char.to_digit(16).ok_or_else(|| FromHexError)? as u8;
176 buf.push(latest_nybble << 4);
176 buf.push(latest_nybble << 4);
177 }
177 }
178 Ok(NodePrefix { buf, is_odd })
178 Ok(NodePrefix { buf, is_odd })
179 }
179 }
180
180
181 pub fn borrow(&self) -> NodePrefixRef {
181 pub fn borrow(&self) -> NodePrefixRef {
182 NodePrefixRef {
182 NodePrefixRef {
183 buf: &self.buf,
183 buf: &self.buf,
184 is_odd: self.is_odd,
184 is_odd: self.is_odd,
185 }
185 }
186 }
186 }
187 }
187 }
188
188
189 #[derive(Clone, Debug, PartialEq)]
189 #[derive(Clone, Debug, PartialEq)]
190 pub struct NodePrefixRef<'a> {
190 pub struct NodePrefixRef<'a> {
191 buf: &'a [u8],
191 buf: &'a [u8],
192 is_odd: bool,
192 is_odd: bool,
193 }
193 }
194
194
195 impl<'a> NodePrefixRef<'a> {
195 impl<'a> NodePrefixRef<'a> {
196 pub fn len(&self) -> usize {
196 pub fn len(&self) -> usize {
197 if self.is_odd {
197 if self.is_odd {
198 self.buf.len() * 2 - 1
198 self.buf.len() * 2 - 1
199 } else {
199 } else {
200 self.buf.len() * 2
200 self.buf.len() * 2
201 }
201 }
202 }
202 }
203
203
204 pub fn is_empty(&self) -> bool {
205 self.len() == 0
206 }
207
208 pub fn is_prefix_of(&self, node: &Node) -> bool {
204 pub fn is_prefix_of(&self, node: &Node) -> bool {
209 if self.is_odd {
205 if self.is_odd {
210 let buf = self.buf;
206 let buf = self.buf;
211 let last_pos = buf.len() - 1;
207 let last_pos = buf.len() - 1;
212 node.data.starts_with(buf.split_at(last_pos).0)
208 node.data.starts_with(buf.split_at(last_pos).0)
213 && node.data[last_pos] >> 4 == buf[last_pos] >> 4
209 && node.data[last_pos] >> 4 == buf[last_pos] >> 4
214 } else {
210 } else {
215 node.data.starts_with(self.buf)
211 node.data.starts_with(self.buf)
216 }
212 }
217 }
213 }
218
214
219 /// Retrieve the `i`th half-byte from the prefix.
215 /// Retrieve the `i`th half-byte from the prefix.
220 ///
216 ///
221 /// This is also the `i`th hexadecimal digit in numeric form,
217 /// This is also the `i`th hexadecimal digit in numeric form,
222 /// also called a [nybble](https://en.wikipedia.org/wiki/Nibble).
218 /// also called a [nybble](https://en.wikipedia.org/wiki/Nibble).
223 pub fn get_nybble(&self, i: usize) -> u8 {
219 pub fn get_nybble(&self, i: usize) -> u8 {
224 assert!(i < self.len());
220 assert!(i < self.len());
225 get_nybble(self.buf, i)
221 get_nybble(self.buf, i)
226 }
222 }
227
223
228 /// Return the index first nybble that's different from `node`
224 /// Return the index first nybble that's different from `node`
229 ///
225 ///
230 /// If the return value is `None` that means that `self` is
226 /// If the return value is `None` that means that `self` is
231 /// a prefix of `node`, but the current method is a bit slower
227 /// a prefix of `node`, but the current method is a bit slower
232 /// than `is_prefix_of`.
228 /// than `is_prefix_of`.
233 ///
229 ///
234 /// Returned index is as in `get_nybble`, i.e., starting at 0.
230 /// Returned index is as in `get_nybble`, i.e., starting at 0.
235 pub fn first_different_nybble(&self, node: &Node) -> Option<usize> {
231 pub fn first_different_nybble(&self, node: &Node) -> Option<usize> {
236 let buf = self.buf;
232 let buf = self.buf;
237 let until = if self.is_odd {
233 let until = if self.is_odd {
238 buf.len() - 1
234 buf.len() - 1
239 } else {
235 } else {
240 buf.len()
236 buf.len()
241 };
237 };
242 for (i, item) in buf.iter().enumerate().take(until) {
238 for (i, item) in buf.iter().enumerate().take(until) {
243 if *item != node.data[i] {
239 if *item != node.data[i] {
244 return if *item & 0xf0 == node.data[i] & 0xf0 {
240 return if *item & 0xf0 == node.data[i] & 0xf0 {
245 Some(2 * i + 1)
241 Some(2 * i + 1)
246 } else {
242 } else {
247 Some(2 * i)
243 Some(2 * i)
248 };
244 };
249 }
245 }
250 }
246 }
251 if self.is_odd && buf[until] & 0xf0 != node.data[until] & 0xf0 {
247 if self.is_odd && buf[until] & 0xf0 != node.data[until] & 0xf0 {
252 Some(until * 2)
248 Some(until * 2)
253 } else {
249 } else {
254 None
250 None
255 }
251 }
256 }
252 }
257 }
253 }
258
254
259 /// A shortcut for full `Node` references
255 /// A shortcut for full `Node` references
260 impl<'a> From<&'a Node> for NodePrefixRef<'a> {
256 impl<'a> From<&'a Node> for NodePrefixRef<'a> {
261 fn from(node: &'a Node) -> Self {
257 fn from(node: &'a Node) -> Self {
262 NodePrefixRef {
258 NodePrefixRef {
263 buf: &node.data,
259 buf: &node.data,
264 is_odd: false,
260 is_odd: false,
265 }
261 }
266 }
262 }
267 }
263 }
268
264
269 impl PartialEq<Node> for NodePrefixRef<'_> {
265 impl PartialEq<Node> for NodePrefixRef<'_> {
270 fn eq(&self, other: &Node) -> bool {
266 fn eq(&self, other: &Node) -> bool {
271 !self.is_odd && self.buf == other.data
267 !self.is_odd && self.buf == other.data
272 }
268 }
273 }
269 }
274
270
275 #[cfg(test)]
271 #[cfg(test)]
276 mod tests {
272 mod tests {
277 use super::*;
273 use super::*;
278
274
279 fn sample_node() -> Node {
275 fn sample_node() -> Node {
280 let mut data = [0; NODE_BYTES_LENGTH];
276 let mut data = [0; NODE_BYTES_LENGTH];
281 data.copy_from_slice(&[
277 data.copy_from_slice(&[
282 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba,
278 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba,
283 0x98, 0x76, 0x54, 0x32, 0x10, 0xde, 0xad, 0xbe, 0xef,
279 0x98, 0x76, 0x54, 0x32, 0x10, 0xde, 0xad, 0xbe, 0xef,
284 ]);
280 ]);
285 data.into()
281 data.into()
286 }
282 }
287
283
288 /// Pad an hexadecimal string to reach `NODE_NYBBLES_LENGTH`
284 /// Pad an hexadecimal string to reach `NODE_NYBBLES_LENGTH`
289 ///check_hash
285 ///check_hash
290 /// The padding is made with zeros
286 /// The padding is made with zeros
291 pub fn hex_pad_right(hex: &str) -> String {
287 pub fn hex_pad_right(hex: &str) -> String {
292 let mut res = hex.to_string();
288 let mut res = hex.to_string();
293 while res.len() < NODE_NYBBLES_LENGTH {
289 while res.len() < NODE_NYBBLES_LENGTH {
294 res.push('0');
290 res.push('0');
295 }
291 }
296 res
292 res
297 }
293 }
298
294
299 fn sample_node_hex() -> String {
295 fn sample_node_hex() -> String {
300 hex_pad_right("0123456789abcdeffedcba9876543210deadbeef")
296 hex_pad_right("0123456789abcdeffedcba9876543210deadbeef")
301 }
297 }
302
298
303 #[test]
299 #[test]
304 fn test_node_from_hex() {
300 fn test_node_from_hex() {
305 assert_eq!(Node::from_hex(&sample_node_hex()).unwrap(), sample_node());
301 assert_eq!(Node::from_hex(&sample_node_hex()).unwrap(), sample_node());
306
302
307 let mut short = hex_pad_right("0123");
303 let mut short = hex_pad_right("0123");
308 short.pop();
304 short.pop();
309 short.pop();
305 short.pop();
310 assert!(Node::from_hex(&short).is_err());
306 assert!(Node::from_hex(&short).is_err());
311
307
312 let not_hex = hex_pad_right("012... oops");
308 let not_hex = hex_pad_right("012... oops");
313 assert!(Node::from_hex(&not_hex).is_err(),);
309 assert!(Node::from_hex(&not_hex).is_err(),);
314 }
310 }
315
311
316 #[test]
312 #[test]
317 fn test_node_encode_hex() {
313 fn test_node_encode_hex() {
318 assert_eq!(format!("{:x}", sample_node()), sample_node_hex());
314 assert_eq!(format!("{:x}", sample_node()), sample_node_hex());
319 }
315 }
320
316
321 #[test]
317 #[test]
322 fn test_prefix_from_hex() -> Result<(), FromHexError> {
318 fn test_prefix_from_hex() -> Result<(), FromHexError> {
323 assert_eq!(
319 assert_eq!(
324 NodePrefix::from_hex("0e1")?,
320 NodePrefix::from_hex("0e1")?,
325 NodePrefix {
321 NodePrefix {
326 buf: vec![14, 16],
322 buf: vec![14, 16],
327 is_odd: true
323 is_odd: true
328 }
324 }
329 );
325 );
330 assert_eq!(
326 assert_eq!(
331 NodePrefix::from_hex("0e1a")?,
327 NodePrefix::from_hex("0e1a")?,
332 NodePrefix {
328 NodePrefix {
333 buf: vec![14, 26],
329 buf: vec![14, 26],
334 is_odd: false
330 is_odd: false
335 }
331 }
336 );
332 );
337
333
338 // checking limit case
334 // checking limit case
339 let node_as_vec = sample_node().data.iter().cloned().collect();
335 let node_as_vec = sample_node().data.iter().cloned().collect();
340 assert_eq!(
336 assert_eq!(
341 NodePrefix::from_hex(sample_node_hex())?,
337 NodePrefix::from_hex(sample_node_hex())?,
342 NodePrefix {
338 NodePrefix {
343 buf: node_as_vec,
339 buf: node_as_vec,
344 is_odd: false
340 is_odd: false
345 }
341 }
346 );
342 );
347
343
348 Ok(())
344 Ok(())
349 }
345 }
350
346
351 #[test]
347 #[test]
352 fn test_prefix_from_hex_errors() {
348 fn test_prefix_from_hex_errors() {
353 assert!(NodePrefix::from_hex("testgr").is_err());
349 assert!(NodePrefix::from_hex("testgr").is_err());
354 let mut long = format!("{:x}", NULL_NODE);
350 let mut long = format!("{:x}", NULL_NODE);
355 long.push('c');
351 long.push('c');
356 assert!(NodePrefix::from_hex(&long).is_err())
352 assert!(NodePrefix::from_hex(&long).is_err())
357 }
353 }
358
354
359 #[test]
355 #[test]
360 fn test_is_prefix_of() -> Result<(), FromHexError> {
356 fn test_is_prefix_of() -> Result<(), FromHexError> {
361 let mut node_data = [0; NODE_BYTES_LENGTH];
357 let mut node_data = [0; NODE_BYTES_LENGTH];
362 node_data[0] = 0x12;
358 node_data[0] = 0x12;
363 node_data[1] = 0xca;
359 node_data[1] = 0xca;
364 let node = Node::from(node_data);
360 let node = Node::from(node_data);
365 assert!(NodePrefix::from_hex("12")?.borrow().is_prefix_of(&node));
361 assert!(NodePrefix::from_hex("12")?.borrow().is_prefix_of(&node));
366 assert!(!NodePrefix::from_hex("1a")?.borrow().is_prefix_of(&node));
362 assert!(!NodePrefix::from_hex("1a")?.borrow().is_prefix_of(&node));
367 assert!(NodePrefix::from_hex("12c")?.borrow().is_prefix_of(&node));
363 assert!(NodePrefix::from_hex("12c")?.borrow().is_prefix_of(&node));
368 assert!(!NodePrefix::from_hex("12d")?.borrow().is_prefix_of(&node));
364 assert!(!NodePrefix::from_hex("12d")?.borrow().is_prefix_of(&node));
369 Ok(())
365 Ok(())
370 }
366 }
371
367
372 #[test]
368 #[test]
373 fn test_get_nybble() -> Result<(), FromHexError> {
369 fn test_get_nybble() -> Result<(), FromHexError> {
374 let prefix = NodePrefix::from_hex("dead6789cafe")?;
370 let prefix = NodePrefix::from_hex("dead6789cafe")?;
375 assert_eq!(prefix.borrow().get_nybble(0), 13);
371 assert_eq!(prefix.borrow().get_nybble(0), 13);
376 assert_eq!(prefix.borrow().get_nybble(7), 9);
372 assert_eq!(prefix.borrow().get_nybble(7), 9);
377 Ok(())
373 Ok(())
378 }
374 }
379
375
380 #[test]
376 #[test]
381 fn test_first_different_nybble_even_prefix() {
377 fn test_first_different_nybble_even_prefix() {
382 let prefix = NodePrefix::from_hex("12ca").unwrap();
378 let prefix = NodePrefix::from_hex("12ca").unwrap();
383 let prefref = prefix.borrow();
379 let prefref = prefix.borrow();
384 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
380 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
385 assert_eq!(prefref.first_different_nybble(&node), Some(0));
381 assert_eq!(prefref.first_different_nybble(&node), Some(0));
386 node.data[0] = 0x13;
382 node.data[0] = 0x13;
387 assert_eq!(prefref.first_different_nybble(&node), Some(1));
383 assert_eq!(prefref.first_different_nybble(&node), Some(1));
388 node.data[0] = 0x12;
384 node.data[0] = 0x12;
389 assert_eq!(prefref.first_different_nybble(&node), Some(2));
385 assert_eq!(prefref.first_different_nybble(&node), Some(2));
390 node.data[1] = 0xca;
386 node.data[1] = 0xca;
391 // now it is a prefix
387 // now it is a prefix
392 assert_eq!(prefref.first_different_nybble(&node), None);
388 assert_eq!(prefref.first_different_nybble(&node), None);
393 }
389 }
394
390
395 #[test]
391 #[test]
396 fn test_first_different_nybble_odd_prefix() {
392 fn test_first_different_nybble_odd_prefix() {
397 let prefix = NodePrefix::from_hex("12c").unwrap();
393 let prefix = NodePrefix::from_hex("12c").unwrap();
398 let prefref = prefix.borrow();
394 let prefref = prefix.borrow();
399 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
395 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
400 assert_eq!(prefref.first_different_nybble(&node), Some(0));
396 assert_eq!(prefref.first_different_nybble(&node), Some(0));
401 node.data[0] = 0x13;
397 node.data[0] = 0x13;
402 assert_eq!(prefref.first_different_nybble(&node), Some(1));
398 assert_eq!(prefref.first_different_nybble(&node), Some(1));
403 node.data[0] = 0x12;
399 node.data[0] = 0x12;
404 assert_eq!(prefref.first_different_nybble(&node), Some(2));
400 assert_eq!(prefref.first_different_nybble(&node), Some(2));
405 node.data[1] = 0xca;
401 node.data[1] = 0xca;
406 // now it is a prefix
402 // now it is a prefix
407 assert_eq!(prefref.first_different_nybble(&node), None);
403 assert_eq!(prefref.first_different_nybble(&node), None);
408 }
404 }
409 }
405 }
410
406
411 #[cfg(test)]
407 #[cfg(test)]
412 pub use tests::hex_pad_right;
408 pub use tests::hex_pad_right;
General Comments 0
You need to be logged in to leave comments. Login now