rust: add message to `DirstateV2ParseError` to give some context stable
authorRaphaël Gomès <rgomes@octobus.net>
Wed, 18 May 2022 09:50:39 +0100
branchstable
changeset 49373 f8ec7b16c98f
parent 49372 270f8e89ff32
child 49374 455fce57e89e
rust: add message to `DirstateV2ParseError` to give some context This is useful when debugging.
rust/hg-core/src/dirstate/entry.rs
rust/hg-core/src/dirstate_tree/dirstate_map.rs
rust/hg-core/src/dirstate_tree/on_disk.rs
--- a/rust/hg-core/src/dirstate/entry.rs	Sun Jun 12 16:04:57 2022 +0100
+++ b/rust/hg-core/src/dirstate/entry.rs	Wed May 18 09:50:39 2022 +0100
@@ -83,7 +83,7 @@
                 second_ambiguous,
             })
         } else {
-            Err(DirstateV2ParseError)
+            Err(DirstateV2ParseError::new("when reading datetime"))
         }
     }
 
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs	Sun Jun 12 16:04:57 2022 +0100
+++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs	Wed May 18 09:50:39 2022 +0100
@@ -463,7 +463,7 @@
         if let Some(data) = on_disk.get(..data_size) {
             Ok(on_disk::read(data, metadata)?)
         } else {
-            Err(DirstateV2ParseError.into())
+            Err(DirstateV2ParseError::new("not enough bytes on disk").into())
         }
     }
 
--- a/rust/hg-core/src/dirstate_tree/on_disk.rs	Sun Jun 12 16:04:57 2022 +0100
+++ b/rust/hg-core/src/dirstate_tree/on_disk.rs	Wed May 18 09:50:39 2022 +0100
@@ -175,11 +175,21 @@
 ///
 /// This should only happen if Mercurial is buggy or a repository is corrupted.
 #[derive(Debug)]
-pub struct DirstateV2ParseError;
+pub struct DirstateV2ParseError {
+    message: String,
+}
+
+impl DirstateV2ParseError {
+    pub fn new<S: Into<String>>(message: S) -> Self {
+        Self {
+            message: message.into(),
+        }
+    }
+}
 
 impl From<DirstateV2ParseError> for HgError {
-    fn from(_: DirstateV2ParseError) -> Self {
-        HgError::corrupted("dirstate-v2 parse error")
+    fn from(e: DirstateV2ParseError) -> Self {
+        HgError::corrupted(format!("dirstate-v2 parse error: {}", e.message))
     }
 }
 
@@ -262,13 +272,16 @@
 pub fn read_docket(
     on_disk: &[u8],
 ) -> Result<Docket<'_>, DirstateV2ParseError> {
-    let (header, uuid) =
-        DocketHeader::from_bytes(on_disk).map_err(|_| DirstateV2ParseError)?;
+    let (header, uuid) = DocketHeader::from_bytes(on_disk).map_err(|e| {
+        DirstateV2ParseError::new(format!("when reading docket, {}", e))
+    })?;
     let uuid_size = header.uuid_size as usize;
     if header.marker == *V2_FORMAT_MARKER && uuid.len() == uuid_size {
         Ok(Docket { header, uuid })
     } else {
-        Err(DirstateV2ParseError)
+        Err(DirstateV2ParseError::new(
+            "invalid format marker or uuid size",
+        ))
     }
 }
 
@@ -281,14 +294,17 @@
         map.dirstate_version = DirstateVersion::V2;
         return Ok(map);
     }
-    let (meta, _) = TreeMetadata::from_bytes(metadata)
-        .map_err(|_| DirstateV2ParseError)?;
+    let (meta, _) = TreeMetadata::from_bytes(metadata).map_err(|e| {
+        DirstateV2ParseError::new(format!("when parsing tree metadata, {}", e))
+    })?;
     let dirstate_map = DirstateMap {
         on_disk,
-        root: dirstate_map::ChildNodes::OnDisk(read_nodes(
-            on_disk,
-            meta.root_nodes,
-        )?),
+        root: dirstate_map::ChildNodes::OnDisk(
+            read_nodes(on_disk, meta.root_nodes).map_err(|mut e| {
+                e.message = format!("{}, when reading root notes", e.message);
+                e
+            })?,
+        ),
         nodes_with_entry_count: meta.nodes_with_entry_count.get(),
         nodes_with_copy_source_count: meta.nodes_with_copy_source_count.get(),
         ignore_patterns_hash: meta.ignore_patterns_hash,
@@ -317,7 +333,7 @@
                 .expect("dirstate-v2 base_name_start out of bounds");
             Ok(start)
         } else {
-            Err(DirstateV2ParseError)
+            Err(DirstateV2ParseError::new("not enough bytes for base name"))
         }
     }
 
@@ -571,11 +587,19 @@
     // `&[u8]` cannot occupy the entire addess space.
     let start = start.get().try_into().unwrap_or(std::usize::MAX);
     let len = len.try_into().unwrap_or(std::usize::MAX);
-    on_disk
-        .get(start..)
-        .and_then(|bytes| T::slice_from_bytes(bytes, len).ok())
+    let bytes = match on_disk.get(start..) {
+        Some(bytes) => bytes,
+        None => {
+            return Err(DirstateV2ParseError::new(
+                "not enough bytes from disk",
+            ))
+        }
+    };
+    T::slice_from_bytes(bytes, len)
+        .map_err(|e| {
+            DirstateV2ParseError::new(format!("when reading a slice, {}", e))
+        })
         .map(|(slice, _rest)| slice)
-        .ok_or_else(|| DirstateV2ParseError)
 }
 
 pub(crate) fn for_each_tracked_path<'on_disk>(
@@ -583,8 +607,9 @@
     metadata: &[u8],
     mut f: impl FnMut(&'on_disk HgPath),
 ) -> Result<(), DirstateV2ParseError> {
-    let (meta, _) = TreeMetadata::from_bytes(metadata)
-        .map_err(|_| DirstateV2ParseError)?;
+    let (meta, _) = TreeMetadata::from_bytes(metadata).map_err(|e| {
+        DirstateV2ParseError::new(format!("when parsing tree metadata, {}", e))
+    })?;
     fn recur<'on_disk>(
         on_disk: &'on_disk [u8],
         nodes: ChildNodes,