rust/hg-core/src/dirstate/dirstate_map.rs
changeset 48061 060cd909439f
parent 48056 cd13d3c2ad2e
equal deleted inserted replaced
48060:a660d8a53267 48061:060cd909439f
     4 //
     4 //
     5 // This software may be used and distributed according to the terms of the
     5 // This software may be used and distributed according to the terms of the
     6 // GNU General Public License version 2 or any later version.
     6 // GNU General Public License version 2 or any later version.
     7 
     7 
     8 use crate::dirstate::parsers::Timestamp;
     8 use crate::dirstate::parsers::Timestamp;
       
     9 use crate::errors::HgError;
     9 use crate::{
    10 use crate::{
    10     dirstate::EntryState,
    11     dirstate::EntryState,
    11     dirstate::SIZE_FROM_OTHER_PARENT,
    12     dirstate::SIZE_FROM_OTHER_PARENT,
    12     dirstate::SIZE_NON_NORMAL,
    13     dirstate::SIZE_NON_NORMAL,
    13     pack_dirstate, parse_dirstate,
    14     pack_dirstate, parse_dirstate,
    14     utils::hg_path::{HgPath, HgPathBuf},
    15     utils::hg_path::{HgPath, HgPathBuf},
    15     CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateParents,
    16     CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateParents,
    16     StateMap,
    17     StateMap,
    17 };
    18 };
    18 use micro_timer::timed;
    19 use micro_timer::timed;
    19 use std::collections::HashSet;
       
    20 use std::iter::FromIterator;
    20 use std::iter::FromIterator;
    21 use std::ops::Deref;
    21 use std::ops::Deref;
    22 
    22 
    23 #[derive(Default)]
    23 #[derive(Default)]
    24 pub struct DirstateMap {
    24 pub struct DirstateMap {
    25     state_map: StateMap,
    25     state_map: StateMap,
    26     pub copy_map: CopyMap,
    26     pub copy_map: CopyMap,
    27     pub dirs: Option<DirsMultiset>,
    27     pub dirs: Option<DirsMultiset>,
    28     pub all_dirs: Option<DirsMultiset>,
    28     pub all_dirs: Option<DirsMultiset>,
    29     non_normal_set: Option<HashSet<HgPathBuf>>,
       
    30     other_parent_set: Option<HashSet<HgPathBuf>>,
       
    31 }
    29 }
    32 
    30 
    33 /// Should only really be used in python interface code, for clarity
    31 /// Should only really be used in python interface code, for clarity
    34 impl Deref for DirstateMap {
    32 impl Deref for DirstateMap {
    35     type Target = StateMap;
    33     type Target = StateMap;
    56     }
    54     }
    57 
    55 
    58     pub fn clear(&mut self) {
    56     pub fn clear(&mut self) {
    59         self.state_map = StateMap::default();
    57         self.state_map = StateMap::default();
    60         self.copy_map.clear();
    58         self.copy_map.clear();
    61         self.non_normal_set = None;
       
    62         self.other_parent_set = None;
       
    63     }
    59     }
    64 
    60 
    65     pub fn set_entry(&mut self, filename: &HgPath, entry: DirstateEntry) {
    61     pub fn set_entry(&mut self, filename: &HgPath, entry: DirstateEntry) {
    66         self.state_map.insert(filename.to_owned(), entry);
    62         self.state_map.insert(filename.to_owned(), entry);
    67     }
    63     }
    82             if let Some(ref mut all_dirs) = self.all_dirs {
    78             if let Some(ref mut all_dirs) = self.all_dirs {
    83                 all_dirs.add_path(filename)?;
    79                 all_dirs.add_path(filename)?;
    84             }
    80             }
    85         }
    81         }
    86         self.state_map.insert(filename.to_owned(), entry.to_owned());
    82         self.state_map.insert(filename.to_owned(), entry.to_owned());
    87 
       
    88         if entry.is_non_normal() {
       
    89             self.get_non_normal_other_parent_entries()
       
    90                 .0
       
    91                 .insert(filename.to_owned());
       
    92         }
       
    93 
       
    94         if entry.is_from_other_parent() {
       
    95             self.get_non_normal_other_parent_entries()
       
    96                 .1
       
    97                 .insert(filename.to_owned());
       
    98         }
       
    99         Ok(())
    83         Ok(())
   100     }
    84     }
   101 
    85 
   102     /// Mark a file as removed in the dirstate.
    86     /// Mark a file as removed in the dirstate.
   103     ///
    87     ///
   124                 } else if old_entry.state() == EntryState::Normal
   108                 } else if old_entry.state() == EntryState::Normal
   125                     && old_entry.size() == SIZE_FROM_OTHER_PARENT
   109                     && old_entry.size() == SIZE_FROM_OTHER_PARENT
   126                 {
   110                 {
   127                     // other parent
   111                     // other parent
   128                     size = SIZE_FROM_OTHER_PARENT;
   112                     size = SIZE_FROM_OTHER_PARENT;
   129                     self.get_non_normal_other_parent_entries()
       
   130                         .1
       
   131                         .insert(filename.to_owned());
       
   132                 }
   113                 }
   133             }
   114             }
   134         }
   115         }
   135         if old_state.is_some() && old_state != Some(EntryState::Removed) {
   116         if old_state.is_some() && old_state != Some(EntryState::Removed) {
   136             if let Some(ref mut dirs) = self.dirs {
   117             if let Some(ref mut dirs) = self.dirs {
   146             self.copy_map.remove(filename);
   127             self.copy_map.remove(filename);
   147         }
   128         }
   148 
   129 
   149         self.state_map
   130         self.state_map
   150             .insert(filename.to_owned(), DirstateEntry::new_removed(size));
   131             .insert(filename.to_owned(), DirstateEntry::new_removed(size));
   151         self.get_non_normal_other_parent_entries()
       
   152             .0
       
   153             .insert(filename.to_owned());
       
   154         Ok(())
   132         Ok(())
   155     }
   133     }
   156 
   134 
   157     /// Remove a file from the dirstate.
   135     /// Remove a file from the dirstate.
   158     /// Returns `true` if the file was previously recorded.
   136     /// Returns `true` if the file was previously recorded.
   171             }
   149             }
   172             if let Some(ref mut all_dirs) = self.all_dirs {
   150             if let Some(ref mut all_dirs) = self.all_dirs {
   173                 all_dirs.delete_path(filename)?;
   151                 all_dirs.delete_path(filename)?;
   174             }
   152             }
   175         }
   153         }
   176         self.get_non_normal_other_parent_entries()
       
   177             .0
       
   178             .remove(filename);
       
   179 
       
   180         self.copy_map.remove(filename);
   154         self.copy_map.remove(filename);
   181 
   155 
   182         Ok(())
   156         Ok(())
   183     }
       
   184 
       
   185     pub fn non_normal_entries_remove(
       
   186         &mut self,
       
   187         key: impl AsRef<HgPath>,
       
   188     ) -> bool {
       
   189         self.get_non_normal_other_parent_entries()
       
   190             .0
       
   191             .remove(key.as_ref())
       
   192     }
       
   193 
       
   194     pub fn non_normal_entries_add(&mut self, key: impl AsRef<HgPath>) {
       
   195         self.get_non_normal_other_parent_entries()
       
   196             .0
       
   197             .insert(key.as_ref().into());
       
   198     }
       
   199 
       
   200     pub fn non_normal_entries_union(
       
   201         &mut self,
       
   202         other: HashSet<HgPathBuf>,
       
   203     ) -> Vec<HgPathBuf> {
       
   204         self.get_non_normal_other_parent_entries()
       
   205             .0
       
   206             .union(&other)
       
   207             .map(ToOwned::to_owned)
       
   208             .collect()
       
   209     }
       
   210 
       
   211     pub fn get_non_normal_other_parent_entries(
       
   212         &mut self,
       
   213     ) -> (&mut HashSet<HgPathBuf>, &mut HashSet<HgPathBuf>) {
       
   214         self.set_non_normal_other_parent_entries(false);
       
   215         (
       
   216             self.non_normal_set.as_mut().unwrap(),
       
   217             self.other_parent_set.as_mut().unwrap(),
       
   218         )
       
   219     }
       
   220 
       
   221     /// Useful to get immutable references to those sets in contexts where
       
   222     /// you only have an immutable reference to the `DirstateMap`, like when
       
   223     /// sharing references with Python.
       
   224     ///
       
   225     /// TODO, get rid of this along with the other "setter/getter" stuff when
       
   226     /// a nice typestate plan is defined.
       
   227     ///
       
   228     /// # Panics
       
   229     ///
       
   230     /// Will panic if either set is `None`.
       
   231     pub fn get_non_normal_other_parent_entries_panic(
       
   232         &self,
       
   233     ) -> (&HashSet<HgPathBuf>, &HashSet<HgPathBuf>) {
       
   234         (
       
   235             self.non_normal_set.as_ref().unwrap(),
       
   236             self.other_parent_set.as_ref().unwrap(),
       
   237         )
       
   238     }
       
   239 
       
   240     pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
       
   241         if !force
       
   242             && self.non_normal_set.is_some()
       
   243             && self.other_parent_set.is_some()
       
   244         {
       
   245             return;
       
   246         }
       
   247         let mut non_normal = HashSet::new();
       
   248         let mut other_parent = HashSet::new();
       
   249 
       
   250         for (filename, entry) in self.state_map.iter() {
       
   251             if entry.is_non_normal() {
       
   252                 non_normal.insert(filename.to_owned());
       
   253             }
       
   254             if entry.is_from_other_parent() {
       
   255                 other_parent.insert(filename.to_owned());
       
   256             }
       
   257         }
       
   258         self.non_normal_set = Some(non_normal);
       
   259         self.other_parent_set = Some(other_parent);
       
   260     }
   157     }
   261 
   158 
   262     /// Both of these setters and their uses appear to be the simplest way to
   159     /// Both of these setters and their uses appear to be the simplest way to
   263     /// emulate a Python lazy property, but it is ugly and unidiomatic.
   160     /// emulate a Python lazy property, but it is ugly and unidiomatic.
   264     /// TODO One day, rewriting this struct using the typestate might be a
   161     /// TODO One day, rewriting this struct using the typestate might be a
   324 
   221 
   325     pub fn pack(
   222     pub fn pack(
   326         &mut self,
   223         &mut self,
   327         parents: DirstateParents,
   224         parents: DirstateParents,
   328         now: Timestamp,
   225         now: Timestamp,
   329     ) -> Result<Vec<u8>, DirstateError> {
   226     ) -> Result<Vec<u8>, HgError> {
   330         let packed =
   227         pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)
   331             pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
       
   332 
       
   333         self.set_non_normal_other_parent_entries(true);
       
   334         Ok(packed)
       
   335     }
   228     }
   336 }
   229 }
   337 
   230 
   338 #[cfg(test)]
   231 #[cfg(test)]
   339 mod tests {
   232 mod tests {
   364             DirstateEntry::from_v1_data(EntryState::Normal, 1337, 1337, 1337),
   257             DirstateEntry::from_v1_data(EntryState::Normal, 1337, 1337, 1337),
   365         )
   258         )
   366         .unwrap();
   259         .unwrap();
   367 
   260 
   368         assert_eq!(1, map.len());
   261         assert_eq!(1, map.len());
   369         assert_eq!(0, map.get_non_normal_other_parent_entries().0.len());
   262     }
   370         assert_eq!(0, map.get_non_normal_other_parent_entries().1.len());
   263 }
   371     }
       
   372 
       
   373     #[test]
       
   374     fn test_non_normal_other_parent_entries() {
       
   375         let mut map: DirstateMap = [
       
   376             (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
       
   377             (b"f2", (EntryState::Normal, 1337, 1337, -1)),
       
   378             (b"f3", (EntryState::Normal, 1337, 1337, 1337)),
       
   379             (b"f4", (EntryState::Normal, 1337, -2, 1337)),
       
   380             (b"f5", (EntryState::Added, 1337, 1337, 1337)),
       
   381             (b"f6", (EntryState::Added, 1337, 1337, -1)),
       
   382             (b"f7", (EntryState::Merged, 1337, 1337, -1)),
       
   383             (b"f8", (EntryState::Merged, 1337, 1337, 1337)),
       
   384             (b"f9", (EntryState::Merged, 1337, -2, 1337)),
       
   385             (b"fa", (EntryState::Added, 1337, -2, 1337)),
       
   386             (b"fb", (EntryState::Removed, 1337, -2, 1337)),
       
   387         ]
       
   388         .iter()
       
   389         .map(|(fname, (state, mode, size, mtime))| {
       
   390             (
       
   391                 HgPathBuf::from_bytes(fname.as_ref()),
       
   392                 DirstateEntry::from_v1_data(*state, *mode, *size, *mtime),
       
   393             )
       
   394         })
       
   395         .collect();
       
   396 
       
   397         let mut non_normal = [
       
   398             b"f1", b"f2", b"f4", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa",
       
   399             b"fb",
       
   400         ]
       
   401         .iter()
       
   402         .map(|x| HgPathBuf::from_bytes(x.as_ref()))
       
   403         .collect();
       
   404 
       
   405         let mut other_parent = HashSet::new();
       
   406         other_parent.insert(HgPathBuf::from_bytes(b"f4"));
       
   407         let entries = map.get_non_normal_other_parent_entries();
       
   408 
       
   409         assert_eq!(
       
   410             (&mut non_normal, &mut other_parent),
       
   411             (entries.0, entries.1)
       
   412         );
       
   413     }
       
   414 }