Mercurial > hg
comparison rust/hg-core/src/dirstate_tree/on_disk.rs @ 47333:69530e5d4fe5
dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
They are used instead of `&Node` and `&ChildNodes` respectively.
The `ChildNodes` type alias also becomes a similar enum.
For now they only have one variant each, to be extended later.
Adding enums now forces various use sites go through new methods
instead of manipulating the underlying data structure directly.
Differential Revision: https://phab.mercurial-scm.org/D10747
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Wed, 19 May 2021 13:15:00 +0200 |
parents | 0252600fd1cf |
children | 18b3060fe598 |
comparison
equal
deleted
inserted
replaced
47332:4ee9f419c52e | 47333:69530e5d4fe5 |
---|---|
7 //! the nodes representing the files and directories at the root of the | 7 //! the nodes representing the files and directories at the root of the |
8 //! repository. Each node is also fixed-size, defined by the `Node` struct. | 8 //! repository. Each node is also fixed-size, defined by the `Node` struct. |
9 //! Nodes in turn contain slices to variable-size paths, and to their own child | 9 //! Nodes in turn contain slices to variable-size paths, and to their own child |
10 //! nodes (if any) for nested files and directories. | 10 //! nodes (if any) for nested files and directories. |
11 | 11 |
12 use crate::dirstate_tree::dirstate_map::{self, DirstateMap}; | 12 use crate::dirstate_tree::dirstate_map::{self, DirstateMap, NodeRef}; |
13 use crate::dirstate_tree::path_with_basename::WithBasename; | 13 use crate::dirstate_tree::path_with_basename::WithBasename; |
14 use crate::errors::HgError; | 14 use crate::errors::HgError; |
15 use crate::utils::hg_path::HgPath; | 15 use crate::utils::hg_path::HgPath; |
16 use crate::DirstateEntry; | 16 use crate::DirstateEntry; |
17 use crate::DirstateError; | 17 use crate::DirstateError; |
198 read_slice::<Node>(on_disk, slice)? | 198 read_slice::<Node>(on_disk, slice)? |
199 .iter() | 199 .iter() |
200 .map(|node| { | 200 .map(|node| { |
201 Ok((node.path(on_disk)?, node.to_in_memory_node(on_disk)?)) | 201 Ok((node.path(on_disk)?, node.to_in_memory_node(on_disk)?)) |
202 }) | 202 }) |
203 .collect() | 203 .collect::<Result<_, _>>() |
204 .map(dirstate_map::ChildNodes::InMemory) | |
204 } | 205 } |
205 | 206 |
206 fn read_hg_path(on_disk: &[u8], slice: Slice) -> Result<Cow<HgPath>, HgError> { | 207 fn read_hg_path(on_disk: &[u8], slice: Slice) -> Result<Cow<HgPath>, HgError> { |
207 let bytes = read_slice::<u8>(on_disk, slice)?; | 208 let bytes = read_slice::<u8>(on_disk, slice)?; |
208 Ok(Cow::Borrowed(HgPath::new(bytes))) | 209 Ok(Cow::Borrowed(HgPath::new(bytes))) |
240 | 241 |
241 // Keep space for the header. We’ll fill it out at the end when we know the | 242 // Keep space for the header. We’ll fill it out at the end when we know the |
242 // actual offset for the root nodes. | 243 // actual offset for the root nodes. |
243 out.resize(header_len, 0_u8); | 244 out.resize(header_len, 0_u8); |
244 | 245 |
245 let root = write_nodes(&mut dirstate_map.root, &mut out)?; | 246 let root = write_nodes(dirstate_map.root.as_ref(), &mut out)?; |
246 | 247 |
247 let header = Header { | 248 let header = Header { |
248 marker: *V2_FORMAT_MARKER, | 249 marker: *V2_FORMAT_MARKER, |
249 parents: parents, | 250 parents: parents, |
250 root, | 251 root, |
256 out[..header_len].copy_from_slice(header.as_bytes()); | 257 out[..header_len].copy_from_slice(header.as_bytes()); |
257 Ok(out) | 258 Ok(out) |
258 } | 259 } |
259 | 260 |
260 fn write_nodes( | 261 fn write_nodes( |
261 nodes: &dirstate_map::ChildNodes, | 262 nodes: dirstate_map::ChildNodesRef, |
262 out: &mut Vec<u8>, | 263 out: &mut Vec<u8>, |
263 ) -> Result<ChildNodes, DirstateError> { | 264 ) -> Result<ChildNodes, DirstateError> { |
264 // `dirstate_map::ChildNodes` is a `HashMap` with undefined iteration | 265 // `dirstate_map::ChildNodes` is a `HashMap` with undefined iteration |
265 // order. Sort to enable binary search in the written file. | 266 // order. Sort to enable binary search in the written file. |
266 let nodes = dirstate_map::Node::sorted(nodes); | 267 let nodes = nodes.sorted(); |
267 | 268 |
268 // First accumulate serialized nodes in a `Vec` | 269 // First accumulate serialized nodes in a `Vec` |
269 let mut on_disk_nodes = Vec::with_capacity(nodes.len()); | 270 let mut on_disk_nodes = Vec::with_capacity(nodes.len()); |
270 for (full_path, node) in nodes { | 271 for node in nodes { |
271 on_disk_nodes.push(Node { | 272 let children = write_nodes(node.children(), out)?; |
272 children: write_nodes(&node.children, out)?, | 273 let full_path = write_slice::<u8>(node.full_path().as_bytes(), out); |
273 tracked_descendants_count: node.tracked_descendants_count.into(), | 274 let copy_source = if let Some(source) = node.copy_source() { |
274 full_path: write_slice::<u8>( | 275 write_slice::<u8>(source.as_bytes(), out) |
275 full_path.full_path().as_bytes(), | 276 } else { |
276 out, | 277 Slice { |
277 ), | 278 start: 0.into(), |
278 base_name_start: u32::try_from(full_path.base_name_start()) | 279 len: 0.into(), |
279 // Could only panic for paths over 4 GiB | 280 } |
280 .expect("dirstate-v2 offset overflow") | 281 }; |
281 .into(), | 282 on_disk_nodes.push(match node { |
282 copy_source: if let Some(source) = &node.copy_source { | 283 NodeRef::InMemory(path, node) => Node { |
283 write_slice::<u8>(source.as_bytes(), out) | 284 children, |
284 } else { | 285 copy_source, |
285 Slice { | 286 full_path, |
286 start: 0.into(), | 287 base_name_start: u32::try_from(path.base_name_start()) |
287 len: 0.into(), | 288 // Could only panic for paths over 4 GiB |
288 } | 289 .expect("dirstate-v2 offset overflow") |
289 }, | 290 .into(), |
290 entry: if let Some(entry) = &node.entry { | 291 tracked_descendants_count: node |
291 OptEntry { | 292 .tracked_descendants_count |
292 state: entry.state.into(), | 293 .into(), |
293 mode: entry.mode.into(), | 294 entry: if let Some(entry) = &node.entry { |
294 mtime: entry.mtime.into(), | 295 OptEntry { |
295 size: entry.size.into(), | 296 state: entry.state.into(), |
296 } | 297 mode: entry.mode.into(), |
297 } else { | 298 mtime: entry.mtime.into(), |
298 OptEntry { | 299 size: entry.size.into(), |
299 state: b'\0', | 300 } |
300 mode: 0.into(), | 301 } else { |
301 mtime: 0.into(), | 302 OptEntry { |
302 size: 0.into(), | 303 state: b'\0', |
303 } | 304 mode: 0.into(), |
305 mtime: 0.into(), | |
306 size: 0.into(), | |
307 } | |
308 }, | |
304 }, | 309 }, |
305 }) | 310 }) |
306 } | 311 } |
307 // … so we can write them contiguously | 312 // … so we can write them contiguously |
308 Ok(write_slice::<Node>(&on_disk_nodes, out)) | 313 Ok(write_slice::<Node>(&on_disk_nodes, out)) |