This will help reduce code and footgun potential for simpler callers.
Details
Details
Diff Detail
Diff Detail
- Repository
- rHG Mercurial
- Branch
- default
- Lint
No Linters Available - Unit
No Unit Test Coverage
hg-reviewers |
This will help reduce code and footgun potential for simpler callers.
No Linters Available |
No Unit Test Coverage |
Path | Packages | |||
---|---|---|---|---|
M | rust/hg-core/src/dirstate_tree/dirstate_map.rs (76 lines) |
Commit | Parents | Author | Summary | Date |
---|---|---|---|---|
c4dcac589c88 | e96b9ba2f8c3 | Raphaël Gomès | Fri, Apr 8, 11:55 AM |
Status | Author | Revision | |
---|---|---|---|
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare | ||
Needs Review | Alphare |
} else { | } else { | ||||
return Ok(None); | return Ok(None); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/// Returns a mutable reference to the node at `path` if it exists | /// Returns a mutable reference to the node at `path` if it exists | ||||
/// | /// | ||||
/// `each_ancestor` is a callback that is called for each ancestor node | |||||
/// when descending the tree. It is used to keep the different counters | |||||
/// of the `DirstateMap` up-to-date. | |||||
fn get_node_mut<'tree>( | |||||
&'tree mut self, | |||||
path: &HgPath, | |||||
each_ancestor: impl FnMut(&mut Node), | |||||
) -> Result<Option<&'tree mut Node<'on_disk>>, DirstateV2ParseError> { | |||||
Self::get_node_mut_inner( | |||||
self.on_disk, | |||||
&mut self.unreachable_bytes, | |||||
&mut self.root, | |||||
path, | |||||
each_ancestor, | |||||
) | |||||
} | |||||
/// Lower-level version of `get_node_mut`. | |||||
/// | |||||
/// This takes `root` instead of `&mut self` so that callers can mutate | /// This takes `root` instead of `&mut self` so that callers can mutate | ||||
/// other fields while the returned borrow is still valid. | /// other fields while the returned borrow is still valid. | ||||
/// | /// | ||||
/// `each_ancestor` is a callback that is called for each ancestor node | /// `each_ancestor` is a callback that is called for each ancestor node | ||||
/// when descending the tree. It is used to keep the different counters | /// when descending the tree. It is used to keep the different counters | ||||
/// of the `DirstateMap` up-to-date. | /// of the `DirstateMap` up-to-date. | ||||
fn get_node_mut<'tree>( | fn get_node_mut_inner<'tree>( | ||||
on_disk: &'on_disk [u8], | on_disk: &'on_disk [u8], | ||||
unreachable_bytes: &mut u32, | unreachable_bytes: &mut u32, | ||||
root: &'tree mut ChildNodes<'on_disk>, | root: &'tree mut ChildNodes<'on_disk>, | ||||
path: &HgPath, | path: &HgPath, | ||||
mut each_ancestor: impl FnMut(&mut Node), | mut each_ancestor: impl FnMut(&mut Node), | ||||
) -> Result<Option<&'tree mut Node<'on_disk>>, DirstateV2ParseError> { | ) -> Result<Option<&'tree mut Node<'on_disk>>, DirstateV2ParseError> { | ||||
let mut children = root; | let mut children = root; | ||||
let mut components = path.components(); | let mut components = path.components(); | ||||
/// # Panics | /// # Panics | ||||
/// | /// | ||||
/// Panics if the node does not exist. | /// Panics if the node does not exist. | ||||
fn set_untracked( | fn set_untracked( | ||||
&mut self, | &mut self, | ||||
filename: &HgPath, | filename: &HgPath, | ||||
old_entry: DirstateEntry, | old_entry: DirstateEntry, | ||||
) -> Result<(), DirstateV2ParseError> { | ) -> Result<(), DirstateV2ParseError> { | ||||
let node = DirstateMap::get_node_mut( | let node = self | ||||
self.on_disk, | .get_node_mut(filename, |ancestor| { | ||||
&mut self.unreachable_bytes, | |||||
&mut self.root, | |||||
filename, | |||||
|ancestor| { | |||||
ancestor.tracked_descendants_count = ancestor | ancestor.tracked_descendants_count = ancestor | ||||
.tracked_descendants_count | .tracked_descendants_count | ||||
.checked_sub(1) | .checked_sub(1) | ||||
.expect("tracked_descendants_count should be >= 0"); | .expect("tracked_descendants_count should be >= 0"); | ||||
}, | })? | ||||
)? | |||||
.expect("node should exist"); | .expect("node should exist"); | ||||
let mut new_entry = old_entry.clone(); | let mut new_entry = old_entry.clone(); | ||||
new_entry.set_untracked(); | new_entry.set_untracked(); | ||||
node.data = NodeData::Entry(new_entry); | node.data = NodeData::Entry(new_entry); | ||||
Ok(()) | Ok(()) | ||||
} | } | ||||
/// Set a node as clean in the dirstate. | /// Set a node as clean in the dirstate. | ||||
/// | /// | ||||
/// It is the responsibility of the caller to remove the copy source. | /// It is the responsibility of the caller to remove the copy source. | ||||
/// | /// | ||||
/// # Panics | /// # Panics | ||||
/// | /// | ||||
/// Panics if the node does not exist. | /// Panics if the node does not exist. | ||||
fn set_clean( | fn set_clean( | ||||
&mut self, | &mut self, | ||||
filename: &HgPath, | filename: &HgPath, | ||||
old_entry: DirstateEntry, | old_entry: DirstateEntry, | ||||
mode: u32, | mode: u32, | ||||
size: u32, | size: u32, | ||||
mtime: TruncatedTimestamp, | mtime: TruncatedTimestamp, | ||||
) -> Result<(), DirstateError> { | ) -> Result<(), DirstateError> { | ||||
let node = DirstateMap::get_node_mut( | let node = self | ||||
self.on_disk, | .get_node_mut(filename, |ancestor| { | ||||
&mut self.unreachable_bytes, | |||||
&mut self.root, | |||||
filename, | |||||
|ancestor| { | |||||
if !old_entry.tracked() { | if !old_entry.tracked() { | ||||
ancestor.tracked_descendants_count += 1; | ancestor.tracked_descendants_count += 1; | ||||
} | } | ||||
}, | })? | ||||
)? | |||||
.expect("node should exist"); | .expect("node should exist"); | ||||
let mut new_entry = old_entry.clone(); | let mut new_entry = old_entry.clone(); | ||||
new_entry.set_clean(mode, size, mtime); | new_entry.set_clean(mode, size, mtime); | ||||
node.data = NodeData::Entry(new_entry); | node.data = NodeData::Entry(new_entry); | ||||
Ok(()) | Ok(()) | ||||
} | } | ||||
/// Set a node as possibly dirty in the dirstate. | /// Set a node as possibly dirty in the dirstate. | ||||
/// | /// | ||||
/// # Panics | /// # Panics | ||||
/// | /// | ||||
/// Panics if the node does not exist. | /// Panics if the node does not exist. | ||||
fn set_possibly_dirty( | fn set_possibly_dirty( | ||||
&mut self, | &mut self, | ||||
filename: &HgPath, | filename: &HgPath, | ||||
) -> Result<(), DirstateError> { | ) -> Result<(), DirstateError> { | ||||
let node = DirstateMap::get_node_mut( | let node = self | ||||
self.on_disk, | .get_node_mut(filename, |_ancestor| {})? | ||||
&mut self.unreachable_bytes, | |||||
&mut self.root, | |||||
filename, | |||||
|_ancestor| {}, | |||||
)? | |||||
.expect("node should exist"); | .expect("node should exist"); | ||||
let entry = node.data.as_entry_mut().expect("entry should exist"); | let entry = node.data.as_entry_mut().expect("entry should exist"); | ||||
entry.set_possibly_dirty(); | entry.set_possibly_dirty(); | ||||
node.data = NodeData::Entry(*entry); | node.data = NodeData::Entry(*entry); | ||||
Ok(()) | Ok(()) | ||||
} | } | ||||
/// Clears the cached mtime for the (potential) folder at `path`. | /// Clears the cached mtime for the (potential) folder at `path`. | ||||
pub(super) fn clear_cached_mtime( | pub(super) fn clear_cached_mtime( | ||||
&mut self, | &mut self, | ||||
path: &HgPath, | path: &HgPath, | ||||
) -> Result<(), DirstateV2ParseError> { | ) -> Result<(), DirstateV2ParseError> { | ||||
let node = match DirstateMap::get_node_mut( | let node = match self.get_node_mut(path, |_ancestor| {})? { | ||||
self.on_disk, | |||||
&mut self.unreachable_bytes, | |||||
&mut self.root, | |||||
path, | |||||
|_ancestor| {}, | |||||
)? { | |||||
Some(node) => node, | Some(node) => node, | ||||
None => return Ok(()), | None => return Ok(()), | ||||
}; | }; | ||||
if let NodeData::CachedDirectory { .. } = &node.data { | if let NodeData::CachedDirectory { .. } = &node.data { | ||||
node.data = NodeData::None | node.data = NodeData::None | ||||
} | } | ||||
Ok(()) | Ok(()) | ||||
} | } | ||||
/// Sets the cached mtime for the (potential) folder at `path`. | /// Sets the cached mtime for the (potential) folder at `path`. | ||||
pub(super) fn set_cached_mtime( | pub(super) fn set_cached_mtime( | ||||
&mut self, | &mut self, | ||||
path: &HgPath, | path: &HgPath, | ||||
mtime: TruncatedTimestamp, | mtime: TruncatedTimestamp, | ||||
) -> Result<(), DirstateV2ParseError> { | ) -> Result<(), DirstateV2ParseError> { | ||||
let node = match DirstateMap::get_node_mut( | let node = match self.get_node_mut(path, |_ancestor| {})? { | ||||
self.on_disk, | |||||
&mut self.unreachable_bytes, | |||||
&mut self.root, | |||||
path, | |||||
|_ancestor| {}, | |||||
)? { | |||||
Some(node) => node, | Some(node) => node, | ||||
None => return Ok(()), | None => return Ok(()), | ||||
}; | }; | ||||
match &node.data { | match &node.data { | ||||
NodeData::Entry(_) => {} // Don’t overwrite an entry | NodeData::Entry(_) => {} // Don’t overwrite an entry | ||||
NodeData::CachedDirectory { .. } | NodeData::None => { | NodeData::CachedDirectory { .. } | NodeData::None => { | ||||
node.data = NodeData::CachedDirectory { mtime } | node.data = NodeData::CachedDirectory { mtime } | ||||
} | } | ||||
pub fn copy_map_remove( | pub fn copy_map_remove( | ||||
&mut self, | &mut self, | ||||
key: &HgPath, | key: &HgPath, | ||||
) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { | ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { | ||||
self.with_dmap_mut(|map| { | self.with_dmap_mut(|map| { | ||||
let count = &mut map.nodes_with_copy_source_count; | let count = &mut map.nodes_with_copy_source_count; | ||||
let unreachable_bytes = &mut map.unreachable_bytes; | let unreachable_bytes = &mut map.unreachable_bytes; | ||||
Ok(DirstateMap::get_node_mut( | Ok(DirstateMap::get_node_mut_inner( | ||||
map.on_disk, | map.on_disk, | ||||
unreachable_bytes, | unreachable_bytes, | ||||
&mut map.root, | &mut map.root, | ||||
key, | key, | ||||
|_ancestor| {}, | |_ancestor| {}, | ||||
)? | )? | ||||
.and_then(|node| { | .and_then(|node| { | ||||
if let Some(source) = &node.copy_source { | if let Some(source) = &node.copy_source { |