# HG changeset patch # User Simon Sapin # Date 2021-01-25 11:28:39 # Node ID 5893706af3decde7b3a63ec4b4fa188d02cddecb # Parent 6380efb821912f25177103bdeec40d536dd6f919 rust: Simplify error type for reading hex node IDs If a string is not valid hexadecimal it’s not that useful to track the precise reason. Differential Revision: https://phab.mercurial-scm.org/D9861 diff --git a/rust/hg-core/src/revlog.rs b/rust/hg-core/src/revlog.rs --- a/rust/hg-core/src/revlog.rs +++ b/rust/hg-core/src/revlog.rs @@ -9,7 +9,7 @@ pub mod node; pub mod nodemap; mod nodemap_docket; pub mod path_encode; -pub use node::{Node, NodeError, NodePrefix, NodePrefixRef}; +pub use node::{FromHexError, Node, NodePrefix, NodePrefixRef}; pub mod changelog; pub mod index; pub mod manifest; diff --git a/rust/hg-core/src/revlog/node.rs b/rust/hg-core/src/revlog/node.rs --- a/rust/hg-core/src/revlog/node.rs +++ b/rust/hg-core/src/revlog/node.rs @@ -9,7 +9,7 @@ //! of a revision. use bytes_cast::BytesCast; -use hex::{self, FromHex, FromHexError}; +use hex::{self, FromHex}; use std::convert::TryFrom; use std::fmt; @@ -47,10 +47,9 @@ type NodeData = [u8; NODE_BYTES_LENGTH]; /// if they need a loop boundary. /// /// All methods that create a `Node` either take a type that enforces -/// the size or fail immediately at runtime with [`ExactLengthRequired`]. +/// the size or return an error at runtime. /// /// [`nybbles_len`]: #method.nybbles_len -/// [`ExactLengthRequired`]: struct.NodeError#variant.ExactLengthRequired #[derive(Clone, Debug, PartialEq, BytesCast)] #[repr(transparent)] pub struct Node { @@ -90,12 +89,8 @@ impl fmt::LowerHex for Node { } } -#[derive(Debug, PartialEq)] -pub enum NodeError { - ExactLengthRequired(usize, String), - PrefixTooLong(String), - HexError(FromHexError, String), -} +#[derive(Debug)] +pub struct FromHexError; /// Low level utility function, also for prefixes fn get_nybble(s: &[u8], i: usize) -> u8 { @@ -128,9 +123,9 @@ impl Node { /// /// To be used in FFI and I/O only, in order to facilitate future /// changes of hash format. - pub fn from_hex(hex: impl AsRef<[u8]>) -> Result { + pub fn from_hex(hex: impl AsRef<[u8]>) -> Result { Ok(NodeData::from_hex(hex.as_ref()) - .map_err(|e| NodeError::from((e, hex)))? + .map_err(|_| FromHexError)? .into()) } @@ -143,19 +138,6 @@ impl Node { } } -impl> From<(FromHexError, T)> for NodeError { - fn from(err_offender: (FromHexError, T)) -> Self { - let (err, offender) = err_offender; - let offender = String::from_utf8_lossy(offender.as_ref()).into_owned(); - match err { - FromHexError::InvalidStringLength => { - NodeError::ExactLengthRequired(NODE_NYBBLES_LENGTH, offender) - } - _ => NodeError::HexError(err, offender), - } - } -} - /// The beginning of a binary revision SHA. /// /// Since it can potentially come from an hexadecimal representation with @@ -175,31 +157,22 @@ impl NodePrefix { /// /// To be used in FFI and I/O only, in order to facilitate future /// changes of hash format. - pub fn from_hex(hex: impl AsRef<[u8]>) -> Result { + pub fn from_hex(hex: impl AsRef<[u8]>) -> Result { let hex = hex.as_ref(); let len = hex.len(); if len > NODE_NYBBLES_LENGTH { - return Err(NodeError::PrefixTooLong( - String::from_utf8_lossy(hex).to_owned().to_string(), - )); + return Err(FromHexError); } let is_odd = len % 2 == 1; let even_part = if is_odd { &hex[..len - 1] } else { hex }; let mut buf: Vec = - Vec::from_hex(&even_part).map_err(|e| (e, hex))?; + Vec::from_hex(&even_part).map_err(|_| FromHexError)?; if is_odd { let latest_char = char::from(hex[len - 1]); - let latest_nybble = latest_char.to_digit(16).ok_or_else(|| { - ( - FromHexError::InvalidHexCharacter { - c: latest_char, - index: len - 1, - }, - hex, - ) - })? as u8; + let latest_nybble = + latest_char.to_digit(16).ok_or_else(|| FromHexError)? as u8; buf.push(latest_nybble << 4); } Ok(NodePrefix { buf, is_odd }) @@ -329,24 +302,15 @@ mod tests { #[test] fn test_node_from_hex() { - assert_eq!(Node::from_hex(&sample_node_hex()), Ok(sample_node())); + assert_eq!(Node::from_hex(&sample_node_hex()).unwrap(), sample_node()); let mut short = hex_pad_right("0123"); short.pop(); short.pop(); - assert_eq!( - Node::from_hex(&short), - Err(NodeError::ExactLengthRequired(NODE_NYBBLES_LENGTH, short)), - ); + assert!(Node::from_hex(&short).is_err()); let not_hex = hex_pad_right("012... oops"); - assert_eq!( - Node::from_hex(¬_hex), - Err(NodeError::HexError( - FromHexError::InvalidHexCharacter { c: '.', index: 3 }, - not_hex, - )), - ); + assert!(Node::from_hex(¬_hex).is_err(),); } #[test] @@ -355,7 +319,7 @@ mod tests { } #[test] - fn test_prefix_from_hex() -> Result<(), NodeError> { + fn test_prefix_from_hex() -> Result<(), FromHexError> { assert_eq!( NodePrefix::from_hex("0e1")?, NodePrefix { @@ -386,25 +350,14 @@ mod tests { #[test] fn test_prefix_from_hex_errors() { - assert_eq!( - NodePrefix::from_hex("testgr"), - Err(NodeError::HexError( - FromHexError::InvalidHexCharacter { c: 't', index: 0 }, - "testgr".to_string() - )) - ); + assert!(NodePrefix::from_hex("testgr").is_err()); let mut long = format!("{:x}", NULL_NODE); long.push('c'); - match NodePrefix::from_hex(&long) - .expect_err("should be refused as too long") - { - NodeError::PrefixTooLong(s) => assert_eq!(s, long), - err => panic!(format!("Should have been TooLong, got {:?}", err)), - } + assert!(NodePrefix::from_hex(&long).is_err()) } #[test] - fn test_is_prefix_of() -> Result<(), NodeError> { + fn test_is_prefix_of() -> Result<(), FromHexError> { let mut node_data = [0; NODE_BYTES_LENGTH]; node_data[0] = 0x12; node_data[1] = 0xca; @@ -417,7 +370,7 @@ mod tests { } #[test] - fn test_get_nybble() -> Result<(), NodeError> { + fn test_get_nybble() -> Result<(), FromHexError> { let prefix = NodePrefix::from_hex("dead6789cafe")?; assert_eq!(prefix.borrow().get_nybble(0), 13); assert_eq!(prefix.borrow().get_nybble(7), 9); diff --git a/rust/hg-core/src/revlog/nodemap.rs b/rust/hg-core/src/revlog/nodemap.rs --- a/rust/hg-core/src/revlog/nodemap.rs +++ b/rust/hg-core/src/revlog/nodemap.rs @@ -13,7 +13,7 @@ //! is used in a more abstract context. use super::{ - node::NULL_NODE, Node, NodeError, NodePrefix, NodePrefixRef, Revision, + node::NULL_NODE, FromHexError, Node, NodePrefix, NodePrefixRef, Revision, RevlogIndex, NULL_REVISION, }; @@ -27,14 +27,14 @@ use std::ops::Index; #[derive(Debug, PartialEq)] pub enum NodeMapError { MultipleResults, - InvalidNodePrefix(NodeError), + InvalidNodePrefix, /// A `Revision` stored in the nodemap could not be found in the index RevisionNotInIndex(Revision), } -impl From for NodeMapError { - fn from(err: NodeError) -> Self { - NodeMapError::InvalidNodePrefix(err) +impl From for NodeMapError { + fn from(_: FromHexError) -> Self { + NodeMapError::InvalidNodePrefix } } diff --git a/rust/hg-cpython/src/revlog.rs b/rust/hg-cpython/src/revlog.rs --- a/rust/hg-cpython/src/revlog.rs +++ b/rust/hg-cpython/src/revlog.rs @@ -18,7 +18,7 @@ use cpython::{ use hg::{ nodemap::{Block, NodeMapError, NodeTree}, revlog::{nodemap::NodeMap, RevlogIndex}, - NodeError, Revision, + Revision, }; use std::cell::RefCell; @@ -468,17 +468,12 @@ fn nodemap_error(py: Python, err: NodeMa match err { NodeMapError::MultipleResults => revlog_error(py), NodeMapError::RevisionNotInIndex(r) => rev_not_in_index(py, r), - NodeMapError::InvalidNodePrefix(s) => invalid_node_prefix(py, &s), + NodeMapError::InvalidNodePrefix => { + PyErr::new::(py, "Invalid node or prefix") + } } } -fn invalid_node_prefix(py: Python, ne: &NodeError) -> PyErr { - PyErr::new::( - py, - format!("Invalid node or prefix: {:?}", ne), - ) -} - /// Create the module, with __package__ given from parent pub fn init_module(py: Python, package: &str) -> PyResult { let dotted_name = &format!("{}.revlog", package);