rust-dirs: handle forgotten `Result`s
authorRaphaël Gomès <rgomes@octobus.net>
Thu, 12 Dec 2019 15:55:25 +0100
changeset 43874 bc7d8f45c3b6
parent 43873 5606e1cb4685
child 43875 cf065c6a0197
rust-dirs: handle forgotten `Result`s In 1fe2e574616e I introduced a temporary bugfix to align Rust code with a new behavior from C/Python and forgot about a few `Result`s (cargo's compiler cache does not re-emit warnings on cached modules). This fixes it. For the record, I am still unsure that this behavior change is a good idea. Note: I was already quite unhappy with the setters and getters for the `DirstateMap` and, indirectly, `Dirs`, and this only further reinforces my feelings. I hope we can one day fix that situation at the type level; Georges Racinet and I were just talking about devising a POC for using the builder pattern in the context of FFI with Python, we'll see what comes out of it. Differential Revision: https://phab.mercurial-scm.org/D7609
rust/hg-core/src/dirstate/dirs_multiset.rs
rust/hg-core/src/dirstate/dirstate_map.rs
rust/hg-core/src/matchers.rs
rust/hg-cpython/src/dirstate/dirs_multiset.rs
rust/hg-cpython/src/dirstate/dirstate_map.rs
--- a/rust/hg-core/src/dirstate/dirs_multiset.rs	Fri Dec 13 09:43:43 2019 -0800
+++ b/rust/hg-core/src/dirstate/dirs_multiset.rs	Thu Dec 12 15:55:25 2019 +0100
@@ -30,7 +30,7 @@
     pub fn from_dirstate(
         dirstate: &FastHashMap<HgPathBuf, DirstateEntry>,
         skip_state: Option<EntryState>,
-    ) -> Self {
+    ) -> Result<Self, DirstateMapError> {
         let mut multiset = DirsMultiset {
             inner: FastHashMap::default(),
         };
@@ -39,27 +39,29 @@
             // This `if` is optimized out of the loop
             if let Some(skip) = skip_state {
                 if skip != *state {
-                    multiset.add_path(filename);
+                    multiset.add_path(filename)?;
                 }
             } else {
-                multiset.add_path(filename);
+                multiset.add_path(filename)?;
             }
         }
 
-        multiset
+        Ok(multiset)
     }
 
     /// Initializes the multiset from a manifest.
