##// END OF EJS Templates
rust: Simplify error type for reading hex node IDs...
Simon Sapin -
r47156:5893706a default
parent child Browse files
Show More
@@ -9,7 +9,7 b' pub mod node;'
9 9 pub mod nodemap;
10 10 mod nodemap_docket;
11 11 pub mod path_encode;
12 pub use node::{Node, NodeError, NodePrefix, NodePrefixRef};
12 pub use node::{FromHexError, Node, NodePrefix, NodePrefixRef};
13 13 pub mod changelog;
14 14 pub mod index;
15 15 pub mod manifest;
@@ -9,7 +9,7 b''
9 9 //! of a revision.
10 10
11 11 use bytes_cast::BytesCast;
12 use hex::{self, FromHex, FromHexError};
12 use hex::{self, FromHex};
13 13 use std::convert::TryFrom;
14 14 use std::fmt;
15 15
@@ -47,10 +47,9 b' type NodeData = [u8; NODE_BYTES_LENGTH];'
47 47 /// if they need a loop boundary.
48 48 ///
49 49 /// All methods that create a `Node` either take a type that enforces
50 /// the size or fail immediately at runtime with [`ExactLengthRequired`].
50 /// the size or return an error at runtime.
51 51 ///
52 52 /// [`nybbles_len`]: #method.nybbles_len
53 /// [`ExactLengthRequired`]: struct.NodeError#variant.ExactLengthRequired
54 53 #[derive(Clone, Debug, PartialEq, BytesCast)]
55 54 #[repr(transparent)]
56 55 pub struct Node {
@@ -90,12 +89,8 b' impl fmt::LowerHex for Node {'
90 89 }
91 90 }
92 91
93 #[derive(Debug, PartialEq)]
94 pub enum NodeError {
95 ExactLengthRequired(usize, String),
96 PrefixTooLong(String),
97 HexError(FromHexError, String),
98 }
92 #[derive(Debug)]
93 pub struct FromHexError;
99 94
100 95 /// Low level utility function, also for prefixes
101 96 fn get_nybble(s: &[u8], i: usize) -> u8 {
@@ -128,9 +123,9 b' impl Node {'
128 123 ///
129 124 /// To be used in FFI and I/O only, in order to facilitate future
130 125 /// changes of hash format.
131 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Node, NodeError> {
126 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Node, FromHexError> {
132 127 Ok(NodeData::from_hex(hex.as_ref())
133 .map_err(|e| NodeError::from((e, hex)))?
128 .map_err(|_| FromHexError)?
134 129 .into())
135 130 }
136 131
@@ -143,19 +138,6 b' impl Node {'
143 138 }
144 139 }
145 140
146 impl<T: AsRef<[u8]>> From<(FromHexError, T)> for NodeError {
147 fn from(err_offender: (FromHexError, T)) -> Self {
148 let (err, offender) = err_offender;
149 let offender = String::from_utf8_lossy(offender.as_ref()).into_owned();
150 match err {
151 FromHexError::InvalidStringLength => {
152 NodeError::ExactLengthRequired(NODE_NYBBLES_LENGTH, offender)
153 }
154 _ => NodeError::HexError(err, offender),
155 }
156 }
157 }
158
159 141 /// The beginning of a binary revision SHA.
160 142 ///
161 143 /// Since it can potentially come from an hexadecimal representation with
@@ -175,31 +157,22 b' impl NodePrefix {'
175 157 ///
176 158 /// To be used in FFI and I/O only, in order to facilitate future
177 159 /// changes of hash format.
178 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Self, NodeError> {
160 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Self, FromHexError> {
179 161 let hex = hex.as_ref();
180 162 let len = hex.len();
181 163 if len > NODE_NYBBLES_LENGTH {
182 return Err(NodeError::PrefixTooLong(
183 String::from_utf8_lossy(hex).to_owned().to_string(),
184 ));
164 return Err(FromHexError);
185 165 }
186 166
187 167 let is_odd = len % 2 == 1;
188 168 let even_part = if is_odd { &hex[..len - 1] } else { hex };
189 169 let mut buf: Vec<u8> =
190 Vec::from_hex(&even_part).map_err(|e| (e, hex))?;
170 Vec::from_hex(&even_part).map_err(|_| FromHexError)?;
191 171
192 172 if is_odd {
193 173 let latest_char = char::from(hex[len - 1]);
194 let latest_nybble = latest_char.to_digit(16).ok_or_else(|| {
195 (
196 FromHexError::InvalidHexCharacter {
197 c: latest_char,
198 index: len - 1,
199 },
200 hex,
201 )
202 })? as u8;
174 let latest_nybble =
175 latest_char.to_digit(16).ok_or_else(|| FromHexError)? as u8;
203 176 buf.push(latest_nybble << 4);
204 177 }
205 178 Ok(NodePrefix { buf, is_odd })
@@ -329,24 +302,15 b' mod tests {'
329 302
330 303 #[test]
331 304 fn test_node_from_hex() {
332 assert_eq!(Node::from_hex(&sample_node_hex()), Ok(sample_node()));
305 assert_eq!(Node::from_hex(&sample_node_hex()).unwrap(), sample_node());
333 306
334 307 let mut short = hex_pad_right("0123");
335 308 short.pop();
336 309 short.pop();
337 assert_eq!(
338 Node::from_hex(&short),
339 Err(NodeError::ExactLengthRequired(NODE_NYBBLES_LENGTH, short)),
340 );
310 assert!(Node::from_hex(&short).is_err());
341 311
342 312 let not_hex = hex_pad_right("012... oops");
343 assert_eq!(
344 Node::from_hex(&not_hex),
345 Err(NodeError::HexError(
346 FromHexError::InvalidHexCharacter { c: '.', index: 3 },
347 not_hex,
348 )),
349 );
313 assert!(Node::from_hex(&not_hex).is_err(),);
350 314 }
351 315
352 316 #[test]
@@ -355,7 +319,7 b' mod tests {'
355 319 }
356 320
357 321 #[test]
358 fn test_prefix_from_hex() -> Result<(), NodeError> {
322 fn test_prefix_from_hex() -> Result<(), FromHexError> {
359 323 assert_eq!(
360 324 NodePrefix::from_hex("0e1")?,
361 325 NodePrefix {
@@ -386,25 +350,14 b' mod tests {'
386 350
387 351 #[test]
388 352 fn test_prefix_from_hex_errors() {
389 assert_eq!(
390 NodePrefix::from_hex("testgr"),
391 Err(NodeError::HexError(
392 FromHexError::InvalidHexCharacter { c: 't', index: 0 },
393 "testgr".to_string()
394 ))
395 );
353 assert!(NodePrefix::from_hex("testgr").is_err());
396 354 let mut long = format!("{:x}", NULL_NODE);
397 355 long.push('c');
398 match NodePrefix::from_hex(&long)
399 .expect_err("should be refused as too long")
400 {
401 NodeError::PrefixTooLong(s) => assert_eq!(s, long),
402 err => panic!(format!("Should have been TooLong, got {:?}", err)),
403 }
356 assert!(NodePrefix::from_hex(&long).is_err())
404 357 }
405 358
406 359 #[test]
407 fn test_is_prefix_of() -> Result<(), NodeError> {
360 fn test_is_prefix_of() -> Result<(), FromHexError> {
408 361 let mut node_data = [0; NODE_BYTES_LENGTH];
409 362 node_data[0] = 0x12;
410 363 node_data[1] = 0xca;
@@ -417,7 +370,7 b' mod tests {'
417 370 }
418 371
419 372 #[test]
420 fn test_get_nybble() -> Result<(), NodeError> {
373 fn test_get_nybble() -> Result<(), FromHexError> {
421 374 let prefix = NodePrefix::from_hex("dead6789cafe")?;
422 375 assert_eq!(prefix.borrow().get_nybble(0), 13);
423 376 assert_eq!(prefix.borrow().get_nybble(7), 9);
@@ -13,7 +13,7 b''
13 13 //! is used in a more abstract context.
14 14
15 15 use super::{
16 node::NULL_NODE, Node, NodeError, NodePrefix, NodePrefixRef, Revision,
16 node::NULL_NODE, FromHexError, Node, NodePrefix, NodePrefixRef, Revision,
17 17 RevlogIndex, NULL_REVISION,
18 18 };
19 19
@@ -27,14 +27,14 b' use std::ops::Index;'
27 27 #[derive(Debug, PartialEq)]
28 28 pub enum NodeMapError {
29 29 MultipleResults,
30 InvalidNodePrefix(NodeError),
30 InvalidNodePrefix,
31 31 /// A `Revision` stored in the nodemap could not be found in the index
32 32 RevisionNotInIndex(Revision),
33 33 }
34 34
35 impl From<NodeError> for NodeMapError {
36 fn from(err: NodeError) -> Self {
37 NodeMapError::InvalidNodePrefix(err)
35 impl From<FromHexError> for NodeMapError {
36 fn from(_: FromHexError) -> Self {
37 NodeMapError::InvalidNodePrefix
38 38 }
39 39 }
40 40
@@ -18,7 +18,7 b' use cpython::{'
18 18 use hg::{
19 19 nodemap::{Block, NodeMapError, NodeTree},
20 20 revlog::{nodemap::NodeMap, RevlogIndex},
21 NodeError, Revision,
21 Revision,
22 22 };
23 23 use std::cell::RefCell;
24 24
@@ -468,15 +468,10 b' fn nodemap_error(py: Python, err: NodeMa'
468 468 match err {
469 469 NodeMapError::MultipleResults => revlog_error(py),
470 470 NodeMapError::RevisionNotInIndex(r) => rev_not_in_index(py, r),
471 NodeMapError::InvalidNodePrefix(s) => invalid_node_prefix(py, &s),
471 NodeMapError::InvalidNodePrefix => {
472 PyErr::new::<ValueError, _>(py, "Invalid node or prefix")
472 473 }
473 474 }
474
475 fn invalid_node_prefix(py: Python, ne: &NodeError) -> PyErr {
476 PyErr::new::<ValueError, _>(
477 py,
478 format!("Invalid node or prefix: {:?}", ne),
479 )
480 475 }
481 476
482 477 /// Create the module, with __package__ given from parent
General Comments 0
You need to be logged in to leave comments. Login now