rust-dirstatemap: add Rust implementation of `reset_state`
authorRaphaël Gomès <rgomes@octobus.net>
Wed, 23 Mar 2022 17:27:58 +0100
changeset 49101 dd0430434ce9
parent 49100 38e5bb1425dd
child 49102 358b1a1e3678
rust-dirstatemap: add Rust implementation of `reset_state` This is the new API which has already been defined in Python Differential Revision: https://phab.mercurial-scm.org/D12499
rust/hg-core/src/dirstate/entry.rs
rust/hg-core/src/dirstate_tree/dirstate_map.rs
rust/hg-cpython/src/dirstate/dirstate_map.rs
--- a/rust/hg-core/src/dirstate/entry.rs	Wed Mar 23 17:38:59 2022 +0100
+++ b/rust/hg-core/src/dirstate/entry.rs	Wed Mar 23 17:27:58 2022 +0100
@@ -259,6 +259,12 @@
     pub fallback_symlink: Option<bool>,
 }
 
+#[derive(Debug, Default, Copy, Clone)]
+pub struct ParentFileData {
+    pub mode_size: Option<(u32, u32)>,
+    pub mtime: Option<TruncatedTimestamp>,
+}
+
 impl DirstateEntry {
     pub fn from_v2_data(v2_data: DirstateV2Data) -> Self {
         let DirstateV2Data {
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs	Wed Mar 23 17:38:59 2022 +0100
+++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs	Wed Mar 23 17:27:58 2022 +0100
@@ -11,6 +11,8 @@
 use crate::dirstate::parsers::packed_entry_size;
 use crate::dirstate::parsers::parse_dirstate_entries;
 use crate::dirstate::CopyMapIter;
+use crate::dirstate::DirstateV2Data;
+use crate::dirstate::ParentFileData;
 use crate::dirstate::StateMapIter;
 use crate::dirstate::TruncatedTimestamp;
 use crate::dirstate::SIZE_FROM_OTHER_PARENT;
@@ -606,6 +608,73 @@
         }
     }
 
+    fn reset_state(
+        &mut self,
+        filename: &HgPath,
+        old_entry_opt: Option<DirstateEntry>,
+        wc_tracked: bool,
+        p1_tracked: bool,
+        p2_info: bool,
+        has_meaningful_mtime: bool,
+        parent_file_data_opt: Option<ParentFileData>,
+    ) -> Result<(), DirstateError> {
+        let (had_entry, was_tracked) = match old_entry_opt {
+            Some(old_entry) => (true, old_entry.tracked()),
+            None => (false, false),
+        };
+        let node = Self::get_or_insert_node(
+            self.on_disk,
+            &mut self.unreachable_bytes,
+            &mut self.root,
+            filename,
+            WithBasename::to_cow_owned,
+            |ancestor| {
+                if !had_entry {
+                    ancestor.descendants_with_entry_count += 1;
+                }
+                if was_tracked {
+                    if !wc_tracked {
+                        ancestor.tracked_descendants_count = ancestor
+                            .tracked_descendants_count
+                            .checked_sub(1)
+                            .expect("tracked count to be >= 0");
+                    }
+                } else {
+                    if wc_tracked {
+                        ancestor.tracked_descendants_count += 1;
+                    }
+                }
+            },
+        )?;
+
+        let v2_data = if let Some(parent_file_data) = parent_file_data_opt {
+            DirstateV2Data {
+                wc_tracked,
+                p1_tracked,
+                p2_info,
+                mode_size: parent_file_data.mode_size,
+                mtime: if has_meaningful_mtime {
+                    parent_file_data.mtime
+                } else {
+                    None
+                },
+                ..Default::default()
+            }
+        } else {
+            DirstateV2Data {
+                wc_tracked,
+                p1_tracked,
+                p2_info,
+                ..Default::default()
+            }
+        };
+        if !had_entry {
+            self.nodes_with_entry_count += 1;
+        }
+        node.data = NodeData::Entry(DirstateEntry::from_v2_data(v2_data));
+        Ok(())
+    }
+
     fn set_tracked(
         &mut self,
         filename: &HgPath,
@@ -812,6 +881,34 @@
         self.with_dmap_mut(|map| map.set_tracked(filename, old_entry_opt))
     }
 
+    pub fn reset_state(
+        &mut self,
+        filename: &HgPath,
+        wc_tracked: bool,
+        p1_tracked: bool,
+        p2_info: bool,
+        has_meaningful_mtime: bool,
+        parent_file_data_opt: Option<ParentFileData>,
+    ) -> Result<(), DirstateError> {
+        if !(p1_tracked || p2_info || wc_tracked) {
+            self.drop_entry_and_copy_source(filename)?;
+            return Ok(());
+        }
+        self.copy_map_remove(filename)?;
+        let old_entry_opt = self.get(filename)?;
+        self.with_dmap_mut(|map| {
+            map.reset_state(
+                filename,
+                old_entry_opt,
+                wc_tracked,
+                p1_tracked,
+                p2_info,
+                has_meaningful_mtime,
+                parent_file_data_opt,
+            )
+        })
+    }
+
     pub fn remove_file(
         &mut self,
         filename: &HgPath,
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs	Wed Mar 23 17:38:59 2022 +0100
+++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs	Wed Mar 23 17:27:58 2022 +0100
@@ -15,6 +15,7 @@
     exc, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList, PyNone, PyObject,
     PyResult, Python, PythonObject, ToPyObject, UnsafePyLeaked,
 };
+use hg::dirstate::{ParentFileData, TruncatedTimestamp};
 
 use crate::{
     dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
@@ -141,6 +142,55 @@
         Ok(was_tracked.to_py_object(py))
     }
 
+    def reset_state(
+        &self,
+        f: PyObject,
+        wc_tracked: bool,
+        p1_tracked: bool,
+        p2_info: bool,
+        has_meaningful_mtime: bool,
+        parentfiledata: Option<(u32, u32, Option<(i64, u32, bool)>)>,
+    ) -> PyResult<PyNone> {
+        let mut has_meaningful_mtime = has_meaningful_mtime;
+        let parent_file_data = match parentfiledata {
+            None => {
+                has_meaningful_mtime = false;
+                None
+            },
+            Some(data) => {
+                let (mode, size, mtime_info) = data;
+                let mtime = if let Some(mtime_info) = mtime_info {
+                    let (mtime_s, mtime_ns, second_ambiguous) = mtime_info;
+                    let timestamp = TruncatedTimestamp::new_truncate(
+                        mtime_s, mtime_ns, second_ambiguous
+                    );
+                    Some(timestamp)
+                } else {
+                    has_meaningful_mtime = false;
+                    None
+                };
+                Some(ParentFileData {
+                    mode_size: Some((mode, size)),
+                    mtime,
+                })
+            }
+        };
+        let bytes = f.extract::<PyBytes>(py)?;
+        let path = HgPath::new(bytes.data(py));
+        let res = self.inner(py).borrow_mut().reset_state(
+            path,
+            wc_tracked,
+            p1_tracked,
+            p2_info,
+            has_meaningful_mtime,
+            parent_file_data,
+        );
+        res.or_else(|_| {
+            Err(PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))
+        })?;
+        Ok(PyNone)
+    }
+
     def removefile(
         &self,
         f: PyObject,