rust/hg-core/src/dirstate_tree/on_disk.rs
changeset 47337 0654b3b3d2b5
parent 47336 8d0260d0dbc9
child 47348 a4de570e61fa
--- a/rust/hg-core/src/dirstate_tree/on_disk.rs	Wed May 19 13:15:00 2021 +0200
+++ b/rust/hg-core/src/dirstate_tree/on_disk.rs	Wed May 19 13:15:00 2021 +0200
@@ -16,6 +16,7 @@
 use crate::DirstateEntry;
 use crate::DirstateError;
 use crate::DirstateParents;
+use crate::EntryState;
 use bytes_cast::unaligned::{I32Be, U32Be, U64Be};
 use bytes_cast::BytesCast;
 use std::borrow::Cow;
@@ -42,7 +43,7 @@
 
 #[derive(BytesCast)]
 #[repr(C)]
-struct Node {
+pub(super) struct Node {
     full_path: PathSlice,
 
     /// In bytes from `self.full_path.start`
@@ -51,12 +52,12 @@
     copy_source: OptPathSlice,
     entry: OptEntry,
     children: ChildNodes,
-    tracked_descendants_count: Size,
+    pub(super) tracked_descendants_count: Size,
 }
 
 /// Either nothing if `state == b'\0'`, or a dirstate entry like in the v1
 /// format
-#[derive(BytesCast)]
+#[derive(BytesCast, Copy, Clone)]
 #[repr(C)]
 struct OptEntry {
     state: u8,
@@ -149,7 +150,9 @@
     }
     let dirstate_map = DirstateMap {
         on_disk,
-        root: read_nodes(on_disk, *root)?,
+        root: dirstate_map::ChildNodes::OnDisk(read_slice::<Node>(
+            on_disk, *root,
+        )?),
         nodes_with_entry_count: nodes_with_entry_count.get(),
         nodes_with_copy_source_count: nodes_with_copy_source_count.get(),
     };
@@ -158,49 +161,96 @@
 }
 
 impl Node {
-    pub(super) fn path<'on_disk>(
+    pub(super) fn full_path<'on_disk>(
         &self,
         on_disk: &'on_disk [u8],
-    ) -> Result<dirstate_map::NodeKey<'on_disk>, DirstateV2ParseError> {
-        let full_path = read_hg_path(on_disk, self.full_path)?;
-        let base_name_start = usize::try_from(self.base_name_start.get())
-            // u32 -> usize, could only panic on a 16-bit CPU
-            .expect("dirstate-v2 base_name_start out of bounds");
-        if base_name_start < full_path.len() {
-            Ok(WithBasename::from_raw_parts(full_path, base_name_start))
+    ) -> Result<&'on_disk HgPath, DirstateV2ParseError> {
+        read_hg_path(on_disk, self.full_path)
+    }
+
+    pub(super) fn base_name_start<'on_disk>(
+        &self,
+    ) -> Result<usize, DirstateV2ParseError> {
+        let start = self.base_name_start.get();
+        if start < self.full_path.len.get() {
+            let start = usize::try_from(start)
+                // u32 -> usize, could only panic on a 16-bit CPU
+                .expect("dirstate-v2 base_name_start out of bounds");
+            Ok(start)
         } else {
             Err(DirstateV2ParseError)
         }
     }
 
+    pub(super) fn base_name<'on_disk>(
+        &self,
+        on_disk: &'on_disk [u8],
+    ) -> Result<&'on_disk HgPath, DirstateV2ParseError> {
+        let full_path = self.full_path(on_disk)?;
+        let base_name_start = self.base_name_start()?;
+        Ok(HgPath::new(&full_path.as_bytes()[base_name_start..]))
+    }
+
+    pub(super) fn path<'on_disk>(
+        &self,
+        on_disk: &'on_disk [u8],
+    ) -> Result<dirstate_map::NodeKey<'on_disk>, DirstateV2ParseError> {
+        Ok(WithBasename::from_raw_parts(
+            Cow::Borrowed(self.full_path(on_disk)?),
+            self.base_name_start()?,
+        ))
+    }
+
+    pub(super) fn has_copy_source<'on_disk>(&self) -> bool {
+        self.copy_source.start.get() != 0
+    }
+
     pub(super) fn copy_source<'on_disk>(
         &self,
         on_disk: &'on_disk [u8],
