Show More
@@ -48,14 +48,17 b" pub(super) type NodeKey<'on_disk> = With" | |||||
48 |
|
48 | |||
49 | pub(super) enum ChildNodes<'on_disk> { |
|
49 | pub(super) enum ChildNodes<'on_disk> { | |
50 | InMemory(FastHashMap<NodeKey<'on_disk>, Node<'on_disk>>), |
|
50 | InMemory(FastHashMap<NodeKey<'on_disk>, Node<'on_disk>>), | |
|
51 | OnDisk(&'on_disk [on_disk::Node]), | |||
51 | } |
|
52 | } | |
52 |
|
53 | |||
53 | pub(super) enum ChildNodesRef<'tree, 'on_disk> { |
|
54 | pub(super) enum ChildNodesRef<'tree, 'on_disk> { | |
54 | InMemory(&'tree FastHashMap<NodeKey<'on_disk>, Node<'on_disk>>), |
|
55 | InMemory(&'tree FastHashMap<NodeKey<'on_disk>, Node<'on_disk>>), | |
|
56 | OnDisk(&'on_disk [on_disk::Node]), | |||
55 | } |
|
57 | } | |
56 |
|
58 | |||
57 | pub(super) enum NodeRef<'tree, 'on_disk> { |
|
59 | pub(super) enum NodeRef<'tree, 'on_disk> { | |
58 | InMemory(&'tree NodeKey<'on_disk>, &'tree Node<'on_disk>), |
|
60 | InMemory(&'tree NodeKey<'on_disk>, &'tree Node<'on_disk>), | |
|
61 | OnDisk(&'on_disk on_disk::Node), | |||
59 | } |
|
62 | } | |
60 |
|
63 | |||
61 | impl Default for ChildNodes<'_> { |
|
64 | impl Default for ChildNodes<'_> { | |
@@ -70,24 +73,42 b" impl<'on_disk> ChildNodes<'on_disk> {" | |||||
70 | ) -> ChildNodesRef<'tree, 'on_disk> { |
|
73 | ) -> ChildNodesRef<'tree, 'on_disk> { | |
71 | match self { |
|
74 | match self { | |
72 | ChildNodes::InMemory(nodes) => ChildNodesRef::InMemory(nodes), |
|
75 | ChildNodes::InMemory(nodes) => ChildNodesRef::InMemory(nodes), | |
|
76 | ChildNodes::OnDisk(nodes) => ChildNodesRef::OnDisk(nodes), | |||
73 | } |
|
77 | } | |
74 | } |
|
78 | } | |
75 |
|
79 | |||
76 | pub(super) fn is_empty(&self) -> bool { |
|
80 | pub(super) fn is_empty(&self) -> bool { | |
77 | match self { |
|
81 | match self { | |
78 | ChildNodes::InMemory(nodes) => nodes.is_empty(), |
|
82 | ChildNodes::InMemory(nodes) => nodes.is_empty(), | |
|
83 | ChildNodes::OnDisk(nodes) => nodes.is_empty(), | |||
79 | } |
|
84 | } | |
80 | } |
|
85 | } | |
81 |
|
86 | |||
82 | pub(super) fn make_mut( |
|
87 | pub(super) fn make_mut( | |
83 | &mut self, |
|
88 | &mut self, | |
84 |
|
|
89 | on_disk: &'on_disk [u8], | |
85 | ) -> Result< |
|
90 | ) -> Result< | |
86 | &mut FastHashMap<NodeKey<'on_disk>, Node<'on_disk>>, |
|
91 | &mut FastHashMap<NodeKey<'on_disk>, Node<'on_disk>>, | |
87 | DirstateV2ParseError, |
|
92 | DirstateV2ParseError, | |
88 | > { |
|
93 | > { | |
89 | match self { |
|
94 | match self { | |
90 | ChildNodes::InMemory(nodes) => Ok(nodes), |
|
95 | ChildNodes::InMemory(nodes) => Ok(nodes), | |
|
96 | ChildNodes::OnDisk(nodes) => { | |||
|
97 | let nodes = nodes | |||
|
98 | .iter() | |||
|
99 | .map(|node| { | |||
|
100 | Ok(( | |||
|
101 | node.path(on_disk)?, | |||
|
102 | node.to_in_memory_node(on_disk)?, | |||
|
103 | )) | |||
|
104 | }) | |||
|
105 | .collect::<Result<_, _>>()?; | |||
|
106 | *self = ChildNodes::InMemory(nodes); | |||
|
107 | match self { | |||
|
108 | ChildNodes::InMemory(nodes) => Ok(nodes), | |||
|
109 | ChildNodes::OnDisk(_) => unreachable!(), | |||
|
110 | } | |||
|
111 | } | |||
91 | } |
|
112 | } | |
92 | } |
|
113 | } | |
93 | } |
|
114 | } | |
@@ -96,12 +117,29 b" impl<'tree, 'on_disk> ChildNodesRef<'tre" | |||||
96 | pub(super) fn get( |
|
117 | pub(super) fn get( | |
97 | &self, |
|
118 | &self, | |
98 | base_name: &HgPath, |
|
119 | base_name: &HgPath, | |
99 |
|
|
120 | on_disk: &'on_disk [u8], | |
100 | ) -> Result<Option<NodeRef<'tree, 'on_disk>>, DirstateV2ParseError> { |
|
121 | ) -> Result<Option<NodeRef<'tree, 'on_disk>>, DirstateV2ParseError> { | |
101 | match self { |
|
122 | match self { | |
102 | ChildNodesRef::InMemory(nodes) => Ok(nodes |
|
123 | ChildNodesRef::InMemory(nodes) => Ok(nodes | |
103 | .get_key_value(base_name) |
|
124 | .get_key_value(base_name) | |
104 | .map(|(k, v)| NodeRef::InMemory(k, v))), |
|
125 | .map(|(k, v)| NodeRef::InMemory(k, v))), | |
|
126 | ChildNodesRef::OnDisk(nodes) => { | |||
|
127 | let mut parse_result = Ok(()); | |||
|
128 | let search_result = nodes.binary_search_by(|node| { | |||
|
129 | match node.base_name(on_disk) { | |||
|
130 | Ok(node_base_name) => node_base_name.cmp(base_name), | |||
|
131 | Err(e) => { | |||
|
132 | parse_result = Err(e); | |||
|
133 | // Dummy comparison result, `search_result` won’t | |||
|
134 | // be used since `parse_result` is an error | |||
|
135 | std::cmp::Ordering::Equal | |||
|
136 | } | |||
|
137 | } | |||
|
138 | }); | |||
|
139 | parse_result.map(|()| { | |||
|
140 | search_result.ok().map(|i| NodeRef::OnDisk(&nodes[i])) | |||
|
141 | }) | |||
|
142 | } | |||
105 | } |
|
143 | } | |
106 | } |
|
144 | } | |
107 |
|
145 | |||
@@ -110,8 +148,11 b" impl<'tree, 'on_disk> ChildNodesRef<'tre" | |||||
110 | &self, |
|
148 | &self, | |
111 | ) -> impl Iterator<Item = NodeRef<'tree, 'on_disk>> { |
|
149 | ) -> impl Iterator<Item = NodeRef<'tree, 'on_disk>> { | |
112 | match self { |
|
150 | match self { | |
113 |
ChildNodesRef::InMemory(nodes) => |
|
151 | ChildNodesRef::InMemory(nodes) => itertools::Either::Left( | |
114 | nodes.iter().map(|(k, v)| NodeRef::InMemory(k, v)) |
|
152 | nodes.iter().map(|(k, v)| NodeRef::InMemory(k, v)), | |
|
153 | ), | |||
|
154 | ChildNodesRef::OnDisk(nodes) => { | |||
|
155 | itertools::Either::Right(nodes.iter().map(NodeRef::OnDisk)) | |||
115 | } |
|
156 | } | |
116 | } |
|
157 | } | |
117 | } |
|
158 | } | |
@@ -123,9 +164,12 b" impl<'tree, 'on_disk> ChildNodesRef<'tre" | |||||
123 | { |
|
164 | { | |
124 | use rayon::prelude::*; |
|
165 | use rayon::prelude::*; | |
125 | match self { |
|
166 | match self { | |
126 |
ChildNodesRef::InMemory(nodes) => |
|
167 | ChildNodesRef::InMemory(nodes) => rayon::iter::Either::Left( | |
127 | nodes.par_iter().map(|(k, v)| NodeRef::InMemory(k, v)) |
|
168 | nodes.par_iter().map(|(k, v)| NodeRef::InMemory(k, v)), | |
128 |
|
|
169 | ), | |
|
170 | ChildNodesRef::OnDisk(nodes) => rayon::iter::Either::Right( | |||
|
171 | nodes.par_iter().map(NodeRef::OnDisk), | |||
|
172 | ), | |||
129 | } |
|
173 | } | |
130 | } |
|
174 | } | |
131 |
|
175 | |||
@@ -139,6 +183,7 b" impl<'tree, 'on_disk> ChildNodesRef<'tre" | |||||
139 | fn sort_key<'a>(node: &'a NodeRef) -> &'a HgPath { |
|
183 | fn sort_key<'a>(node: &'a NodeRef) -> &'a HgPath { | |
140 | match node { |
|
184 | match node { | |
141 | NodeRef::InMemory(path, _node) => path.base_name(), |
|
185 | NodeRef::InMemory(path, _node) => path.base_name(), | |
|
186 | NodeRef::OnDisk(_) => unreachable!(), | |||
142 | } |
|
187 | } | |
143 | } |
|
188 | } | |
144 | // `sort_unstable_by_key` doesn’t allow keys borrowing from the |
|
189 | // `sort_unstable_by_key` doesn’t allow keys borrowing from the | |
@@ -146,6 +191,10 b" impl<'tree, 'on_disk> ChildNodesRef<'tre" | |||||
146 | vec.sort_unstable_by(|a, b| sort_key(a).cmp(sort_key(b))); |
|
191 | vec.sort_unstable_by(|a, b| sort_key(a).cmp(sort_key(b))); | |
147 | vec |
|
192 | vec | |
148 | } |
|
193 | } | |
|
194 | ChildNodesRef::OnDisk(nodes) => { | |||
|
195 | // Nodes on disk are already sorted | |||
|
196 | nodes.iter().map(NodeRef::OnDisk).collect() | |||
|
197 | } | |||
149 | } |
|
198 | } | |
150 | } |
|
199 | } | |
151 | } |
|
200 | } | |
@@ -153,61 +202,72 b" impl<'tree, 'on_disk> ChildNodesRef<'tre" | |||||
153 | impl<'tree, 'on_disk> NodeRef<'tree, 'on_disk> { |
|
202 | impl<'tree, 'on_disk> NodeRef<'tree, 'on_disk> { | |
154 | pub(super) fn full_path( |
|
203 | pub(super) fn full_path( | |
155 | &self, |
|
204 | &self, | |
156 |
|
|
205 | on_disk: &'on_disk [u8], | |
157 | ) -> Result<&'tree HgPath, DirstateV2ParseError> { |
|
206 | ) -> Result<&'tree HgPath, DirstateV2ParseError> { | |
158 | match self { |
|
207 | match self { | |
159 | NodeRef::InMemory(path, _node) => Ok(path.full_path()), |
|
208 | NodeRef::InMemory(path, _node) => Ok(path.full_path()), | |
|
209 | NodeRef::OnDisk(node) => node.full_path(on_disk), | |||
160 | } |
|
210 | } | |
161 | } |
|
211 | } | |
162 |
|
212 | |||
163 | /// Returns a `Cow` that can borrow 'on_disk but is detached from 'tree |
|
213 | /// Returns a `Cow` that can borrow 'on_disk but is detached from 'tree | |
164 | pub(super) fn full_path_cow( |
|
214 | pub(super) fn full_path_cow( | |
165 | &self, |
|
215 | &self, | |
166 |
|
|
216 | on_disk: &'on_disk [u8], | |
167 | ) -> Result<Cow<'on_disk, HgPath>, DirstateV2ParseError> { |
|
217 | ) -> Result<Cow<'on_disk, HgPath>, DirstateV2ParseError> { | |
168 | match self { |
|
218 | match self { | |
169 | NodeRef::InMemory(path, _node) => Ok(path.full_path().clone()), |
|
219 | NodeRef::InMemory(path, _node) => Ok(path.full_path().clone()), | |
|
220 | NodeRef::OnDisk(node) => { | |||
|
221 | Ok(Cow::Borrowed(node.full_path(on_disk)?)) | |||
|
222 | } | |||
170 | } |
|
223 | } | |
171 | } |
|
224 | } | |
172 |
|
225 | |||
173 | pub(super) fn base_name( |
|
226 | pub(super) fn base_name( | |
174 | &self, |
|
227 | &self, | |
175 |
|
|
228 | on_disk: &'on_disk [u8], | |
176 | ) -> Result<&'tree HgPath, DirstateV2ParseError> { |
|
229 | ) -> Result<&'tree HgPath, DirstateV2ParseError> { | |
177 | match self { |
|
230 | match self { | |
178 | NodeRef::InMemory(path, _node) => Ok(path.base_name()), |
|
231 | NodeRef::InMemory(path, _node) => Ok(path.base_name()), | |
|
232 | NodeRef::OnDisk(node) => node.base_name(on_disk), | |||
179 | } |
|
233 | } | |
180 | } |
|
234 | } | |
181 |
|
235 | |||
182 | pub(super) fn children( |
|
236 | pub(super) fn children( | |
183 | &self, |
|
237 | &self, | |
184 |
|
|
238 | on_disk: &'on_disk [u8], | |
185 | ) -> Result<ChildNodesRef<'tree, 'on_disk>, DirstateV2ParseError> { |
|
239 | ) -> Result<ChildNodesRef<'tree, 'on_disk>, DirstateV2ParseError> { | |
186 | match self { |
|
240 | match self { | |
187 | NodeRef::InMemory(_path, node) => Ok(node.children.as_ref()), |
|
241 | NodeRef::InMemory(_path, node) => Ok(node.children.as_ref()), | |
|
242 | NodeRef::OnDisk(node) => { | |||
|
243 | Ok(ChildNodesRef::OnDisk(node.children(on_disk)?)) | |||
|
244 | } | |||
188 | } |
|
245 | } | |
189 | } |
|
246 | } | |
190 |
|
247 | |||
191 | pub(super) fn has_copy_source(&self) -> bool { |
|
248 | pub(super) fn has_copy_source(&self) -> bool { | |
192 | match self { |
|
249 | match self { | |
193 | NodeRef::InMemory(_path, node) => node.copy_source.is_some(), |
|
250 | NodeRef::InMemory(_path, node) => node.copy_source.is_some(), | |
|
251 | NodeRef::OnDisk(node) => node.has_copy_source(), | |||
194 | } |
|
252 | } | |
195 | } |
|
253 | } | |
196 |
|
254 | |||
197 | pub(super) fn copy_source( |
|
255 | pub(super) fn copy_source( | |
198 | &self, |
|
256 | &self, | |
199 |
|
|
257 | on_disk: &'on_disk [u8], | |
200 | ) -> Result<Option<&'tree HgPath>, DirstateV2ParseError> { |
|
258 | ) -> Result<Option<&'tree HgPath>, DirstateV2ParseError> { | |
201 | match self { |
|
259 | match self { | |
202 | NodeRef::InMemory(_path, node) => { |
|
260 | NodeRef::InMemory(_path, node) => { | |
203 | Ok(node.copy_source.as_ref().map(|s| &**s)) |
|
261 | Ok(node.copy_source.as_ref().map(|s| &**s)) | |
204 | } |
|
262 | } | |
|
263 | NodeRef::OnDisk(node) => node.copy_source(on_disk), | |||
205 | } |
|
264 | } | |
206 | } |
|
265 | } | |
207 |
|
266 | |||
208 | pub(super) fn has_entry(&self) -> bool { |
|
267 | pub(super) fn has_entry(&self) -> bool { | |
209 | match self { |
|
268 | match self { | |
210 | NodeRef::InMemory(_path, node) => node.entry.is_some(), |
|
269 | NodeRef::InMemory(_path, node) => node.entry.is_some(), | |
|
270 | NodeRef::OnDisk(node) => node.has_entry(), | |||
211 | } |
|
271 | } | |
212 | } |
|
272 | } | |
213 |
|
273 | |||
@@ -216,6 +276,7 b" impl<'tree, 'on_disk> NodeRef<'tree, 'on" | |||||
216 | ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> { |
|
276 | ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> { | |
217 | match self { |
|
277 | match self { | |
218 | NodeRef::InMemory(_path, node) => Ok(node.entry), |
|
278 | NodeRef::InMemory(_path, node) => Ok(node.entry), | |
|
279 | NodeRef::OnDisk(node) => node.entry(), | |||
219 | } |
|
280 | } | |
220 | } |
|
281 | } | |
221 |
|
282 | |||
@@ -226,12 +287,14 b" impl<'tree, 'on_disk> NodeRef<'tree, 'on" | |||||
226 | NodeRef::InMemory(_path, node) => { |
|
287 | NodeRef::InMemory(_path, node) => { | |
227 | Ok(node.entry.as_ref().map(|entry| entry.state)) |
|
288 | Ok(node.entry.as_ref().map(|entry| entry.state)) | |
228 | } |
|
289 | } | |
|
290 | NodeRef::OnDisk(node) => node.state(), | |||
229 | } |
|
291 | } | |
230 | } |
|
292 | } | |
231 |
|
293 | |||
232 | pub(super) fn tracked_descendants_count(&self) -> u32 { |
|
294 | pub(super) fn tracked_descendants_count(&self) -> u32 { | |
233 | match self { |
|
295 | match self { | |
234 | NodeRef::InMemory(_path, node) => node.tracked_descendants_count, |
|
296 | NodeRef::InMemory(_path, node) => node.tracked_descendants_count, | |
|
297 | NodeRef::OnDisk(node) => node.tracked_descendants_count.get(), | |||
235 | } |
|
298 | } | |
236 | } |
|
299 | } | |
237 | } |
|
300 | } |
@@ -16,6 +16,7 b' use crate::utils::hg_path::HgPath;' | |||||
16 | use crate::DirstateEntry; |
|
16 | use crate::DirstateEntry; | |
17 | use crate::DirstateError; |
|
17 | use crate::DirstateError; | |
18 | use crate::DirstateParents; |
|
18 | use crate::DirstateParents; | |
|
19 | use crate::EntryState; | |||
19 | use bytes_cast::unaligned::{I32Be, U32Be, U64Be}; |
|
20 | use bytes_cast::unaligned::{I32Be, U32Be, U64Be}; | |
20 | use bytes_cast::BytesCast; |
|
21 | use bytes_cast::BytesCast; | |
21 | use std::borrow::Cow; |
|
22 | use std::borrow::Cow; | |
@@ -42,7 +43,7 b' struct Header {' | |||||
42 |
|
43 | |||
43 | #[derive(BytesCast)] |
|
44 | #[derive(BytesCast)] | |
44 | #[repr(C)] |
|
45 | #[repr(C)] | |
45 | struct Node { |
|
46 | pub(super) struct Node { | |
46 | full_path: PathSlice, |
|
47 | full_path: PathSlice, | |
47 |
|
48 | |||
48 | /// In bytes from `self.full_path.start` |
|
49 | /// In bytes from `self.full_path.start` | |
@@ -51,12 +52,12 b' struct Node {' | |||||
51 | copy_source: OptPathSlice, |
|
52 | copy_source: OptPathSlice, | |
52 | entry: OptEntry, |
|
53 | entry: OptEntry, | |
53 | children: ChildNodes, |
|
54 | children: ChildNodes, | |
54 | tracked_descendants_count: Size, |
|
55 | pub(super) tracked_descendants_count: Size, | |
55 | } |
|
56 | } | |
56 |
|
57 | |||
57 | /// Either nothing if `state == b'\0'`, or a dirstate entry like in the v1 |
|
58 | /// Either nothing if `state == b'\0'`, or a dirstate entry like in the v1 | |
58 | /// format |
|
59 | /// format | |
59 | #[derive(BytesCast)] |
|
60 | #[derive(BytesCast, Copy, Clone)] | |
60 | #[repr(C)] |
|
61 | #[repr(C)] | |
61 | struct OptEntry { |
|
62 | struct OptEntry { | |
62 | state: u8, |
|
63 | state: u8, | |
@@ -149,7 +150,9 b" pub(super) fn read<'on_disk>(" | |||||
149 | } |
|
150 | } | |
150 | let dirstate_map = DirstateMap { |
|
151 | let dirstate_map = DirstateMap { | |
151 | on_disk, |
|
152 | on_disk, | |
152 | root: read_nodes(on_disk, *root)?, |
|
153 | root: dirstate_map::ChildNodes::OnDisk(read_slice::<Node>( | |
|
154 | on_disk, *root, | |||
|
155 | )?), | |||
153 | nodes_with_entry_count: nodes_with_entry_count.get(), |
|
156 | nodes_with_entry_count: nodes_with_entry_count.get(), | |
154 | nodes_with_copy_source_count: nodes_with_copy_source_count.get(), |
|
157 | nodes_with_copy_source_count: nodes_with_copy_source_count.get(), | |
155 | }; |
|
158 | }; | |
@@ -158,49 +161,96 b" pub(super) fn read<'on_disk>(" | |||||
158 | } |
|
161 | } | |
159 |
|
162 | |||
160 | impl Node { |
|
163 | impl Node { | |
161 | pub(super) fn path<'on_disk>( |
|
164 | pub(super) fn full_path<'on_disk>( | |
162 | &self, |
|
165 | &self, | |
163 | on_disk: &'on_disk [u8], |
|
166 | on_disk: &'on_disk [u8], | |
164 |
) -> Result< |
|
167 | ) -> Result<&'on_disk HgPath, DirstateV2ParseError> { | |
165 |
|
|
168 | read_hg_path(on_disk, self.full_path) | |
166 | let base_name_start = usize::try_from(self.base_name_start.get()) |
|
169 | } | |
167 | // u32 -> usize, could only panic on a 16-bit CPU |
|
170 | ||
168 | .expect("dirstate-v2 base_name_start out of bounds"); |
|
171 | pub(super) fn base_name_start<'on_disk>( | |
169 | if base_name_start < full_path.len() { |
|
172 | &self, | |
170 | Ok(WithBasename::from_raw_parts(full_path, base_name_start)) |
|
173 | ) -> Result<usize, DirstateV2ParseError> { | |
|
174 | let start = self.base_name_start.get(); | |||
|
175 | if start < self.full_path.len.get() { | |||
|
176 | let start = usize::try_from(start) | |||
|
177 | // u32 -> usize, could only panic on a 16-bit CPU | |||
|
178 | .expect("dirstate-v2 base_name_start out of bounds"); | |||
|
179 | Ok(start) | |||
171 | } else { |
|
180 | } else { | |
172 | Err(DirstateV2ParseError) |
|
181 | Err(DirstateV2ParseError) | |
173 | } |
|
182 | } | |
174 | } |
|
183 | } | |
175 |
|
184 | |||
|
185 | pub(super) fn base_name<'on_disk>( | |||
|
186 | &self, | |||
|
187 | on_disk: &'on_disk [u8], | |||
|
188 | ) -> Result<&'on_disk HgPath, DirstateV2ParseError> { | |||
|
189 | let full_path = self.full_path(on_disk)?; | |||
|
190 | let base_name_start = self.base_name_start()?; | |||
|
191 | Ok(HgPath::new(&full_path.as_bytes()[base_name_start..])) | |||
|
192 | } | |||
|
193 | ||||
|
194 | pub(super) fn path<'on_disk>( | |||
|
195 | &self, | |||
|
196 | on_disk: &'on_disk [u8], | |||
|
197 | ) -> Result<dirstate_map::NodeKey<'on_disk>, DirstateV2ParseError> { | |||
|
198 | Ok(WithBasename::from_raw_parts( | |||
|
199 | Cow::Borrowed(self.full_path(on_disk)?), | |||
|
200 | self.base_name_start()?, | |||
|
201 | )) | |||
|
202 | } | |||
|
203 | ||||
|
204 | pub(super) fn has_copy_source<'on_disk>(&self) -> bool { | |||
|
205 | self.copy_source.start.get() != 0 | |||
|
206 | } | |||
|
207 | ||||
176 | pub(super) fn copy_source<'on_disk>( |
|
208 | pub(super) fn copy_source<'on_disk>( | |
177 | &self, |
|
209 | &self, | |
178 | on_disk: &'on_disk [u8], |
|
210 | on_disk: &'on_disk [u8], | |
179 |
) -> Result<Option< |
|
211 | ) -> Result<Option<&'on_disk HgPath>, DirstateV2ParseError> { | |
180 |
Ok(if self.copy_source |
|
212 | Ok(if self.has_copy_source() { | |
181 | Some(read_hg_path(on_disk, self.copy_source)?) |
|
213 | Some(read_hg_path(on_disk, self.copy_source)?) | |
182 | } else { |
|
214 | } else { | |
183 | None |
|
215 | None | |
184 | }) |
|
216 | }) | |
185 | } |
|
217 | } | |
186 |
|
218 | |||
|
219 | pub(super) fn has_entry(&self) -> bool { | |||
|
220 | self.entry.state != b'\0' | |||
|
221 | } | |||
|
222 | ||||
|
223 | pub(super) fn state( | |||
|
224 | &self, | |||
|
225 | ) -> Result<Option<EntryState>, DirstateV2ParseError> { | |||
|
226 | Ok(if self.has_entry() { | |||
|
227 | Some( | |||
|
228 | self.entry | |||
|
229 | .state | |||
|
230 | .try_into() | |||
|
231 | .map_err(|_| DirstateV2ParseError)?, | |||
|
232 | ) | |||
|
233 | } else { | |||
|
234 | None | |||
|
235 | }) | |||
|
236 | } | |||
|
237 | ||||
187 | pub(super) fn entry( |
|
238 | pub(super) fn entry( | |
188 | &self, |
|
239 | &self, | |
189 | ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> { |
|
240 | ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> { | |
190 | Ok(if self.entry.state != b'\0' { |
|
241 | Ok(self.state()?.map(|state| DirstateEntry { | |
191 |
|
|
242 | state, | |
192 | state: self |
|
243 | mode: self.entry.mode.get(), | |
193 | .entry |
|
244 | mtime: self.entry.mtime.get(), | |
194 | .state |
|
245 | size: self.entry.size.get(), | |
195 | .try_into() |
|
246 | })) | |
196 | .map_err(|_| DirstateV2ParseError)?, |
|
247 | } | |
197 | mode: self.entry.mode.get(), |
|
248 | ||
198 | mtime: self.entry.mtime.get(), |
|
249 | pub(super) fn children<'on_disk>( | |
199 | size: self.entry.size.get(), |
|
250 | &self, | |
200 | }) |
|
251 | on_disk: &'on_disk [u8], | |
201 | } else { |
|
252 | ) -> Result<&'on_disk [Node], DirstateV2ParseError> { | |
202 | None |
|
253 | read_slice::<Node>(on_disk, self.children) | |
203 | }) |
|
|||
204 | } |
|
254 | } | |
205 |
|
255 | |||
206 | pub(super) fn to_in_memory_node<'on_disk>( |
|
256 | pub(super) fn to_in_memory_node<'on_disk>( | |
@@ -208,33 +258,22 b' impl Node {' | |||||
208 | on_disk: &'on_disk [u8], |
|
258 | on_disk: &'on_disk [u8], | |
209 | ) -> Result<dirstate_map::Node<'on_disk>, DirstateV2ParseError> { |
|
259 | ) -> Result<dirstate_map::Node<'on_disk>, DirstateV2ParseError> { | |
210 | Ok(dirstate_map::Node { |
|
260 | Ok(dirstate_map::Node { | |
211 |
children: |
|
261 | children: dirstate_map::ChildNodes::OnDisk( | |
212 |
|
|
262 | self.children(on_disk)?, | |
|
263 | ), | |||
|
264 | copy_source: self.copy_source(on_disk)?.map(Cow::Borrowed), | |||
213 | entry: self.entry()?, |
|
265 | entry: self.entry()?, | |
214 | tracked_descendants_count: self.tracked_descendants_count.get(), |
|
266 | tracked_descendants_count: self.tracked_descendants_count.get(), | |
215 | }) |
|
267 | }) | |
216 | } |
|
268 | } | |
217 | } |
|
269 | } | |
218 |
|
270 | |||
219 | fn read_nodes( |
|
|||
220 | on_disk: &[u8], |
|
|||
221 | slice: ChildNodes, |
|
|||
222 | ) -> Result<dirstate_map::ChildNodes, DirstateV2ParseError> { |
|
|||
223 | read_slice::<Node>(on_disk, slice)? |
|
|||
224 | .iter() |
|
|||
225 | .map(|node| { |
|
|||
226 | Ok((node.path(on_disk)?, node.to_in_memory_node(on_disk)?)) |
|
|||
227 | }) |
|
|||
228 | .collect::<Result<_, _>>() |
|
|||
229 | .map(dirstate_map::ChildNodes::InMemory) |
|
|||
230 | } |
|
|||
231 |
|
||||
232 | fn read_hg_path( |
|
271 | fn read_hg_path( | |
233 | on_disk: &[u8], |
|
272 | on_disk: &[u8], | |
234 | slice: Slice, |
|
273 | slice: Slice, | |
235 |
) -> Result< |
|
274 | ) -> Result<&HgPath, DirstateV2ParseError> { | |
236 | let bytes = read_slice::<u8>(on_disk, slice)?; |
|
275 | let bytes = read_slice::<u8>(on_disk, slice)?; | |
237 |
Ok |
|
276 | Ok(HgPath::new(bytes)) | |
238 | } |
|
277 | } | |
239 |
|
278 | |||
240 | fn read_slice<T>( |
|
279 | fn read_slice<T>( | |
@@ -300,8 +339,11 b' fn write_nodes(' | |||||
300 | // First accumulate serialized nodes in a `Vec` |
|
339 | // First accumulate serialized nodes in a `Vec` | |
301 | let mut on_disk_nodes = Vec::with_capacity(nodes.len()); |
|
340 | let mut on_disk_nodes = Vec::with_capacity(nodes.len()); | |
302 | for node in nodes { |
|
341 | for node in nodes { | |
303 | let children = node.children(dirstate_map.on_disk)?; |
|
342 | let children = write_nodes( | |
304 | let children = write_nodes(dirstate_map, children, out)?; |
|
343 | dirstate_map, | |
|
344 | node.children(dirstate_map.on_disk)?, | |||
|
345 | out, | |||
|
346 | )?; | |||
305 | let full_path = node.full_path(dirstate_map.on_disk)?; |
|
347 | let full_path = node.full_path(dirstate_map.on_disk)?; | |
306 | let full_path = write_slice::<u8>(full_path.as_bytes(), out); |
|
348 | let full_path = write_slice::<u8>(full_path.as_bytes(), out); | |
307 | let copy_source = |
|
349 | let copy_source = | |
@@ -341,6 +383,12 b' fn write_nodes(' | |||||
341 | } |
|
383 | } | |
342 | }, |
|
384 | }, | |
343 | }, |
|
385 | }, | |
|
386 | NodeRef::OnDisk(node) => Node { | |||
|
387 | children, | |||
|
388 | copy_source, | |||
|
389 | full_path, | |||
|
390 | ..*node | |||
|
391 | }, | |||
344 | }) |
|
392 | }) | |
345 | } |
|
393 | } | |
346 | // … so we can write them contiguously |
|
394 | // … so we can write them contiguously |
General Comments 0
You need to be logged in to leave comments.
Login now