rust/hg-core/src/dirstate_tree/dirstate_map.rs
changeset 47348 a4de570e61fa
parent 47347 73ddcedeaadf
child 47349 7138c863d0a1
equal deleted inserted replaced
47347:73ddcedeaadf 47348:a4de570e61fa
   293             }
   293             }
   294             NodeRef::OnDisk(node) => node.copy_source(on_disk),
   294             NodeRef::OnDisk(node) => node.copy_source(on_disk),
   295         }
   295         }
   296     }
   296     }
   297 
   297 
   298     pub(super) fn has_entry(&self) -> bool {
       
   299         match self {
       
   300             NodeRef::InMemory(_path, node) => node.entry.is_some(),
       
   301             NodeRef::OnDisk(node) => node.has_entry(),
       
   302         }
       
   303     }
       
   304 
       
   305     pub(super) fn entry(
   298     pub(super) fn entry(
   306         &self,
   299         &self,
   307     ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> {
   300     ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> {
   308         match self {
   301         match self {
   309             NodeRef::InMemory(_path, node) => Ok(node.entry),
   302             NodeRef::InMemory(_path, node) => {
       
   303                 Ok(node.data.as_entry().copied())
       
   304             }
   310             NodeRef::OnDisk(node) => node.entry(),
   305             NodeRef::OnDisk(node) => node.entry(),
   311         }
   306         }
   312     }
   307     }
   313 
   308 
   314     pub(super) fn state(
   309     pub(super) fn state(
   315         &self,
   310         &self,
   316     ) -> Result<Option<EntryState>, DirstateV2ParseError> {
   311     ) -> Result<Option<EntryState>, DirstateV2ParseError> {
   317         match self {
   312         match self {
   318             NodeRef::InMemory(_path, node) => {
   313             NodeRef::InMemory(_path, node) => {
   319                 Ok(node.entry.as_ref().map(|entry| entry.state))
   314                 Ok(node.data.as_entry().map(|entry| entry.state))
   320             }
   315             }
   321             NodeRef::OnDisk(node) => node.state(),
   316             NodeRef::OnDisk(node) => node.state(),
   322         }
   317         }
   323     }
   318     }
   324 
   319 
   331 }
   326 }
   332 
   327 
   333 /// Represents a file or a directory
   328 /// Represents a file or a directory
   334 #[derive(Default)]
   329 #[derive(Default)]
   335 pub(super) struct Node<'on_disk> {
   330 pub(super) struct Node<'on_disk> {
   336     /// `None` for directories
   331     pub(super) data: NodeData,
   337     pub(super) entry: Option<DirstateEntry>,
       
   338 
   332 
   339     pub(super) copy_source: Option<Cow<'on_disk, HgPath>>,
   333     pub(super) copy_source: Option<Cow<'on_disk, HgPath>>,
   340 
   334 
   341     pub(super) children: ChildNodes<'on_disk>,
   335     pub(super) children: ChildNodes<'on_disk>,
   342 
   336 
   343     /// How many (non-inclusive) descendants of this node are tracked files
   337     /// How many (non-inclusive) descendants of this node are tracked files
   344     pub(super) tracked_descendants_count: u32,
   338     pub(super) tracked_descendants_count: u32,
       
   339 }
       
   340 
       
   341 pub(super) enum NodeData {
       
   342     Entry(DirstateEntry),
       
   343     CachedDirectory { mtime: on_disk::Timestamp },
       
   344     None,
       
   345 }
       
   346 
       
   347 impl Default for NodeData {
       
   348     fn default() -> Self {
       
   349         NodeData::None
       
   350     }
       
   351 }
       
   352 
       
   353 impl NodeData {
       
   354     fn has_entry(&self) -> bool {
       
   355         match self {
       
   356             NodeData::Entry(_) => true,
       
   357             _ => false,
       
   358         }
       
   359     }
       
   360 
       
   361     fn as_entry(&self) -> Option<&DirstateEntry> {
       
   362         match self {
       
   363             NodeData::Entry(entry) => Some(entry),
       
   364             _ => None,
       
   365         }
       
   366     }
   345 }
   367 }
   346 
   368 
   347 impl<'on_disk> DirstateMap<'on_disk> {
   369 impl<'on_disk> DirstateMap<'on_disk> {
   348     pub(super) fn empty(on_disk: &'on_disk [u8]) -> Self {
   370     pub(super) fn empty(on_disk: &'on_disk [u8]) -> Self {
   349         Self {
   371         Self {
   384                             ancestor.tracked_descendants_count += 1
   406                             ancestor.tracked_descendants_count += 1
   385                         }
   407                         }
   386                     },
   408                     },
   387                 )?;
   409                 )?;
   388                 assert!(
   410                 assert!(
   389                     node.entry.is_none(),
   411                     !node.data.has_entry(),
   390                     "duplicate dirstate entry in read"
   412                     "duplicate dirstate entry in read"
   391                 );
   413                 );
   392                 assert!(
   414                 assert!(
   393                     node.copy_source.is_none(),
   415                     node.copy_source.is_none(),
   394                     "duplicate dirstate entry in read"
   416                     "duplicate dirstate entry in read"
   395                 );
   417                 );
   396                 node.entry = Some(*entry);
   418                 node.data = NodeData::Entry(*entry);
   397                 node.copy_source = copy_source.map(Cow::Borrowed);
   419                 node.copy_source = copy_source.map(Cow::Borrowed);
   398                 map.nodes_with_entry_count += 1;
   420                 map.nodes_with_entry_count += 1;
   399                 if copy_source.is_some() {
   421                 if copy_source.is_some() {
   400                     map.nodes_with_copy_source_count += 1
   422                     map.nodes_with_copy_source_count += 1
   401                 }
   423                 }
   517                     -1 => ancestor.tracked_descendants_count -= 1,
   539                     -1 => ancestor.tracked_descendants_count -= 1,
   518                     _ => {}
   540                     _ => {}
   519                 }
   541                 }
   520             },
   542             },
   521         )?;
   543         )?;
   522         if node.entry.is_none() {
   544         if !node.data.has_entry() {
   523             self.nodes_with_entry_count += 1
   545             self.nodes_with_entry_count += 1
   524         }
   546         }
   525         node.entry = Some(new_entry);
   547         node.data = NodeData::Entry(new_entry);
   526         Ok(())
   548         Ok(())
   527     }
   549     }
   528 
   550 
   529     fn iter_nodes<'tree>(
   551     fn iter_nodes<'tree>(
   530         &'tree self,
   552         &'tree self,
   585             if let Some(node) = Self::get_node_mut(
   607             if let Some(node) = Self::get_node_mut(
   586                 self.on_disk,
   608                 self.on_disk,
   587                 &mut self.root,
   609                 &mut self.root,
   588                 path.as_ref(),
   610                 path.as_ref(),
   589             )? {
   611             )? {
   590                 if let Some(entry) = node.entry.as_mut() {
   612                 if let NodeData::Entry(entry) = &mut node.data {
   591                     entry.clear_mtime();
   613                     entry.clear_mtime();
   592                 }
   614                 }
   593             }
   615             }
   594         }
   616         }
   595         Ok(())
   617         Ok(())
   701                     }
   723                     }
   702                 } else {
   724                 } else {
   703                     return Ok(None);
   725                     return Ok(None);
   704                 }
   726                 }
   705             } else {
   727             } else {
       
   728                 let had_entry = node.data.has_entry();
       
   729                 if had_entry {
       
   730                     node.data = NodeData::None
       
   731                 }
   706                 dropped = Dropped {
   732                 dropped = Dropped {
   707                     was_tracked: node
   733                     was_tracked: node
   708                         .entry
   734                         .data
   709                         .as_ref()
   735                         .as_entry()
   710                         .map_or(false, |entry| entry.state.is_tracked()),
   736                         .map_or(false, |entry| entry.state.is_tracked()),
   711                     had_entry: node.entry.take().is_some(),
   737                     had_entry,
   712                     had_copy_source: node.copy_source.take().is_some(),
   738                     had_copy_source: node.copy_source.take().is_some(),
   713                 };
   739                 };
   714             }
   740             }
   715             // After recursion, for both leaf (rest_of_path is None) nodes and
   741             // After recursion, for both leaf (rest_of_path is None) nodes and
   716             // parent nodes, remove a node if it just became empty.
   742             // parent nodes, remove a node if it just became empty.
   717             if node.entry.is_none()
   743             if !node.data.has_entry()
   718                 && node.copy_source.is_none()
   744                 && node.copy_source.is_none()
   719                 && node.children.is_empty()
   745                 && node.children.is_empty()
   720             {
   746             {
   721                 nodes.make_mut(on_disk)?.remove(first_path_component);
   747                 nodes.make_mut(on_disk)?.remove(first_path_component);
   722             }
   748             }
   744     ) -> Result<(), DirstateV2ParseError> {
   770     ) -> Result<(), DirstateV2ParseError> {
   745         for filename in filenames {
   771         for filename in filenames {
   746             if let Some(node) =
   772             if let Some(node) =
   747                 Self::get_node_mut(self.on_disk, &mut self.root, &filename)?
   773                 Self::get_node_mut(self.on_disk, &mut self.root, &filename)?
   748             {
   774             {
   749                 if let Some(entry) = node.entry.as_mut() {
   775                 if let NodeData::Entry(entry) = &mut node.data {
   750                     entry.clear_ambiguous_mtime(now);
   776                     entry.clear_ambiguous_mtime(now);
   751                 }
   777                 }
   752             }
   778             }
   753         }
   779         }
   754         Ok(())
   780         Ok(())
   813         directory: &HgPath,
   839         directory: &HgPath,
   814     ) -> Result<bool, DirstateError> {
   840     ) -> Result<bool, DirstateError> {
   815         if let Some(node) = self.get_node(directory)? {
   841         if let Some(node) = self.get_node(directory)? {
   816             // A node without a `DirstateEntry` was created to hold child
   842             // A node without a `DirstateEntry` was created to hold child
   817             // nodes, and is therefore a directory.
   843             // nodes, and is therefore a directory.
   818             Ok(!node.has_entry() && node.tracked_descendants_count() > 0)
   844             let state = node.state()?;
       
   845             Ok(state.is_none() && node.tracked_descendants_count() > 0)
   819         } else {
   846         } else {
   820             Ok(false)
   847             Ok(false)
   821         }
   848         }
   822     }
   849     }
   823 
   850 
   824     fn has_dir(&mut self, directory: &HgPath) -> Result<bool, DirstateError> {
   851     fn has_dir(&mut self, directory: &HgPath) -> Result<bool, DirstateError> {
   825         if let Some(node) = self.get_node(directory)? {
   852         if let Some(node) = self.get_node(directory)? {
   826             // A node without a `DirstateEntry` was created to hold child
   853             // A node without a `DirstateEntry` was created to hold child
   827             // nodes, and is therefore a directory.
   854             // nodes, and is therefore a directory.
   828             Ok(!node.has_entry())
   855             Ok(node.state()?.is_none())
   829         } else {
   856         } else {
   830             Ok(false)
   857             Ok(false)
   831         }
   858         }
   832     }
   859     }
   833 
   860