-    pub fn from_manifest(manifest: &[impl AsRef<HgPath>]) -> Self {
+    pub fn from_manifest(
+        manifest: &[impl AsRef<HgPath>],
+    ) -> Result<Self, DirstateMapError> {
         let mut multiset = DirsMultiset {
             inner: FastHashMap::default(),
         };
 
         for filename in manifest {
-            multiset.add_path(filename.as_ref());
+            multiset.add_path(filename.as_ref())?;
         }
 
-        multiset
+        Ok(multiset)
     }
 
     /// Increases the count of deepest directory contained in the path.
@@ -134,7 +136,7 @@
     #[test]
     fn test_delete_path_path_not_found() {
         let manifest: Vec<HgPathBuf> = vec![];
-        let mut map = DirsMultiset::from_manifest(&manifest);
+        let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
         let path = HgPathBuf::from_bytes(b"doesnotexist/");
         assert_eq!(
             Err(DirstateMapError::PathNotFound(path.to_owned())),
@@ -144,7 +146,8 @@
 
     #[test]
     fn test_delete_path_empty_path() {
-        let mut map = DirsMultiset::from_manifest(&vec![HgPathBuf::new()]);
+        let mut map =
+            DirsMultiset::from_manifest(&vec![HgPathBuf::new()]).unwrap();
         let path = HgPath::new(b"");
         assert_eq!(Ok(()), map.delete_path(path));
         assert_eq!(
@@ -191,7 +194,7 @@
     #[test]
     fn test_add_path_empty_path() {
         let manifest: Vec<HgPathBuf> = vec![];
-        let mut map = DirsMultiset::from_manifest(&manifest);
+        let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
         let path = HgPath::new(b"");
         map.add_path(path);
 
@@ -201,7 +204,7 @@
     #[test]
     fn test_add_path_successful() {
         let manifest: Vec<HgPathBuf> = vec![];
-        let mut map = DirsMultiset::from_manifest(&manifest);
+        let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
 
         map.add_path(HgPath::new(b"a/"));
         assert_eq!(1, *map.inner.get(HgPath::new(b"a")).unwrap());
@@ -247,13 +250,14 @@
     #[test]
     fn test_dirsmultiset_new_empty() {
         let manifest: Vec<HgPathBuf> = vec![];
-        let new = DirsMultiset::from_manifest(&manifest);
+        let new = DirsMultiset::from_manifest(&manifest).unwrap();
         let expected = DirsMultiset {
             inner: FastHashMap::default(),
         };
         assert_eq!(expected, new);
 
-        let new = DirsMultiset::from_dirstate(&FastHashMap::default(), None);
+        let new = DirsMultiset::from_dirstate(&FastHashMap::default(), None)
+            .unwrap();
         let expected = DirsMultiset {
             inner: FastHashMap::default(),
         };
@@ -271,7 +275,7 @@
             .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
             .collect();
 
-        let new = DirsMultiset::from_manifest(&input_vec);
+        let new = DirsMultiset::from_manifest(&input_vec).unwrap();
         let expected = DirsMultiset {
             inner: expected_inner,
         };
@@ -296,7 +300,7 @@
             .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
             .collect();
 
-        let new = DirsMultiset::from_dirstate(&input_map, None);
+        let new = DirsMultiset::from_dirstate(&input_map, None).unwrap();
         let expected = DirsMultiset {
             inner: expected_inner,
         };
@@ -332,7 +336,8 @@
             .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,
         };
--- a/rust/hg-core/src/dirstate/dirstate_map.rs	Fri Dec 13 09:43:43 2019 -0800
+++ b/rust/hg-core/src/dirstate/dirstate_map.rs	Thu Dec 12 15:55:25 2019 +0100
@@ -126,7 +126,7 @@
         }
         if old_state == EntryState::Unknown {
             if let Some(ref mut all_dirs) = self.all_dirs {
-                all_dirs.add_path(filename);
+                all_dirs.add_path(filename)?;
             }
         }
 
@@ -227,30 +227,38 @@
     /// emulate a Python lazy property, but it is ugly and unidiomatic.
     /// TODO One day, rewriting this struct using the typestate might be a
     /// good idea.
-    pub fn set_all_dirs(&mut self) {
+    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, None));
+                Some(DirsMultiset::from_dirstate(&self.state_map, None)?);
         }
+        Ok(())
     }
 
-    pub fn set_dirs(&mut self) {
+    pub fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
         if self.dirs.is_none() {
             self.dirs = Some(DirsMultiset::from_dirstate(
                 &self.state_map,
                 Some(EntryState::Removed),
-            ));
+            )?);
         }
+        Ok(())
     }
 
-    pub fn has_tracked_dir(&mut self, directory: &HgPath) -> bool {
-        self.set_dirs();
-        self.dirs.as_ref().unwrap().contains(directory)
+    pub fn has_tracked_dir(
+        &mut self,
+        directory: &HgPath,
+    ) -> Result<bool, DirstateMapError> {
+        self.set_dirs()?;
+        Ok(self.dirs.as_ref().unwrap().contains(directory))
     }
 
-    pub fn has_dir(&mut self, directory: &HgPath) -> bool {
-        self.set_all_dirs();
-        self.all_dirs.as_ref().unwrap().contains(directory)
+    pub fn has_dir(
+        &mut self,
+        directory: &HgPath,
+    ) -> Result<bool, DirstateMapError> {
+        self.set_all_dirs()?;
+        Ok(self.all_dirs.as_ref().unwrap().contains(directory))
     }
 
     pub fn parents(
@@ -350,11 +358,11 @@
         assert!(map.dirs.is_none());
         assert!(map.all_dirs.is_none());
 
-        assert_eq!(false, map.has_dir(HgPath::new(b"nope")));
+        assert_eq!(map.has_dir(HgPath::new(b"nope")).unwrap(), false);
         assert!(map.all_dirs.is_some());
         assert!(map.dirs.is_none());
 
-        assert_eq!(false, map.has_tracked_dir(HgPath::new(b"nope")));
+        assert_eq!(map.has_tracked_dir(HgPath::new(b"nope")).unwrap(), false);
         assert!(map.dirs.is_some());
     }
 
--- a/rust/hg-core/src/matchers.rs	Fri Dec 13 09:43:43 2019 -0800
+++ b/rust/hg-core/src/matchers.rs	Thu Dec 12 15:55:25 2019 +0100
@@ -7,7 +7,7 @@
 
 //! Structs and types for matching files and directories.
 
-use crate::utils::hg_path::{HgPath, HgPathBuf};
+use crate::utils::hg_path::HgPath;
 use std::collections::HashSet;
 
 pub enum VisitChildrenSet<'a> {
--- a/rust/hg-cpython/src/dirstate/dirs_multiset.rs	Fri Dec 13 09:43:43 2019 -0800
+++ b/rust/hg-cpython/src/dirstate/dirs_multiset.rs	Thu Dec 12 15:55:25 2019 +0100
@@ -47,6 +47,9 @@
         let inner = if let Ok(map) = map.cast_as::<PyDict>(py) {
             let dirstate = extract_dirstate(py, &map)?;
             DirsMultiset::from_dirstate(&dirstate, skip_state)
+                .map_err(|e| {
+                    PyErr::new::<exc::ValueError, _>(py, e.to_string())
+                })?
         } else {
             let map: Result<Vec<HgPathBuf>, PyErr> = map
                 .iter(py)?
@@ -57,6 +60,9 @@
                 })
                 .collect();
             DirsMultiset::from_manifest(&map?)
+                .map_err(|e| {
+                    PyErr::new::<exc::ValueError, _>(py, e.to_string())
+                })?
         };
 
         Self::create_instance(
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs	Fri Dec 13 09:43:43 2019 -0800
+++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs	Thu Dec 12 15:55:25 2019 +0100
@@ -200,6 +200,9 @@
         let d = d.extract::<PyBytes>(py)?;
         Ok(self.inner_shared(py).borrow_mut()?
             .has_tracked_dir(HgPath::new(d.data(py)))
+            .map_err(|e| {
+                PyErr::new::<exc::ValueError, _>(py, e.to_string())
+            })?
             .to_py_object(py))
     }
 
@@ -207,6 +210,9 @@
         let d = d.extract::<PyBytes>(py)?;
         Ok(self.inner_shared(py).borrow_mut()?
             .has_dir(HgPath::new(d.data(py)))
+            .map_err(|e| {
+                PyErr::new::<exc::ValueError, _>(py, e.to_string())
+            })?
             .to_py_object(py))
     }
 
