D7788: rust-node: binary Node and conversion utilities
gracinet (Georges Racinet)
phabricator at mercurial-scm.org
Mon Jan 6 19:26:16 UTC 2020
gracinet created this revision.
Herald added subscribers: mercurial-devel, kevincox, durin42.
Herald added a reviewer: hg-reviewers.
REVISION SUMMARY
Our choice of type makes sure that a `Node` has the exact
wanted size. We'll use a different type for prefixes.
REPOSITORY
rHG Mercurial
BRANCH
default
REVISION DETAIL
https://phab.mercurial-scm.org/D7788
AFFECTED FILES
rust/hg-core/src/dirstate/dirs_multiset.rs
rust/hg-core/src/matchers.rs
rust/hg-core/src/revlog.rs
rust/hg-core/src/revlog/node.rs
rust/hg-core/src/utils.rs
rust/hg-core/src/utils/hg_path.rs
CHANGE DETAILS
diff --git a/rust/hg-core/src/utils/hg_path.rs b/rust/hg-core/src/utils/hg_path.rs
--- a/rust/hg-core/src/utils/hg_path.rs
+++ b/rust/hg-core/src/utils/hg_path.rs
@@ -157,7 +157,7 @@
return Err(HgPathError::ContainsNullByte(
bytes.to_vec(),
index,
- ))
+ ));
}
b'/' => {
if previous_byte.is_some() && previous_byte == Some(b'/') {
diff --git a/rust/hg-core/src/utils.rs b/rust/hg-core/src/utils.rs
--- a/rust/hg-core/src/utils.rs
+++ b/rust/hg-core/src/utils.rs
@@ -18,10 +18,7 @@
/// use crate::hg::utils::replace_slice;
/// let mut line = b"I hate writing tests!".to_vec();
/// replace_slice(&mut line, b"hate", b"love");
-/// assert_eq!(
-/// line,
-/// b"I love writing tests!".to_vec()
-/// );
+/// assert_eq!(line, b"I love writing tests!".to_vec());
/// ```
pub fn replace_slice<T>(buf: &mut [T], from: &[T], to: &[T])
where
@@ -66,18 +63,9 @@
/// ```
/// use hg::utils::SliceExt;
- /// assert_eq!(
- /// b" to trim ".trim(),
- /// b"to trim"
- /// );
- /// assert_eq!(
- /// b"to trim ".trim(),
- /// b"to trim"
- /// );
- /// assert_eq!(
- /// b" to trim".trim(),
- /// b"to trim"
- /// );
+ /// assert_eq!(b" to trim ".trim(), b"to trim");
+ /// assert_eq!(b"to trim ".trim(), b"to trim");
+ /// assert_eq!(b" to trim".trim(), b"to trim");
/// ```
fn trim(&self) -> &[u8] {
self.trim_start().trim_end()
diff --git a/rust/hg-core/src/revlog/node.rs b/rust/hg-core/src/revlog/node.rs
new file mode 100644
--- /dev/null
+++ b/rust/hg-core/src/revlog/node.rs
@@ -0,0 +1,91 @@
+// Copyright 2019-2020 Georges Racinet <georges.racinet at octobus.net>
+//
+// This software may be used and distributed according to the terms of the
+// GNU General Public License version 2 or any later version.
+
+//! Definitions and utilities for Revision nodes
+//!
+//! In Mercurial code base, it is customary to call "a node" the binary SHA
+//! of a revision.
+
+use std::num::ParseIntError;
+
+/// Binary revisions SHA
+pub type Node = [u8; 20];
+
+/// The node value for NULL_REVISION
+pub const NULL_NODE: Node = [0; 20];
+
+#[derive(Debug, PartialEq)]
+pub enum NodeError {
+ ExactLengthRequired(String),
+ NotHexadecimal,
+}
+
+pub fn node_from_hex(hex: &str) -> Result<Node, NodeError> {
+ if hex.len() != 40 {
+ return Err(NodeError::ExactLengthRequired(hex.to_string()));
+ }
+ let mut node = [0; 20];
+ for i in 0..20 {
+ node[i] = u8::from_str_radix(&hex[i * 2..i * 2 + 2], 16)?
+ }
+ Ok(node)
+}
+
+pub fn node_to_hex(n: &Node) -> String {
+ let as_vec: Vec<String> = n.iter().map(|b| format!("{:02x}", b)).collect();
+ as_vec.join("")
+}
+
+/// Retrieve the `i`th half-byte from a bytes slice
+///
+/// This is also the `i`th hexadecimal digit in numeric form,
+/// also called a [nybble](https://en.wikipedia.org/wiki/Nibble).
+pub fn get_nybble(i: usize, s: &[u8]) -> u8 {
+ if i % 2 == 0 {
+ s[i / 2] >> 4
+ } else {
+ s[i / 2] & 0x0f
+ }
+}
+
+impl From<ParseIntError> for NodeError {
+ fn from(_: ParseIntError) -> Self {
+ NodeError::NotHexadecimal
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ const SAMPLE_NODE_HEX: &str = "0123456789abcdeffedcba9876543210deadbeef";
+
+ #[test]
+ fn test_node_from_hex() {
+ assert_eq!(
+ node_from_hex(SAMPLE_NODE_HEX),
+ Ok([
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc,
+ 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xde, 0xad, 0xbe, 0xef
+ ])
+ );
+ let short = "0123456789abcdeffedcba9876543210";
+ assert_eq!(
+ node_from_hex(short),
+ Err(NodeError::ExactLengthRequired(short.to_string())),
+ );
+ }
+
+ #[test]
+ fn test_node_to_hex() {
+ assert_eq!(
+ node_to_hex(&[
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc,
+ 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xde, 0xad, 0xbe, 0xef
+ ]),
+ SAMPLE_NODE_HEX
+ );
+ }
+}
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
@@ -5,7 +5,9 @@
// GNU General Public License version 2 or any later version.
//! Mercurial concepts for handling revision history
+pub mod node;
pub mod nodemap;
+pub use node::{Node, NodeError};
/// Mercurial revision numbers
///
diff --git a/rust/hg-core/src/matchers.rs b/rust/hg-core/src/matchers.rs
--- a/rust/hg-core/src/matchers.rs
+++ b/rust/hg-core/src/matchers.rs
@@ -81,7 +81,10 @@
/// Matches everything.
///```
-/// use hg::{ matchers::{Matcher, AlwaysMatcher}, utils::hg_path::HgPath };
+/// use hg::{
+/// matchers::{AlwaysMatcher, Matcher},
+/// utils::hg_path::HgPath,
+/// };
///
/// let matcher = AlwaysMatcher;
///
@@ -121,7 +124,10 @@
/// patterns.
///
///```
-/// use hg::{ matchers::{Matcher, FileMatcher}, utils::hg_path::HgPath };
+/// use hg::{
+/// matchers::{FileMatcher, Matcher},
+/// utils::hg_path::HgPath,
+/// };
///
/// let files = [HgPath::new(b"a.txt"), HgPath::new(br"re:.*\.c$")];
/// let matcher = FileMatcher::new(&files).unwrap();
diff --git a/rust/hg-core/src/dirstate/dirs_multiset.rs b/rust/hg-core/src/dirstate/dirs_multiset.rs
--- a/rust/hg-core/src/dirstate/dirs_multiset.rs
+++ b/rust/hg-core/src/dirstate/dirs_multiset.rs
@@ -108,7 +108,7 @@
Entry::Vacant(_) => {
return Err(DirstateMapError::PathNotFound(
path.as_ref().to_owned(),
- ))
+ ));
}
};
}
To: gracinet, #hg-reviewers
Cc: durin42, kevincox, mercurial-devel
More information about the Mercurial-devel
mailing list