# HG changeset patch
# User Simon Sapin <simon.sapin@octobus.net>
# Date 2021-05-19 11:15:00
# Node ID 4ee9f419c52ee780cda10854736a6c5068e4837f
# Parent  0252600fd1cf2299aeb43bcf4b407265945c6814

rust: Return owned instead of borrowed DirstateEntry in DirstateMap APIs

This will enable the tree-based DirstateMap to not always have an actual
DirstateEntry in memory for all nodes, but construct it on demand.

Differential Revision: https://phab.mercurial-scm.org/D10746

diff --git a/rust/hg-core/src/dirstate.rs b/rust/hg-core/src/dirstate.rs
--- a/rust/hg-core/src/dirstate.rs
+++ b/rust/hg-core/src/dirstate.rs
@@ -77,7 +77,7 @@ pub const SIZE_FROM_OTHER_PARENT: i32 = 
 
 pub type StateMap = FastHashMap<HgPathBuf, DirstateEntry>;
 pub type StateMapIter<'a> =
-    Box<dyn Iterator<Item = (&'a HgPath, &'a DirstateEntry)> + Send + 'a>;
+    Box<dyn Iterator<Item = (&'a HgPath, DirstateEntry)> + Send + 'a>;
 
 pub type CopyMap = FastHashMap<HgPathBuf, HgPathBuf>;
 pub type CopyMapIter<'a> =
diff --git a/rust/hg-core/src/dirstate/dirs_multiset.rs b/rust/hg-core/src/dirstate/dirs_multiset.rs
--- a/rust/hg-core/src/dirstate/dirs_multiset.rs
+++ b/rust/hg-core/src/dirstate/dirs_multiset.rs
@@ -30,12 +30,12 @@ impl DirsMultiset {
     /// Initializes the multiset from a dirstate.
     ///
     /// If `skip_state` is provided, skips dirstate entries with equal state.
-    pub fn from_dirstate<'a, I, P>(
+    pub fn from_dirstate<I, P>(
         dirstate: I,
         skip_state: Option<EntryState>,
     ) -> Result<Self, DirstateMapError>
     where
-        I: IntoIterator<Item = (P, &'a DirstateEntry)>,
+        I: IntoIterator<Item = (P, DirstateEntry)>,
         P: AsRef<HgPath>,
     {
         let mut multiset = DirsMultiset {
@@ -338,7 +338,7 @@ mod tests {
         assert_eq!(expected, new);
 
         let new =
-            DirsMultiset::from_dirstate(&StateMap::default(), None).unwrap();
+            DirsMultiset::from_dirstate(StateMap::default(), None).unwrap();
         let expected = DirsMultiset {
             inner: FastHashMap::default(),
         };
@@ -381,7 +381,7 @@ mod tests {
             .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
             .collect();
 
-        let new = DirsMultiset::from_dirstate(&input_map, None).unwrap();
+        let new = DirsMultiset::from_dirstate(input_map, None).unwrap();
         let expected = DirsMultiset {
             inner: expected_inner,
         };
@@ -417,7 +417,7 @@ mod tests {
             .collect();
 
         let new =
-            DirsMultiset::from_dirstate(&input_map, Some(EntryState::Normal))
+            DirsMultiset::from_dirstate(input_map, Some(EntryState::Normal))
                 .unwrap();
         let expected = DirsMultiset {
             inner: expected_inner,
diff --git a/rust/hg-core/src/dirstate/dirstate_map.rs b/rust/hg-core/src/dirstate/dirstate_map.rs
--- a/rust/hg-core/src/dirstate/dirstate_map.rs
+++ b/rust/hg-core/src/dirstate/dirstate_map.rs
@@ -249,7 +249,7 @@ impl DirstateMap {
     pub fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
         if self.all_dirs.is_none() {
             self.all_dirs = Some(DirsMultiset::from_dirstate(
-                self.state_map.iter(),
+                self.state_map.iter().map(|(k, v)| (k, *v)),
                 None,
             )?);
         }
@@ -259,7 +259,7 @@ impl DirstateMap {
     pub fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
         if self.dirs.is_none() {
             self.dirs = Some(DirsMultiset::from_dirstate(
-                self.state_map.iter(),
+                self.state_map.iter().map(|(k, v)| (k, *v)),
                 Some(EntryState::Removed),
             )?);
         }
diff --git a/rust/hg-core/src/dirstate_tree/dirstate_map.rs b/rust/hg-core/src/dirstate_tree/dirstate_map.rs
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs
+++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs
@@ -627,13 +627,13 @@ impl<'on_disk> super::dispatch::Dirstate
         self.get(key).is_some()
     }
 
-    fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
-        self.get_node(key)?.entry.as_ref()
+    fn get(&self, key: &HgPath) -> Option<DirstateEntry> {
+        self.get_node(key)?.entry
     }
 
     fn iter(&self) -> StateMapIter<'_> {
         Box::new(self.iter_nodes().filter_map(|(path, node)| {
-            node.entry.as_ref().map(|entry| (&**path, entry))
+            node.entry.map(|entry| (&**path, entry))
         }))
     }
 }
diff --git a/rust/hg-core/src/dirstate_tree/dispatch.rs b/rust/hg-core/src/dirstate_tree/dispatch.rs
--- a/rust/hg-core/src/dirstate_tree/dispatch.rs
+++ b/rust/hg-core/src/dirstate_tree/dispatch.rs
@@ -117,7 +117,7 @@ pub trait DirstateMapMethods {
 
     fn contains_key(&self, key: &HgPath) -> bool;
 
-    fn get(&self, key: &HgPath) -> Option<&DirstateEntry>;
+    fn get(&self, key: &HgPath) -> Option<DirstateEntry>;
 
     fn iter(&self) -> StateMapIter<'_>;
 }
@@ -290,11 +290,11 @@ impl DirstateMapMethods for DirstateMap 
         (&**self).contains_key(key)
     }
 
-    fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
-        (&**self).get(key)
+    fn get(&self, key: &HgPath) -> Option<DirstateEntry> {
+        (&**self).get(key).cloned()
     }
 
     fn iter(&self) -> StateMapIter<'_> {
-        Box::new((&**self).iter().map(|(key, value)| (&**key, value)))
+        Box::new((&**self).iter().map(|(key, value)| (&**key, *value)))
     }
 }
diff --git a/rust/hg-cpython/src/dirstate/dirs_multiset.rs b/rust/hg-cpython/src/dirstate/dirs_multiset.rs
--- a/rust/hg-cpython/src/dirstate/dirs_multiset.rs
+++ b/rust/hg-cpython/src/dirstate/dirs_multiset.rs
@@ -45,7 +45,8 @@ py_class!(pub class Dirs |py| {
         }
         let inner = if let Ok(map) = map.cast_as::<PyDict>(py) {
             let dirstate = extract_dirstate(py, &map)?;
-            DirsMultiset::from_dirstate(&dirstate, skip_state)
+            let dirstate = dirstate.iter().map(|(k, v)| (k, *v));
+            DirsMultiset::from_dirstate(dirstate, skip_state)
                 .map_err(|e: DirstateMapError| {
                     PyErr::new::<exc::ValueError, _>(py, e.to_string())
                 })?
diff --git a/rust/hg-cpython/src/dirstate/dirstate_map.rs b/rust/hg-cpython/src/dirstate/dirstate_map.rs
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs
+++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs
@@ -92,7 +92,7 @@ py_class!(pub class DirstateMap |py| {
         let key = key.extract::<PyBytes>(py)?;
         match self.inner(py).borrow().get(HgPath::new(key.data(py))) {
             Some(entry) => {
-                Ok(Some(make_dirstate_tuple(py, entry)?))
+                Ok(Some(make_dirstate_tuple(py, &entry)?))
             },
             None => Ok(default)
         }
@@ -348,7 +348,7 @@ py_class!(pub class DirstateMap |py| {
         let key = HgPath::new(key.data(py));
         match self.inner(py).borrow().get(key) {
             Some(entry) => {
-                Ok(make_dirstate_tuple(py, entry)?)
+                Ok(make_dirstate_tuple(py, &entry)?)
             },
             None => Err(PyErr::new::<exc::KeyError, _>(
                 py,
@@ -525,13 +525,13 @@ impl DirstateMap {
     }
     fn translate_key(
         py: Python,
-        res: (&HgPath, &DirstateEntry),
+        res: (&HgPath, DirstateEntry),
     ) -> PyResult<Option<PyBytes>> {
         Ok(Some(PyBytes::new(py, res.0.as_bytes())))
     }
     fn translate_key_value(
         py: Python,
-        res: (&HgPath, &DirstateEntry),
+        res: (&HgPath, DirstateEntry),
     ) -> PyResult<Option<(PyBytes, PyObject)>> {
         let (f, entry) = res;
         Ok(Some((
diff --git a/rust/hg-cpython/src/dirstate/dispatch.rs b/rust/hg-cpython/src/dirstate/dispatch.rs
--- a/rust/hg-cpython/src/dirstate/dispatch.rs
+++ b/rust/hg-cpython/src/dirstate/dispatch.rs
@@ -173,7 +173,7 @@ impl DirstateMapMethods for OwningDirsta
         self.get().contains_key(key)
     }
 
-    fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
+    fn get(&self, key: &HgPath) -> Option<DirstateEntry> {
         self.get().get(key)
     }