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 |
|
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( |
|
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( |
|
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 |
|
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 |
|
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( |
|
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 |
|
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::NodePrefix |
|
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: NodePrefix |
|
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::NodePrefix |
|
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: NodePrefix |
|
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< |
|
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( |
|
196 | Ok(Self { data, nybbles_len }) | |
179 | } |
|
197 | } | |
180 |
|
198 | |||
181 |
pub fn |
|
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. |
|
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 |
|
|
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 |
|
267 | impl From<Node> for NodePrefix { | |
257 |
fn from(node: |
|
268 | fn from(node: Node) -> Self { | |
258 |
NodePrefix |
|
269 | NodePrefix { | |
259 | buf: &node.data, |
|
270 | nybbles_len: node.nybbles_len() as _, | |
260 |
|
|
271 | data: node.data, | |
261 | } |
|
272 | } | |
262 | } |
|
273 | } | |
263 | } |
|
274 | } | |
264 |
|
275 | |||
265 |
impl PartialEq<Node> for NodePrefix |
|
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( |
|
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(¬_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}", |
|
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 |
|
|
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( |
|
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")?. |
|
345 | assert!(NodePrefix::from_hex("12")?.is_prefix_of(&node)); | |
362 |
assert!(!NodePrefix::from_hex("1a")?. |
|
346 | assert!(!NodePrefix::from_hex("1a")?.is_prefix_of(&node)); | |
363 |
assert!(NodePrefix::from_hex("12c")?. |
|
347 | assert!(NodePrefix::from_hex("12c")?.is_prefix_of(&node)); | |
364 |
assert!(!NodePrefix::from_hex("12d")?. |
|
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 |
|
355 | assert_eq!(prefix.get_nybble(0), 13); | |
372 |
assert_eq!(prefix |
|
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!(pref |
|
364 | assert_eq!(prefix.first_different_nybble(&node), Some(0)); | |
382 | node.data[0] = 0x13; |
|
365 | node.data[0] = 0x13; | |
383 |
assert_eq!(pref |
|
366 | assert_eq!(prefix.first_different_nybble(&node), Some(1)); | |
384 | node.data[0] = 0x12; |
|
367 | node.data[0] = 0x12; | |
385 |
assert_eq!(pref |
|
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!(pref |
|
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!(pref |
|
378 | assert_eq!(prefix.first_different_nybble(&node), Some(0)); | |
397 | node.data[0] = 0x13; |
|
379 | node.data[0] = 0x13; | |
398 |
assert_eq!(pref |
|
380 | assert_eq!(prefix.first_different_nybble(&node), Some(1)); | |
399 | node.data[0] = 0x12; |
|
381 | node.data[0] = 0x12; | |
400 |
assert_eq!(pref |
|
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!(pref |
|
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, |
|
16 | node::NULL_NODE, FromHexError, Node, NodePrefix, Revision, RevlogIndex, | |
17 |
|
|
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: NodePrefix |
|
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)? |
|
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: NodePrefix |
|
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)? |
|
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: NodePrefix |
|
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: NodePrefix |
|
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: NodePrefix |
|
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 |
|
617 | struct NodeTreeVisitor<'n> { | |
621 | nt: &'n NodeTree, |
|
618 | nt: &'n NodeTree, | |
622 |
prefix: NodePrefix |
|
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 |
|
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: NodePrefix |
|
701 | prefix: NodePrefix, | |
705 | ) -> Result<Option<Revision>, NodeMapError> { |
|
702 | ) -> Result<Option<Revision>, NodeMapError> { | |
706 |
validate_candidate(idx, 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: NodePrefix |
|
710 | prefix: NodePrefix, | |
714 | ) -> Result<Option<usize>, NodeMapError> { |
|
711 | ) -> Result<Option<usize>, NodeMapError> { | |
715 |
validate_candidate(idx, 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::{NodePrefix |
|
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: NodePrefix |
|
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, |
|
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