Mercurial > public > mercurial-scm > hg
view rust/hg-core/src/dirstate.rs @ 47347:73ddcedeaadf
dirstate-tree: Change status() results to not borrow DirstateMap
The `status` function takes a `&'tree mut DirstateMap<'on_disk>` parameter.
`'on_disk` borrows a read-only byte buffer with the contents of the
`.hg/dirstate` file. `DirstateMap` internally uses represents file paths as
`std::borrow::Cow<'on_disk, HgPath>`, which borrows the byte buffer when
possible and allocates an owned string if not, such as for files added to the
dirstate after it was loaded from disk.
Previously the return type of of `status` has a `'tree`?lifetime, meaning it
could borrow all paths from the `DirstateMap`. With this changeset, that
lifetime is changed to `'on_disk` meaning that only paths from the byte buffer
can be borrowed, and paths allocated by `DirstateMap` must be copied.
Usually most paths are in the byte buffer, and most paths are not part of the
return value of `status`, so the number of extra copies should be small.
This change will enable `status` to mutate the `DirstateMap` after it has
finished constructing its return value. Previously such mutation would be
prevented by possible on-going borrows.
Differential Revision: https://phab.mercurial-scm.org/D10824
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Fri, 28 May 2021 20:07:27 +0200 |
parents | ed1583a845d2 |
children | bd88b6bfd8da |
line wrap: on
line source
// dirstate module // // Copyright 2019 Raphaël Gomès <rgomes@octobus.net> // // This software may be used and distributed according to the terms of the // GNU General Public License version 2 or any later version. use crate::dirstate_tree::on_disk::DirstateV2ParseError; use crate::errors::HgError; use crate::revlog::Node; use crate::utils::hg_path::{HgPath, HgPathBuf}; use crate::FastHashMap; use bytes_cast::{unaligned, BytesCast}; use std::convert::TryFrom; pub mod dirs_multiset; pub mod dirstate_map; pub mod parsers; pub mod status; #[derive(Debug, PartialEq, Clone, BytesCast)] #[repr(C)] pub struct DirstateParents { pub p1: Node, pub p2: Node, } /// The C implementation uses all signed types. This will be an issue /// either when 4GB+ source files are commonplace or in 2038, whichever /// comes first. #[derive(Debug, PartialEq, Copy, Clone)] pub struct DirstateEntry { pub state: EntryState, pub mode: i32, pub mtime: i32, pub size: i32, } impl DirstateEntry { pub fn is_non_normal(&self) -> bool { self.state != EntryState::Normal || self.mtime == MTIME_UNSET } pub fn is_from_other_parent(&self) -> bool { self.state == EntryState::Normal && self.size == SIZE_FROM_OTHER_PARENT } // TODO: other platforms #[cfg(unix)] pub fn mode_changed( &self, filesystem_metadata: &std::fs::Metadata, ) -> bool { use std::os::unix::fs::MetadataExt; const EXEC_BIT_MASK: u32 = 0o100; let dirstate_exec_bit = (self.mode as u32) & EXEC_BIT_MASK; let fs_exec_bit = filesystem_metadata.mode() & EXEC_BIT_MASK; dirstate_exec_bit != fs_exec_bit } } #[derive(BytesCast)] #[repr(C)] struct RawEntry { state: u8, mode: unaligned::I32Be, size: unaligned::I32Be, mtime: unaligned::I32Be, length: unaligned::I32Be, } const MTIME_UNSET: i32 = -1; /// A `DirstateEntry` with a size of `-2` means that it was merged from the /// other parent. This allows revert to pick the right status back during a /// merge. pub const SIZE_FROM_OTHER_PARENT: i32 = -2; pub type StateMap = FastHashMap<HgPathBuf, DirstateEntry>; pub type StateMapIter<'a> = Box< dyn Iterator< Item = Result<(&'a HgPath, DirstateEntry), DirstateV2ParseError>, > + Send + 'a, >; pub type CopyMap = FastHashMap<HgPathBuf, HgPathBuf>; pub type CopyMapIter<'a> = Box< dyn Iterator<Item = Result<(&'a HgPath, &'a HgPath), DirstateV2ParseError>> + Send + 'a, >; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum EntryState { Normal, Added, Removed, Merged, Unknown, } impl EntryState { pub fn is_tracked(self) -> bool { use EntryState::*; match self { Normal | Added | Merged => true, Removed | Unknown => false, } } } impl TryFrom<u8> for EntryState { type Error = HgError; fn try_from(value: u8) -> Result<Self, Self::Error> { match value { b'n' => Ok(EntryState::Normal), b'a' => Ok(EntryState::Added), b'r' => Ok(EntryState::Removed), b'm' => Ok(EntryState::Merged), b'?' => Ok(EntryState::Unknown), _ => Err(HgError::CorruptedRepository(format!( "Incorrect dirstate entry state {}", value ))), } } } impl Into<u8> for EntryState { fn into(self) -> u8 { match self { EntryState::Normal => b'n', EntryState::Added => b'a', EntryState::Removed => b'r', EntryState::Merged => b'm', EntryState::Unknown => b'?', } } }