rust/hg-core/src/dirstate_tree/dirstate_map.rs
changeset 47283 2a9ddc8094c7
parent 47282 ce41ee53263f
child 47330 73f23e7610f8
equal deleted inserted replaced
47282:ce41ee53263f 47283:2a9ddc8094c7
     2 use micro_timer::timed;
     2 use micro_timer::timed;
     3 use std::borrow::Cow;
     3 use std::borrow::Cow;
     4 use std::convert::TryInto;
     4 use std::convert::TryInto;
     5 use std::path::PathBuf;
     5 use std::path::PathBuf;
     6 
     6 
     7 use super::on_disk::V2_FORMAT_MARKER;
     7 use super::on_disk;
     8 use super::path_with_basename::WithBasename;
     8 use super::path_with_basename::WithBasename;
     9 use crate::dirstate::parsers::clear_ambiguous_mtime;
     9 use crate::dirstate::parsers::clear_ambiguous_mtime;
    10 use crate::dirstate::parsers::pack_entry;
    10 use crate::dirstate::parsers::pack_entry;
    11 use crate::dirstate::parsers::packed_entry_size;
    11 use crate::dirstate::parsers::packed_entry_size;
    12 use crate::dirstate::parsers::parse_dirstate_entries;
    12 use crate::dirstate::parsers::parse_dirstate_entries;
    13 use crate::dirstate::parsers::Timestamp;
    13 use crate::dirstate::parsers::Timestamp;
    14 use crate::errors::HgError;
       
    15 use crate::matchers::Matcher;
    14 use crate::matchers::Matcher;
    16 use crate::utils::hg_path::{HgPath, HgPathBuf};
    15 use crate::utils::hg_path::{HgPath, HgPathBuf};
    17 use crate::utils::SliceExt;
       
    18 use crate::CopyMapIter;
    16 use crate::CopyMapIter;
    19 use crate::DirstateEntry;
    17 use crate::DirstateEntry;
    20 use crate::DirstateError;
    18 use crate::DirstateError;
    21 use crate::DirstateMapError;
    19 use crate::DirstateMapError;
    22 use crate::DirstateParents;
    20 use crate::DirstateParents;
    28 use crate::StatusError;
    26 use crate::StatusError;
    29 use crate::StatusOptions;
    27 use crate::StatusOptions;
    30 
    28 
    31 pub struct DirstateMap<'on_disk> {
    29 pub struct DirstateMap<'on_disk> {
    32     /// Contents of the `.hg/dirstate` file
    30     /// Contents of the `.hg/dirstate` file
    33     on_disk: &'on_disk [u8],
    31     pub(super) on_disk: &'on_disk [u8],
    34 
    32 
    35     pub(super) root: ChildNodes<'on_disk>,
    33     pub(super) root: ChildNodes<'on_disk>,
    36 
    34 
    37     /// Number of nodes anywhere in the tree that have `.entry.is_some()`.
    35     /// Number of nodes anywhere in the tree that have `.entry.is_some()`.
    38     nodes_with_entry_count: usize,
    36     pub(super) nodes_with_entry_count: u32,
    39 
    37 
    40     /// Number of nodes anywhere in the tree that have
    38     /// Number of nodes anywhere in the tree that have
    41     /// `.copy_source.is_some()`.
    39     /// `.copy_source.is_some()`.
    42     nodes_with_copy_source_count: usize,
    40     pub(super) nodes_with_copy_source_count: u32,
    43 }
    41 }
    44 
    42 
    45 /// Using a plain `HgPathBuf` of the full path from the repository root as a
    43 /// Using a plain `HgPathBuf` of the full path from the repository root as a
    46 /// map key would also work: all paths in a given map have the same parent
    44 /// map key would also work: all paths in a given map have the same parent
    47 /// path, so comparing full paths gives the same result as comparing base
    45 /// path, so comparing full paths gives the same result as comparing base
    60     pub(super) copy_source: Option<Cow<'on_disk, HgPath>>,
    58     pub(super) copy_source: Option<Cow<'on_disk, HgPath>>,
    61 
    59 
    62     pub(super) children: ChildNodes<'on_disk>,
    60     pub(super) children: ChildNodes<'on_disk>,
    63 
    61 
    64     /// How many (non-inclusive) descendants of this node are tracked files
    62     /// How many (non-inclusive) descendants of this node are tracked files
    65     tracked_descendants_count: usize,
    63     pub(super) tracked_descendants_count: u32,
    66 }
    64 }
    67 
    65 
    68 impl<'on_disk> Node<'on_disk> {
    66 impl<'on_disk> Node<'on_disk> {
    69     pub(super) fn state(&self) -> Option<EntryState> {
    67     pub(super) fn state(&self) -> Option<EntryState> {
    70         self.entry.as_ref().map(|entry| entry.state)
    68         self.entry.as_ref().map(|entry| entry.state)
    87     &'tree mut Option<DirstateEntry>,
    85     &'tree mut Option<DirstateEntry>,
    88     &'tree mut Option<Cow<'on_disk, HgPath>>,
    86     &'tree mut Option<Cow<'on_disk, HgPath>>,
    89 );
    87 );
    90 
    88 
    91 impl<'on_disk> DirstateMap<'on_disk> {
    89 impl<'on_disk> DirstateMap<'on_disk> {
       
    90     pub(super) fn empty(on_disk: &'on_disk [u8]) -> Self {
       
    91         Self {
       
    92             on_disk,
       
    93             root: ChildNodes::default(),
       
    94             nodes_with_entry_count: 0,
       
    95             nodes_with_copy_source_count: 0,
       
    96         }
       
    97     }
       
    98 
    92     #[timed]
    99     #[timed]
    93     pub fn new_v2(
   100     pub fn new_v2(
    94         on_disk: &'on_disk [u8],
   101         on_disk: &'on_disk [u8],
    95     ) -> Result<(Self, Option<DirstateParents>), DirstateError> {
   102     ) -> Result<(Self, Option<DirstateParents>), DirstateError> {
    96         if let Some(rest) = on_disk.drop_prefix(V2_FORMAT_MARKER) {
   103         on_disk::read(on_disk)
    97             Self::new_v1(rest)
       
    98         } else if on_disk.is_empty() {
       
    99             Self::new_v1(on_disk)
       
   100         } else {
       
   101             return Err(HgError::corrupted(
       
   102                 "missing dirstate-v2 magic number",
       
   103             )
       
   104             .into());
       
   105         }
       
   106     }
   104     }
   107 
   105 
   108     #[timed]
   106     #[timed]
   109     pub fn new_v1(
   107     pub fn new_v1(
   110         on_disk: &'on_disk [u8],
   108         on_disk: &'on_disk [u8],
   111     ) -> Result<(Self, Option<DirstateParents>), DirstateError> {
   109     ) -> Result<(Self, Option<DirstateParents>), DirstateError> {
   112         let mut map = Self {
   110         let mut map = Self::empty(on_disk);
   113             on_disk,
       
   114             root: ChildNodes::default(),
       
   115             nodes_with_entry_count: 0,
       
   116             nodes_with_copy_source_count: 0,
       
   117         };
       
   118         if map.on_disk.is_empty() {
   111         if map.on_disk.is_empty() {
   119             return Ok((map, None));
   112             return Ok((map, None));
   120         }
   113         }
   121 
   114 
   122         let parents = parse_dirstate_entries(
   115         let parents = parse_dirstate_entries(
   563     fn pack_v2(
   556     fn pack_v2(
   564         &mut self,
   557         &mut self,
   565         parents: DirstateParents,
   558         parents: DirstateParents,
   566         now: Timestamp,
   559         now: Timestamp,
   567     ) -> Result<Vec<u8>, DirstateError> {
   560     ) -> Result<Vec<u8>, DirstateError> {
   568         // Inefficient but temporary
   561         on_disk::write(self, parents, now)
   569         let mut v2 = V2_FORMAT_MARKER.to_vec();
       
   570         v2.append(&mut self.pack_v1(parents, now)?);
       
   571         Ok(v2)
       
   572     }
   562     }
   573 
   563 
   574     fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
   564     fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
   575         // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
   565         // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
   576         // needs to be recomputed
   566         // needs to be recomputed
   593     {
   583     {
   594         super::status::status(self, matcher, root_dir, ignore_files, options)
   584         super::status::status(self, matcher, root_dir, ignore_files, options)
   595     }
   585     }
   596 
   586 
   597     fn copy_map_len(&self) -> usize {
   587     fn copy_map_len(&self) -> usize {
   598         self.nodes_with_copy_source_count
   588         self.nodes_with_copy_source_count as usize
   599     }
   589     }
   600 
   590 
   601     fn copy_map_iter(&self) -> CopyMapIter<'_> {
   591     fn copy_map_iter(&self) -> CopyMapIter<'_> {
   602         Box::new(self.iter_nodes().filter_map(|(path, node)| {
   592         Box::new(self.iter_nodes().filter_map(|(path, node)| {
   603             node.copy_source
   593             node.copy_source
   644         }
   634         }
   645         node.copy_source.replace(value.into()).map(Cow::into_owned)
   635         node.copy_source.replace(value.into()).map(Cow::into_owned)
   646     }
   636     }
   647 
   637 
   648     fn len(&self) -> usize {
   638     fn len(&self) -> usize {
   649         self.nodes_with_entry_count
   639         self.nodes_with_entry_count as usize
   650     }
   640     }
   651 
   641 
   652     fn contains_key(&self, key: &HgPath) -> bool {
   642     fn contains_key(&self, key: &HgPath) -> bool {
   653         self.get(key).is_some()
   643         self.get(key).is_some()
   654     }
   644     }