##// END OF EJS Templates
rust: Make NodePrefix allocation-free and Copy, remove NodePrefixRef...
Simon Sapin -
r47160:645ee722 default
parent child Browse files
Show More
@@ -286,11 +286,6 b' dependencies = ['
286 ]
286 ]
287
287
288 [[package]]
288 [[package]]
289 name = "hex"
290 version = "0.4.2"
291 source = "registry+https://github.com/rust-lang/crates.io-index"
292
293 [[package]]
294 name = "hg-core"
289 name = "hg-core"
295 version = "0.1.0"
290 version = "0.1.0"
296 dependencies = [
291 dependencies = [
@@ -300,7 +295,6 b' dependencies = ['
300 "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
295 "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
301 "flate2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
296 "flate2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
302 "format-bytes 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
297 "format-bytes 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
303 "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
304 "im-rc 15.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
298 "im-rc 15.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
305 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
299 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
306 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
300 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -956,7 +950,6 b' dependencies = ['
956 "checksum getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
950 "checksum getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
957 "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
951 "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
958 "checksum hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
952 "checksum hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
959 "checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
960 "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
953 "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
961 "checksum im-rc 15.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca8957e71f04a205cb162508f9326aea04676c8dfd0711220190d6b83664f3f"
954 "checksum im-rc 15.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca8957e71f04a205cb162508f9326aea04676c8dfd0711220190d6b83664f3f"
962 "checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
955 "checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
@@ -11,7 +11,6 b' name = "hg"'
11 [dependencies]
11 [dependencies]
12 bytes-cast = "0.1"
12 bytes-cast = "0.1"
13 byteorder = "1.3.4"
13 byteorder = "1.3.4"
14 hex = "0.4.2"
15 im-rc = "15.0.*"
14 im-rc = "15.0.*"
16 lazy_static = "1.4.0"
15 lazy_static = "1.4.0"
17 memchr = "2.3.3"
16 memchr = "2.3.3"
@@ -88,13 +88,13 b' pub fn cat('
88 _ => {
88 _ => {
89 let changelog_node = NodePrefix::from_hex(&rev)
89 let changelog_node = NodePrefix::from_hex(&rev)
90 .map_err(|_| CatRevErrorKind::InvalidRevision)?;
90 .map_err(|_| CatRevErrorKind::InvalidRevision)?;
91 changelog.get_node(changelog_node.borrow())?
91 changelog.get_node(changelog_node)?
92 }
92 }
93 };
93 };
94 let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?)
94 let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?)
95 .map_err(|_| CatRevErrorKind::CorruptedRevlog)?;
95 .map_err(|_| CatRevErrorKind::CorruptedRevlog)?;
96
96
97 let manifest_entry = manifest.get_node((&manifest_node).into())?;
97 let manifest_entry = manifest.get_node(manifest_node.into())?;
98 let mut bytes = vec![];
98 let mut bytes = vec![];
99
99
100 for (manifest_file, node_bytes) in manifest_entry.files_with_nodes() {
100 for (manifest_file, node_bytes) in manifest_entry.files_with_nodes() {
@@ -107,7 +107,7 b' pub fn cat('
107 Revlog::open(repo, &index_path, Some(&data_path))?;
107 Revlog::open(repo, &index_path, Some(&data_path))?;
108 let file_node = Node::from_hex(node_bytes)
108 let file_node = Node::from_hex(node_bytes)
109 .map_err(|_| CatRevErrorKind::CorruptedRevlog)?;
109 .map_err(|_| CatRevErrorKind::CorruptedRevlog)?;
110 let file_rev = file_log.get_node_rev((&file_node).into())?;
110 let file_rev = file_log.get_node_rev(file_node.into())?;
111 let data = file_log.get_rev_data(file_rev)?;
111 let data = file_log.get_rev_data(file_rev)?;
112 if data.starts_with(&METADATA_DELIMITER) {
112 if data.starts_with(&METADATA_DELIMITER) {
113 let end_delimiter_position = data
113 let end_delimiter_position = data
@@ -93,7 +93,7 b' pub fn debug_data('
93 _ => {
93 _ => {
94 let node = NodePrefix::from_hex(&rev)
94 let node = NodePrefix::from_hex(&rev)
95 .map_err(|_| DebugDataErrorKind::InvalidRevision)?;
95 .map_err(|_| DebugDataErrorKind::InvalidRevision)?;
96 let rev = revlog.get_node_rev(node.borrow())?;
96 let rev = revlog.get_node_rev(node)?;
97 revlog.get_rev_data(rev)?
97 revlog.get_rev_data(rev)?
98 }
98 }
99 };
99 };
@@ -147,12 +147,12 b' pub fn list_rev_tracked_files('
147 _ => {
147 _ => {
148 let changelog_node = NodePrefix::from_hex(&rev)
148 let changelog_node = NodePrefix::from_hex(&rev)
149 .or(Err(ListRevTrackedFilesErrorKind::InvalidRevision))?;
149 .or(Err(ListRevTrackedFilesErrorKind::InvalidRevision))?;
150 changelog.get_node(changelog_node.borrow())?
150 changelog.get_node(changelog_node)?
151 }
151 }
152 };
152 };
153 let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?)
153 let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?)
154 .or(Err(ListRevTrackedFilesErrorKind::CorruptedRevlog))?;
154 .or(Err(ListRevTrackedFilesErrorKind::CorruptedRevlog))?;
155 let manifest_entry = manifest.get_node((&manifest_node).into())?;
155 let manifest_entry = manifest.get_node(manifest_node.into())?;
156 Ok(FilesForRev(manifest_entry))
156 Ok(FilesForRev(manifest_entry))
157 }
157 }
158
158
@@ -9,7 +9,7 b' pub mod node;'
9 pub mod nodemap;
9 pub mod nodemap;
10 mod nodemap_docket;
10 mod nodemap_docket;
11 pub mod path_encode;
11 pub mod path_encode;
12 pub use node::{FromHexError, Node, NodePrefix, NodePrefixRef};
12 pub use node::{FromHexError, Node, NodePrefix};
13 pub mod changelog;
13 pub mod changelog;
14 pub mod index;
14 pub mod index;
15 pub mod manifest;
15 pub mod manifest;
@@ -1,6 +1,6 b''
1 use crate::repo::Repo;
1 use crate::repo::Repo;
2 use crate::revlog::revlog::{Revlog, RevlogError};
2 use crate::revlog::revlog::{Revlog, RevlogError};
3 use crate::revlog::NodePrefixRef;
3 use crate::revlog::NodePrefix;
4 use crate::revlog::Revision;
4 use crate::revlog::Revision;
5
5
6 /// A specialized `Revlog` to work with `changelog` data format.
6 /// A specialized `Revlog` to work with `changelog` data format.
@@ -19,7 +19,7 b' impl Changelog {'
19 /// Return the `ChangelogEntry` a given node id.
19 /// Return the `ChangelogEntry` a given node id.
20 pub fn get_node(
20 pub fn get_node(
21 &self,
21 &self,
22 node: NodePrefixRef,
22 node: NodePrefix,
23 ) -> Result<ChangelogEntry, RevlogError> {
23 ) -> Result<ChangelogEntry, RevlogError> {
24 let rev = self.revlog.get_node_rev(node)?;
24 let rev = self.revlog.get_node_rev(node)?;
25 self.get_rev(rev)
25 self.get_rev(rev)
@@ -1,6 +1,6 b''
1 use crate::repo::Repo;
1 use crate::repo::Repo;
2 use crate::revlog::revlog::{Revlog, RevlogError};
2 use crate::revlog::revlog::{Revlog, RevlogError};
3 use crate::revlog::NodePrefixRef;
3 use crate::revlog::NodePrefix;
4 use crate::revlog::Revision;
4 use crate::revlog::Revision;
5 use crate::utils::hg_path::HgPath;
5 use crate::utils::hg_path::HgPath;
6
6
@@ -20,7 +20,7 b' impl Manifest {'
20 /// Return the `ManifestEntry` of a given node id.
20 /// Return the `ManifestEntry` of a given node id.
21 pub fn get_node(
21 pub fn get_node(
22 &self,
22 &self,
23 node: NodePrefixRef,
23 node: NodePrefix,
24 ) -> Result<ManifestEntry, RevlogError> {
24 ) -> Result<ManifestEntry, RevlogError> {
25 let rev = self.revlog.get_node_rev(node)?;
25 let rev = self.revlog.get_node_rev(node)?;
26 self.get_rev(rev)
26 self.get_rev(rev)
@@ -9,8 +9,7 b''
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 std::convert::{TryFrom, TryInto};
13 use std::convert::TryFrom;
14 use std::fmt;
13 use std::fmt;
15
14
16 /// The length in bytes of a `Node`
15 /// The length in bytes of a `Node`
@@ -50,7 +49,7 b' type NodeData = [u8; NODE_BYTES_LENGTH];'
50 /// the size or return an error at runtime.
49 /// the size or return an error at runtime.
51 ///
50 ///
52 /// [`nybbles_len`]: #method.nybbles_len
51 /// [`nybbles_len`]: #method.nybbles_len
53 #[derive(Clone, Debug, PartialEq, BytesCast)]
52 #[derive(Copy, Clone, Debug, PartialEq, BytesCast)]
54 #[repr(transparent)]
53 #[repr(transparent)]
55 pub struct Node {
54 pub struct Node {
56 data: NodeData,
55 data: NodeData,
@@ -72,7 +71,7 b" impl<'a> TryFrom<&'a [u8]> for &'a Node "
72 type Error = ();
71 type Error = ();
73
72
74 #[inline]
73 #[inline]
75 fn try_from(bytes: &'a [u8]) -> Result<&'a Node, Self::Error> {
74 fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
76 match Node::from_bytes(bytes) {
75 match Node::from_bytes(bytes) {
77 Ok((node, rest)) if rest.is_empty() => Ok(node),
76 Ok((node, rest)) if rest.is_empty() => Ok(node),
78 _ => Err(()),
77 _ => Err(()),
@@ -80,6 +79,17 b" impl<'a> TryFrom<&'a [u8]> for &'a Node "
80 }
79 }
81 }
80 }
82
81
82 /// Return an error if the slice has an unexpected length
83 impl TryFrom<&'_ [u8]> for Node {
84 type Error = std::array::TryFromSliceError;
85
86 #[inline]
87 fn try_from(bytes: &'_ [u8]) -> Result<Self, Self::Error> {
88 let data = bytes.try_into()?;
89 Ok(Self { data })
90 }
91 }
92
83 impl fmt::LowerHex for Node {
93 impl fmt::LowerHex for Node {
84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85 for &byte in &self.data {
95 for &byte in &self.data {
@@ -124,9 +134,12 b' impl Node {'
124 /// To be used in FFI and I/O only, in order to facilitate future
134 /// To be used in FFI and I/O only, in order to facilitate future
125 /// changes of hash format.
135 /// changes of hash format.
126 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Node, FromHexError> {
136 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Node, FromHexError> {
127 Ok(NodeData::from_hex(hex.as_ref())
137 let prefix = NodePrefix::from_hex(hex)?;
128 .map_err(|_| FromHexError)?
138 if prefix.nybbles_len() == NODE_NYBBLES_LENGTH {
129 .into())
139 Ok(Self { data: prefix.data })
140 } else {
141 Err(FromHexError)
142 }
130 }
143 }
131
144
132 /// Provide access to binary data
145 /// Provide access to binary data
@@ -143,10 +156,14 b' impl Node {'
143 /// Since it can potentially come from an hexadecimal representation with
156 /// 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
157 /// odd length, it needs to carry around whether the last 4 bits are relevant
145 /// or not.
158 /// or not.
146 #[derive(Debug, PartialEq)]
159 #[derive(Debug, PartialEq, Copy, Clone)]
147 pub struct NodePrefix {
160 pub struct NodePrefix {
148 buf: Vec<u8>,
161 /// In `1..=NODE_NYBBLES_LENGTH`
149 is_odd: bool,
162 nybbles_len: u8,
163 /// The first `4 * length_in_nybbles` bits are used (considering bits
164 /// within a bytes in big-endian: most significant first), the rest
165 /// are zero.
166 data: NodeData,
150 }
167 }
151
168
152 impl NodePrefix {
169 impl NodePrefix {
@@ -164,52 +181,35 b' impl NodePrefix {'
164 return Err(FromHexError);
181 return Err(FromHexError);
165 }
182 }
166
183
167 let is_odd = len % 2 == 1;
184 let mut data = [0; NODE_BYTES_LENGTH];
168 let even_part = if is_odd { &hex[..len - 1] } else { hex };
185 let mut nybbles_len = 0;
169 let mut buf: Vec<u8> =
186 for &ascii_byte in hex {
170 Vec::from_hex(&even_part).map_err(|_| FromHexError)?;
187 let nybble = match char::from(ascii_byte).to_digit(16) {
171
188 Some(digit) => digit as u8,
172 if is_odd {
189 None => return Err(FromHexError),
173 let latest_char = char::from(hex[len - 1]);
190 };
174 let latest_nybble =
191 // Fill in the upper half of a byte first, then the lower half.
175 latest_char.to_digit(16).ok_or_else(|| FromHexError)? as u8;
192 let shift = if nybbles_len % 2 == 0 { 4 } else { 0 };
176 buf.push(latest_nybble << 4);
193 data[nybbles_len as usize / 2] |= nybble << shift;
194 nybbles_len += 1;
177 }
195 }
178 Ok(NodePrefix { buf, is_odd })
196 Ok(Self { data, nybbles_len })
179 }
197 }
180
198
181 pub fn borrow(&self) -> NodePrefixRef {
199 pub fn nybbles_len(&self) -> usize {
182 NodePrefixRef {
200 self.nybbles_len as _
183 buf: &self.buf,
184 is_odd: self.is_odd,
185 }
186 }
187 }
188
189 #[derive(Clone, Debug, PartialEq)]
190 pub struct NodePrefixRef<'a> {
191 buf: &'a [u8],
192 is_odd: bool,
193 }
194
195 impl<'a> NodePrefixRef<'a> {
196 pub fn len(&self) -> usize {
197 if self.is_odd {
198 self.buf.len() * 2 - 1
199 } else {
200 self.buf.len() * 2
201 }
202 }
201 }
203
202
204 pub fn is_prefix_of(&self, node: &Node) -> bool {
203 pub fn is_prefix_of(&self, node: &Node) -> bool {
205 if self.is_odd {
204 let full_bytes = self.nybbles_len() / 2;
206 let buf = self.buf;
205 if self.data[..full_bytes] != node.data[..full_bytes] {
207 let last_pos = buf.len() - 1;
206 return false;
208 node.data.starts_with(buf.split_at(last_pos).0)
209 && node.data[last_pos] >> 4 == buf[last_pos] >> 4
210 } else {
211 node.data.starts_with(self.buf)
212 }
207 }
208 if self.nybbles_len() % 2 == 0 {
209 return true;
210 }
211 let last = self.nybbles_len() - 1;
212 self.get_nybble(last) == node.get_nybble(last)
213 }
213 }
214
214
215 /// Retrieve the `i`th half-byte from the prefix.
215 /// Retrieve the `i`th half-byte from the prefix.
@@ -217,8 +217,12 b" impl<'a> NodePrefixRef<'a> {"
217 /// This is also the `i`th hexadecimal digit in numeric form,
217 /// This is also the `i`th hexadecimal digit in numeric form,
218 /// also called a [nybble](https://en.wikipedia.org/wiki/Nibble).
218 /// also called a [nybble](https://en.wikipedia.org/wiki/Nibble).
219 pub fn get_nybble(&self, i: usize) -> u8 {
219 pub fn get_nybble(&self, i: usize) -> u8 {
220 assert!(i < self.len());
220 assert!(i < self.nybbles_len());
221 get_nybble(self.buf, i)
221 get_nybble(&self.data, i)
222 }
223
224 fn iter_nybbles(&self) -> impl Iterator<Item = u8> + '_ {
225 (0..self.nybbles_len()).map(move |i| get_nybble(&self.data, i))
222 }
226 }
223
227
224 /// Return the index first nybble that's different from `node`
228 /// Return the index first nybble that's different from `node`
@@ -229,42 +233,49 b" impl<'a> NodePrefixRef<'a> {"
229 ///
233 ///
230 /// Returned index is as in `get_nybble`, i.e., starting at 0.
234 /// Returned index is as in `get_nybble`, i.e., starting at 0.
231 pub fn first_different_nybble(&self, node: &Node) -> Option<usize> {
235 pub fn first_different_nybble(&self, node: &Node) -> Option<usize> {
232 let buf = self.buf;
236 self.iter_nybbles()
233 let until = if self.is_odd {
237 .zip(NodePrefix::from(*node).iter_nybbles())
234 buf.len() - 1
238 .position(|(a, b)| a != b)
235 } else {
239 }
236 buf.len()
240 }
237 };
241
238 for (i, item) in buf.iter().enumerate().take(until) {
242 impl fmt::LowerHex for NodePrefix {
239 if *item != node.data[i] {
243 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
240 return if *item & 0xf0 == node.data[i] & 0xf0 {
244 let full_bytes = self.nybbles_len() / 2;
241 Some(2 * i + 1)
245 for &byte in &self.data[..full_bytes] {
242 } else {
246 write!(f, "{:02x}", byte)?
243 Some(2 * i)
244 };
245 }
246 }
247 }
247 if self.is_odd && buf[until] & 0xf0 != node.data[until] & 0xf0 {
248 if self.nybbles_len() % 2 == 1 {
248 Some(until * 2)
249 let last = self.nybbles_len() - 1;
249 } else {
250 write!(f, "{:x}", self.get_nybble(last))?
250 None
251 }
252 Ok(())
253 }
254 }
255
256 /// A shortcut for full `Node` references
257 impl From<&'_ Node> for NodePrefix {
258 fn from(node: &'_ Node) -> Self {
259 NodePrefix {
260 nybbles_len: node.nybbles_len() as _,
261 data: node.data,
251 }
262 }
252 }
263 }
253 }
264 }
254
265
255 /// A shortcut for full `Node` references
266 /// A shortcut for full `Node` references
256 impl<'a> From<&'a Node> for NodePrefixRef<'a> {
267 impl From<Node> for NodePrefix {
257 fn from(node: &'a Node) -> Self {
268 fn from(node: Node) -> Self {
258 NodePrefixRef {
269 NodePrefix {
259 buf: &node.data,
270 nybbles_len: node.nybbles_len() as _,
260 is_odd: false,
271 data: node.data,
261 }
272 }
262 }
273 }
263 }
274 }
264
275
265 impl PartialEq<Node> for NodePrefixRef<'_> {
276 impl PartialEq<Node> for NodePrefix {
266 fn eq(&self, other: &Node) -> bool {
277 fn eq(&self, other: &Node) -> bool {
267 !self.is_odd && self.buf == other.data
278 Self::from(*other) == *self
268 }
279 }
269 }
280 }
270
281
@@ -272,18 +283,16 b" impl PartialEq<Node> for NodePrefixRef<'"
272 mod tests {
283 mod tests {
273 use super::*;
284 use super::*;
274
285
275 fn sample_node() -> Node {
286 const SAMPLE_NODE_HEX: &str = "0123456789abcdeffedcba9876543210deadbeef";
276 let mut data = [0; NODE_BYTES_LENGTH];
287 const SAMPLE_NODE: Node = Node {
277 data.copy_from_slice(&[
288 data: [
278 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba,
289 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba,
279 0x98, 0x76, 0x54, 0x32, 0x10, 0xde, 0xad, 0xbe, 0xef,
290 0x98, 0x76, 0x54, 0x32, 0x10, 0xde, 0xad, 0xbe, 0xef,
280 ]);
291 ],
281 data.into()
292 };
282 }
283
293
284 /// Pad an hexadecimal string to reach `NODE_NYBBLES_LENGTH`
294 /// Pad an hexadecimal string to reach `NODE_NYBBLES_LENGTH`
285 ///check_hash
295 /// The padding is made with zeros.
286 /// The padding is made with zeros
287 pub fn hex_pad_right(hex: &str) -> String {
296 pub fn hex_pad_right(hex: &str) -> String {
288 let mut res = hex.to_string();
297 let mut res = hex.to_string();
289 while res.len() < NODE_NYBBLES_LENGTH {
298 while res.len() < NODE_NYBBLES_LENGTH {
@@ -292,55 +301,30 b' mod tests {'
292 res
301 res
293 }
302 }
294
303
295 fn sample_node_hex() -> String {
296 hex_pad_right("0123456789abcdeffedcba9876543210deadbeef")
297 }
298
299 #[test]
304 #[test]
300 fn test_node_from_hex() {
305 fn test_node_from_hex() {
301 assert_eq!(Node::from_hex(&sample_node_hex()).unwrap(), sample_node());
306 let not_hex = "012... oops";
302
307 let too_short = "0123";
303 let mut short = hex_pad_right("0123");
308 let too_long = format!("{}0", SAMPLE_NODE_HEX);
304 short.pop();
309 assert_eq!(Node::from_hex(SAMPLE_NODE_HEX).unwrap(), SAMPLE_NODE);
305 short.pop();
310 assert!(Node::from_hex(not_hex).is_err());
306 assert!(Node::from_hex(&short).is_err());
311 assert!(Node::from_hex(too_short).is_err());
307
312 assert!(Node::from_hex(&too_long).is_err());
308 let not_hex = hex_pad_right("012... oops");
309 assert!(Node::from_hex(&not_hex).is_err(),);
310 }
313 }
311
314
312 #[test]
315 #[test]
313 fn test_node_encode_hex() {
316 fn test_node_encode_hex() {
314 assert_eq!(format!("{:x}", sample_node()), sample_node_hex());
317 assert_eq!(format!("{:x}", SAMPLE_NODE), SAMPLE_NODE_HEX);
315 }
318 }
316
319
317 #[test]
320 #[test]
318 fn test_prefix_from_hex() -> Result<(), FromHexError> {
321 fn test_prefix_from_to_hex() -> Result<(), FromHexError> {
319 assert_eq!(
322 assert_eq!(format!("{:x}", NodePrefix::from_hex("0e1")?), "0e1");
320 NodePrefix::from_hex("0e1")?,
323 assert_eq!(format!("{:x}", NodePrefix::from_hex("0e1a")?), "0e1a");
321 NodePrefix {
322 buf: vec![14, 16],
323 is_odd: true
324 }
325 );
326 assert_eq!(
324 assert_eq!(
327 NodePrefix::from_hex("0e1a")?,
325 format!("{:x}", NodePrefix::from_hex(SAMPLE_NODE_HEX)?),
328 NodePrefix {
326 SAMPLE_NODE_HEX
329 buf: vec![14, 26],
330 is_odd: false
331 }
332 );
327 );
333
334 // checking limit case
335 let node_as_vec = sample_node().data.iter().cloned().collect();
336 assert_eq!(
337 NodePrefix::from_hex(sample_node_hex())?,
338 NodePrefix {
339 buf: node_as_vec,
340 is_odd: false
341 }
342 );
343
344 Ok(())
328 Ok(())
345 }
329 }
346
330
@@ -358,49 +342,47 b' mod tests {'
358 node_data[0] = 0x12;
342 node_data[0] = 0x12;
359 node_data[1] = 0xca;
343 node_data[1] = 0xca;
360 let node = Node::from(node_data);
344 let node = Node::from(node_data);
361 assert!(NodePrefix::from_hex("12")?.borrow().is_prefix_of(&node));
345 assert!(NodePrefix::from_hex("12")?.is_prefix_of(&node));
362 assert!(!NodePrefix::from_hex("1a")?.borrow().is_prefix_of(&node));
346 assert!(!NodePrefix::from_hex("1a")?.is_prefix_of(&node));
363 assert!(NodePrefix::from_hex("12c")?.borrow().is_prefix_of(&node));
347 assert!(NodePrefix::from_hex("12c")?.is_prefix_of(&node));
364 assert!(!NodePrefix::from_hex("12d")?.borrow().is_prefix_of(&node));
348 assert!(!NodePrefix::from_hex("12d")?.is_prefix_of(&node));
365 Ok(())
349 Ok(())
366 }
350 }
367
351
368 #[test]
352 #[test]
369 fn test_get_nybble() -> Result<(), FromHexError> {
353 fn test_get_nybble() -> Result<(), FromHexError> {
370 let prefix = NodePrefix::from_hex("dead6789cafe")?;
354 let prefix = NodePrefix::from_hex("dead6789cafe")?;
371 assert_eq!(prefix.borrow().get_nybble(0), 13);
355 assert_eq!(prefix.get_nybble(0), 13);
372 assert_eq!(prefix.borrow().get_nybble(7), 9);
356 assert_eq!(prefix.get_nybble(7), 9);
373 Ok(())
357 Ok(())
374 }
358 }
375
359
376 #[test]
360 #[test]
377 fn test_first_different_nybble_even_prefix() {
361 fn test_first_different_nybble_even_prefix() {
378 let prefix = NodePrefix::from_hex("12ca").unwrap();
362 let prefix = NodePrefix::from_hex("12ca").unwrap();
379 let prefref = prefix.borrow();
380 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
363 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
381 assert_eq!(prefref.first_different_nybble(&node), Some(0));
364 assert_eq!(prefix.first_different_nybble(&node), Some(0));
382 node.data[0] = 0x13;
365 node.data[0] = 0x13;
383 assert_eq!(prefref.first_different_nybble(&node), Some(1));
366 assert_eq!(prefix.first_different_nybble(&node), Some(1));
384 node.data[0] = 0x12;
367 node.data[0] = 0x12;
385 assert_eq!(prefref.first_different_nybble(&node), Some(2));
368 assert_eq!(prefix.first_different_nybble(&node), Some(2));
386 node.data[1] = 0xca;
369 node.data[1] = 0xca;
387 // now it is a prefix
370 // now it is a prefix
388 assert_eq!(prefref.first_different_nybble(&node), None);
371 assert_eq!(prefix.first_different_nybble(&node), None);
389 }
372 }
390
373
391 #[test]
374 #[test]
392 fn test_first_different_nybble_odd_prefix() {
375 fn test_first_different_nybble_odd_prefix() {
393 let prefix = NodePrefix::from_hex("12c").unwrap();
376 let prefix = NodePrefix::from_hex("12c").unwrap();
394 let prefref = prefix.borrow();
395 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
377 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
396 assert_eq!(prefref.first_different_nybble(&node), Some(0));
378 assert_eq!(prefix.first_different_nybble(&node), Some(0));
397 node.data[0] = 0x13;
379 node.data[0] = 0x13;
398 assert_eq!(prefref.first_different_nybble(&node), Some(1));
380 assert_eq!(prefix.first_different_nybble(&node), Some(1));
399 node.data[0] = 0x12;
381 node.data[0] = 0x12;
400 assert_eq!(prefref.first_different_nybble(&node), Some(2));
382 assert_eq!(prefix.first_different_nybble(&node), Some(2));
401 node.data[1] = 0xca;
383 node.data[1] = 0xca;
402 // now it is a prefix
384 // now it is a prefix
403 assert_eq!(prefref.first_different_nybble(&node), None);
385 assert_eq!(prefix.first_different_nybble(&node), None);
404 }
386 }
405 }
387 }
406
388
@@ -13,8 +13,8 b''
13 //! is used in a more abstract context.
13 //! is used in a more abstract context.
14
14
15 use super::{
15 use super::{
16 node::NULL_NODE, FromHexError, Node, NodePrefix, NodePrefixRef, Revision,
16 node::NULL_NODE, FromHexError, Node, NodePrefix, Revision, RevlogIndex,
17 RevlogIndex, NULL_REVISION,
17 NULL_REVISION,
18 };
18 };
19
19
20 use bytes_cast::{unaligned, BytesCast};
20 use bytes_cast::{unaligned, BytesCast};
@@ -82,7 +82,7 b' pub trait NodeMap {'
82 fn find_bin<'a>(
82 fn find_bin<'a>(
83 &self,
83 &self,
84 idx: &impl RevlogIndex,
84 idx: &impl RevlogIndex,
85 prefix: NodePrefixRef<'a>,
85 prefix: NodePrefix,
86 ) -> Result<Option<Revision>, NodeMapError>;
86 ) -> Result<Option<Revision>, NodeMapError>;
87
87
88 /// Find the unique Revision whose `Node` hexadecimal string representation
88 /// Find the unique Revision whose `Node` hexadecimal string representation
@@ -97,7 +97,7 b' pub trait NodeMap {'
97 idx: &impl RevlogIndex,
97 idx: &impl RevlogIndex,
98 prefix: &str,
98 prefix: &str,
99 ) -> Result<Option<Revision>, NodeMapError> {
99 ) -> Result<Option<Revision>, NodeMapError> {
100 self.find_bin(idx, NodePrefix::from_hex(prefix)?.borrow())
100 self.find_bin(idx, NodePrefix::from_hex(prefix)?)
101 }
101 }
102
102
103 /// Give the size of the shortest node prefix that determines
103 /// Give the size of the shortest node prefix that determines
@@ -114,7 +114,7 b' pub trait NodeMap {'
114 fn unique_prefix_len_bin<'a>(
114 fn unique_prefix_len_bin<'a>(
115 &self,
115 &self,
116 idx: &impl RevlogIndex,
116 idx: &impl RevlogIndex,
117 node_prefix: NodePrefixRef<'a>,
117 node_prefix: NodePrefix,
118 ) -> Result<Option<usize>, NodeMapError>;
118 ) -> Result<Option<usize>, NodeMapError>;
119
119
120 /// Same as `unique_prefix_len_bin`, with the hexadecimal representation
120 /// Same as `unique_prefix_len_bin`, with the hexadecimal representation
@@ -124,7 +124,7 b' pub trait NodeMap {'
124 idx: &impl RevlogIndex,
124 idx: &impl RevlogIndex,
125 prefix: &str,
125 prefix: &str,
126 ) -> Result<Option<usize>, NodeMapError> {
126 ) -> Result<Option<usize>, NodeMapError> {
127 self.unique_prefix_len_bin(idx, NodePrefix::from_hex(prefix)?.borrow())
127 self.unique_prefix_len_bin(idx, NodePrefix::from_hex(prefix)?)
128 }
128 }
129
129
130 /// Same as `unique_prefix_len_bin`, with a full `Node` as input
130 /// Same as `unique_prefix_len_bin`, with a full `Node` as input
@@ -278,7 +278,7 b' impl Index<usize> for NodeTree {'
278 /// Return `None` unless the `Node` for `rev` has given prefix in `index`.
278 /// Return `None` unless the `Node` for `rev` has given prefix in `index`.
279 fn has_prefix_or_none(
279 fn has_prefix_or_none(
280 idx: &impl RevlogIndex,
280 idx: &impl RevlogIndex,
281 prefix: NodePrefixRef,
281 prefix: NodePrefix,
282 rev: Revision,
282 rev: Revision,
283 ) -> Result<Option<Revision>, NodeMapError> {
283 ) -> Result<Option<Revision>, NodeMapError> {
284 idx.node(rev)
284 idx.node(rev)
@@ -299,7 +299,7 b' fn has_prefix_or_none('
299 /// revision is the only one for a *subprefix* of the one being looked up.
299 /// revision is the only one for a *subprefix* of the one being looked up.
300 fn validate_candidate(
300 fn validate_candidate(
301 idx: &impl RevlogIndex,
301 idx: &impl RevlogIndex,
302 prefix: NodePrefixRef,
302 prefix: NodePrefix,
303 candidate: (Option<Revision>, usize),
303 candidate: (Option<Revision>, usize),
304 ) -> Result<(Option<Revision>, usize), NodeMapError> {
304 ) -> Result<(Option<Revision>, usize), NodeMapError> {
305 let (rev, steps) = candidate;
305 let (rev, steps) = candidate;
@@ -426,7 +426,7 b' impl NodeTree {'
426 /// `NodeTree`).
426 /// `NodeTree`).
427 fn lookup(
427 fn lookup(
428 &self,
428 &self,
429 prefix: NodePrefixRef,
429 prefix: NodePrefix,
430 ) -> Result<(Option<Revision>, usize), NodeMapError> {
430 ) -> Result<(Option<Revision>, usize), NodeMapError> {
431 for (i, visit_item) in self.visit(prefix).enumerate() {
431 for (i, visit_item) in self.visit(prefix).enumerate() {
432 if let Some(opt) = visit_item.final_revision() {
432 if let Some(opt) = visit_item.final_revision() {
@@ -436,10 +436,7 b' impl NodeTree {'
436 Err(NodeMapError::MultipleResults)
436 Err(NodeMapError::MultipleResults)
437 }
437 }
438
438
439 fn visit<'n, 'p>(
439 fn visit<'n>(&'n self, prefix: NodePrefix) -> NodeTreeVisitor<'n> {
440 &'n self,
441 prefix: NodePrefixRef<'p>,
442 ) -> NodeTreeVisitor<'n, 'p> {
443 NodeTreeVisitor {
440 NodeTreeVisitor {
444 nt: self,
441 nt: self,
445 prefix,
442 prefix,
@@ -617,9 +614,9 b' impl Deref for NodeTreeBytes {'
617 }
614 }
618 }
615 }
619
616
620 struct NodeTreeVisitor<'n, 'p> {
617 struct NodeTreeVisitor<'n> {
621 nt: &'n NodeTree,
618 nt: &'n NodeTree,
622 prefix: NodePrefixRef<'p>,
619 prefix: NodePrefix,
623 visit: usize,
620 visit: usize,
624 nybble_idx: usize,
621 nybble_idx: usize,
625 done: bool,
622 done: bool,
@@ -632,11 +629,11 b' struct NodeTreeVisitItem {'
632 element: Element,
629 element: Element,
633 }
630 }
634
631
635 impl<'n, 'p> Iterator for NodeTreeVisitor<'n, 'p> {
632 impl<'n> Iterator for NodeTreeVisitor<'n> {
636 type Item = NodeTreeVisitItem;
633 type Item = NodeTreeVisitItem;
637
634
638 fn next(&mut self) -> Option<Self::Item> {
635 fn next(&mut self) -> Option<Self::Item> {
639 if self.done || self.nybble_idx >= self.prefix.len() {
636 if self.done || self.nybble_idx >= self.prefix.nybbles_len() {
640 return None;
637 return None;
641 }
638 }
642
639
@@ -701,18 +698,18 b' impl NodeMap for NodeTree {'
701 fn find_bin<'a>(
698 fn find_bin<'a>(
702 &self,
699 &self,
703 idx: &impl RevlogIndex,
700 idx: &impl RevlogIndex,
704 prefix: NodePrefixRef<'a>,
701 prefix: NodePrefix,
705 ) -> Result<Option<Revision>, NodeMapError> {
702 ) -> Result<Option<Revision>, NodeMapError> {
706 validate_candidate(idx, prefix.clone(), self.lookup(prefix)?)
703 validate_candidate(idx, prefix, self.lookup(prefix)?)
707 .map(|(opt, _shortest)| opt)
704 .map(|(opt, _shortest)| opt)
708 }
705 }
709
706
710 fn unique_prefix_len_bin<'a>(
707 fn unique_prefix_len_bin<'a>(
711 &self,
708 &self,
712 idx: &impl RevlogIndex,
709 idx: &impl RevlogIndex,
713 prefix: NodePrefixRef<'a>,
710 prefix: NodePrefix,
714 ) -> Result<Option<usize>, NodeMapError> {
711 ) -> Result<Option<usize>, NodeMapError> {
715 validate_candidate(idx, prefix.clone(), self.lookup(prefix)?)
712 validate_candidate(idx, prefix, self.lookup(prefix)?)
716 .map(|(opt, shortest)| opt.map(|_rev| shortest))
713 .map(|(opt, shortest)| opt.map(|_rev| shortest))
717 }
714 }
718 }
715 }
@@ -11,7 +11,7 b' use micro_timer::timed;'
11 use zstd;
11 use zstd;
12
12
13 use super::index::Index;
13 use super::index::Index;
14 use super::node::{NodePrefixRef, NODE_BYTES_LENGTH, NULL_NODE};
14 use super::node::{NodePrefix, NODE_BYTES_LENGTH, NULL_NODE};
15 use super::nodemap;
15 use super::nodemap;
16 use super::nodemap::NodeMap;
16 use super::nodemap::NodeMap;
17 use super::nodemap_docket::NodeMapDocket;
17 use super::nodemap_docket::NodeMapDocket;
@@ -117,7 +117,7 b' impl Revlog {'
117 #[timed]
117 #[timed]
118 pub fn get_node_rev(
118 pub fn get_node_rev(
119 &self,
119 &self,
120 node: NodePrefixRef,
120 node: NodePrefix,
121 ) -> Result<Revision, RevlogError> {
121 ) -> Result<Revision, RevlogError> {
122 if let Some(nodemap) = &self.nodemap {
122 if let Some(nodemap) = &self.nodemap {
123 return nodemap
123 return nodemap
@@ -64,7 +64,7 b' py_class!(pub class MixedIndex |py| {'
64 let nt = opt.as_ref().unwrap();
64 let nt = opt.as_ref().unwrap();
65 let idx = &*self.cindex(py).borrow();
65 let idx = &*self.cindex(py).borrow();
66 let node = node_from_py_bytes(py, &node)?;
66 let node = node_from_py_bytes(py, &node)?;
67 nt.find_bin(idx, (&node).into()).map_err(|e| nodemap_error(py, e))
67 nt.find_bin(idx, node.into()).map_err(|e| nodemap_error(py, e))
68 }
68 }
69
69
70 /// same as `get_rev()` but raises a bare `error.RevlogError` if node
70 /// same as `get_rev()` but raises a bare `error.RevlogError` if node
General Comments 0
You need to be logged in to leave comments. Login now