@@ -330,24 +336,35 @@
 
     def getdirs(&self) -> PyResult<Dirs> {
         // TODO don't copy, share the reference
-        self.inner_shared(py).borrow_mut()?.set_dirs();
+        self.inner_shared(py).borrow_mut()?.set_dirs()
+            .map_err(|e| {
+                PyErr::new::<exc::ValueError, _>(py, e.to_string())
+            })?;
         Dirs::from_inner(
             py,
             DirsMultiset::from_dirstate(
                 &self.inner_shared(py).borrow(),
                 Some(EntryState::Removed),
-            ),
+            )
+            .map_err(|e| {
+                PyErr::new::<exc::ValueError, _>(py, e.to_string())
+            })?,
         )
     }
     def getalldirs(&self) -> PyResult<Dirs> {
         // TODO don't copy, share the reference
-        self.inner_shared(py).borrow_mut()?.set_all_dirs();
+        self.inner_shared(py).borrow_mut()?.set_all_dirs()
+            .map_err(|e| {
+                PyErr::new::<exc::ValueError, _>(py, e.to_string())
+            })?;
         Dirs::from_inner(
             py,
             DirsMultiset::from_dirstate(
                 &self.inner_shared(py).borrow(),
                 None,
-            ),
+            ).map_err(|e| {
+                PyErr::new::<exc::ValueError, _>(py, e.to_string())
+            })?,
         )
     }