-    ) -> Result<Option<Cow<'on_disk, HgPath>>, DirstateV2ParseError> {
-        Ok(if self.copy_source.start.get() != 0 {
+    ) -> Result<Option<&'on_disk HgPath>, DirstateV2ParseError> {
+        Ok(if self.has_copy_source() {
             Some(read_hg_path(on_disk, self.copy_source)?)
         } else {
             None
         })
     }
 
+    pub(super) fn has_entry(&self) -> bool {
+        self.entry.state != b'\0'
+    }
+
+    pub(super) fn state(
+        &self,
+    ) -> Result<Option<EntryState>, DirstateV2ParseError> {
+        Ok(if self.has_entry() {
+            Some(
+                self.entry
+                    .state
+                    .try_into()
+                    .map_err(|_| DirstateV2ParseError)?,
+            )
+        } else {
+            None
+        })
+    }
+
     pub(super) fn entry(
         &self,
     ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> {
-        Ok(if self.entry.state != b'\0' {
-            Some(DirstateEntry {
-                state: self
-                    .entry
-                    .state
-                    .try_into()
-                    .map_err(|_| DirstateV2ParseError)?,
-                mode: self.entry.mode.get(),
-                mtime: self.entry.mtime.get(),
-                size: self.entry.size.get(),
-            })
-        } else {
-            None
-        })
+        Ok(self.state()?.map(|state| DirstateEntry {
+            state,
+            mode: self.entry.mode.get(),
+            mtime: self.entry.mtime.get(),
+            size: self.entry.size.get(),
+        }))
+    }
+
+    pub(super) fn children<'on_disk>(
+        &self,
+        on_disk: &'on_disk [u8],
+    ) -> Result<&'on_disk [Node], DirstateV2ParseError> {
+        read_slice::<Node>(on_disk, self.children)
     }
 
     pub(super) fn to_in_memory_node<'on_disk>(
@@ -208,33 +258,22 @@
         on_disk: &'on_disk [u8],
     ) -> Result<dirstate_map::Node<'on_disk>, DirstateV2ParseError> {
         Ok(dirstate_map::Node {
-            children: read_nodes(on_disk, self.children)?,
-            copy_source: self.copy_source(on_disk)?,
+            children: dirstate_map::ChildNodes::OnDisk(
+                self.children(on_disk)?,
+            ),
+            copy_source: self.copy_source(on_disk)?.map(Cow::Borrowed),
             entry: self.entry()?,
             tracked_descendants_count: self.tracked_descendants_count.get(),
         })
     }
 }
 
-fn read_nodes(
-    on_disk: &[u8],
-    slice: ChildNodes,
-) -> Result<dirstate_map::ChildNodes, DirstateV2ParseError> {
-    read_slice::<Node>(on_disk, slice)?
-        .iter()
-        .map(|node| {
-            Ok((node.path(on_disk)?, node.to_in_memory_node(on_disk)?))
-        })
-        .collect::<Result<_, _>>()
-        .map(dirstate_map::ChildNodes::InMemory)
-}
-
 fn read_hg_path(
     on_disk: &[u8],
     slice: Slice,
-) -> Result<Cow<HgPath>, DirstateV2ParseError> {
+) -> Result<&HgPath, DirstateV2ParseError> {
     let bytes = read_slice::<u8>(on_disk, slice)?;
-    Ok(Cow::Borrowed(HgPath::new(bytes)))
+    Ok(HgPath::new(bytes))
 }
 
 fn read_slice<T>(
@@ -300,8 +339,11 @@
     // First accumulate serialized nodes in a `Vec`
     let mut on_disk_nodes = Vec::with_capacity(nodes.len());
     for node in nodes {
-        let children = node.children(dirstate_map.on_disk)?;
-        let children = write_nodes(dirstate_map, children, out)?;
+        let children = write_nodes(
+            dirstate_map,
+            node.children(dirstate_map.on_disk)?,
+            out,
+        )?;
         let full_path = node.full_path(dirstate_map.on_disk)?;
         let full_path = write_slice::<u8>(full_path.as_bytes(), out);
         let copy_source =
@@ -341,6 +383,12 @@
                     }
                 },
             },
+            NodeRef::OnDisk(node) => Node {
+                children,
+                copy_source,
+                full_path,
+                ..*node
+            },
         })
     }
     // … so we can write them contiguously