rust/hg-core/src/dirstate_tree/dirstate_map.rs
changeset 47280 1766130fe9ba
parent 47193 47ccab19bf9f
child 47282 ce41ee53263f
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs	Wed May 19 13:15:00 2021 +0200
+++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs	Wed May 19 13:15:00 2021 +0200
@@ -4,14 +4,17 @@
 use std::convert::TryInto;
 use std::path::PathBuf;
 
+use super::on_disk::V2_FORMAT_MARKER;
 use super::path_with_basename::WithBasename;
 use crate::dirstate::parsers::clear_ambiguous_mtime;
 use crate::dirstate::parsers::pack_entry;
 use crate::dirstate::parsers::packed_entry_size;
 use crate::dirstate::parsers::parse_dirstate_entries;
 use crate::dirstate::parsers::Timestamp;
+use crate::errors::HgError;
 use crate::matchers::Matcher;
 use crate::utils::hg_path::{HgPath, HgPathBuf};
+use crate::utils::SliceExt;
 use crate::CopyMapIter;
 use crate::DirstateEntry;
 use crate::DirstateError;
@@ -75,7 +78,24 @@
 );
 
 impl<'on_disk> DirstateMap<'on_disk> {
-    pub fn new(
+    #[timed]
+    pub fn new_v2(
+        on_disk: &'on_disk [u8],
+    ) -> Result<(Self, Option<DirstateParents>), DirstateError> {
+        if let Some(rest) = on_disk.drop_prefix(V2_FORMAT_MARKER) {
+            Self::new_v1(rest)
+        } else if on_disk.is_empty() {
+            Self::new_v1(on_disk)
+        } else {
+            return Err(HgError::corrupted(
+                "missing dirstate-v2 magic number",
+            )
+            .into());
+        }
+    }
+
+    #[timed]
+    pub fn new_v1(
         on_disk: &'on_disk [u8],
     ) -> Result<(Self, Option<DirstateParents>), DirstateError> {
         let mut map = Self {
@@ -84,23 +104,16 @@
             nodes_with_entry_count: 0,
             nodes_with_copy_source_count: 0,
         };
-        let parents = map.read()?;
-        Ok((map, parents))
-    }
-
-    /// Should only be called in `new`
-    #[timed]
-    fn read(&mut self) -> Result<Option<DirstateParents>, DirstateError> {
-        if self.on_disk.is_empty() {
-            return Ok(None);
+        if map.on_disk.is_empty() {
+            return Ok((map, None));
         }
 
         let parents = parse_dirstate_entries(
-            self.on_disk,
+            map.on_disk,
             |path, entry, copy_source| {
                 let tracked = entry.state.is_tracked();
                 let node = Self::get_or_insert_node(
-                    &mut self.root,
+                    &mut map.root,
                     path,
                     WithBasename::to_cow_borrowed,
                     |ancestor| {
@@ -119,14 +132,15 @@
                 );
                 node.entry = Some(*entry);
                 node.copy_source = copy_source.map(Cow::Borrowed);
-                self.nodes_with_entry_count += 1;
+                map.nodes_with_entry_count += 1;
                 if copy_source.is_some() {
-                    self.nodes_with_copy_source_count += 1
+                    map.nodes_with_copy_source_count += 1
                 }
             },
         )?;
+        let parents = Some(parents.clone());
 
-        Ok(Some(parents.clone()))
+        Ok((map, parents))
     }
 
     fn get_node(&self, path: &HgPath) -> Option<&Node> {
@@ -498,7 +512,8 @@
         }
     }
 
-    fn pack(
+    #[timed]
+    fn pack_v1(
         &mut self,
         parents: DirstateParents,
         now: Timestamp,
@@ -533,6 +548,18 @@
         Ok(packed)
     }
 
+    #[timed]
+    fn pack_v2(
+        &mut self,
+        parents: DirstateParents,
+        now: Timestamp,
+    ) -> Result<Vec<u8>, DirstateError> {
+        // Inefficient but temporary
+        let mut v2 = V2_FORMAT_MARKER.to_vec();
+        v2.append(&mut self.pack_v1(parents, now)?);
+        Ok(v2)
+    }
+
     fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
         // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
         // needs to be recomputed