rust/hg-core/src/dirstate/entry.rs
changeset 48271 269ff8978086
parent 48270 84f6b0c41b90
child 48273 68bb472aee9c
equal deleted inserted replaced
48270:84f6b0c41b90 48271:269ff8978086
    12     Added,
    12     Added,
    13     Removed,
    13     Removed,
    14     Merged,
    14     Merged,
    15 }
    15 }
    16 
    16 
    17 /// The C implementation uses all signed types. This will be an issue
    17 /// `size` and `mtime.seconds` are truncated to 31 bits.
    18 /// either when 4GB+ source files are commonplace or in 2038, whichever
    18 ///
    19 /// comes first.
    19 /// TODO: double-check status algorithm correctness for files
    20 #[derive(Debug, PartialEq, Copy, Clone)]
    20 /// larger than 2 GiB or modified after 2038.
       
    21 #[derive(Debug, Copy, Clone)]
    21 pub struct DirstateEntry {
    22 pub struct DirstateEntry {
    22     pub(crate) flags: Flags,
    23     pub(crate) flags: Flags,
    23     mode_size: Option<(u32, u32)>,
    24     mode_size: Option<(u32, u32)>,
    24     mtime: Option<u32>,
    25     mtime: Option<TruncatedTimestamp>,
    25 }
    26 }
    26 
    27 
    27 bitflags! {
    28 bitflags! {
    28     pub(crate) struct Flags: u8 {
    29     pub(crate) struct Flags: u8 {
    29         const WDIR_TRACKED = 1 << 0;
    30         const WDIR_TRACKED = 1 << 0;
    35         const FALLBACK_SYMLINK = 1 << 6;
    36         const FALLBACK_SYMLINK = 1 << 6;
    36     }
    37     }
    37 }
    38 }
    38 
    39 
    39 /// A Unix timestamp with nanoseconds precision
    40 /// A Unix timestamp with nanoseconds precision
    40 #[derive(Copy, Clone)]
    41 #[derive(Debug, Copy, Clone)]
    41 pub struct TruncatedTimestamp {
    42 pub struct TruncatedTimestamp {
    42     truncated_seconds: u32,
    43     truncated_seconds: u32,
    43     /// Always in the `0 .. 1_000_000_000` range.
    44     /// Always in the `0 .. 1_000_000_000` range.
    44     nanoseconds: u32,
    45     nanoseconds: u32,
    45 }
    46 }
    86         }
    87         }
    87         #[cfg(not(unix))]
    88         #[cfg(not(unix))]
    88         {
    89         {
    89             metadata.modified().map(Self::from)
    90             metadata.modified().map(Self::from)
    90         }
    91         }
       
    92     }
       
    93 
       
    94     pub fn to_integer_second(mut self) -> Self {
       
    95         self.nanoseconds = 0;
       
    96         self
    91     }
    97     }
    92 
    98 
    93     /// The lower 31 bits of the number of seconds since the epoch.
    99     /// The lower 31 bits of the number of seconds since the epoch.
    94     pub fn truncated_seconds(&self) -> u32 {
   100     pub fn truncated_seconds(&self) -> u32 {
    95         self.truncated_seconds
   101         self.truncated_seconds
   180     pub fn from_v2_data(
   186     pub fn from_v2_data(
   181         wdir_tracked: bool,
   187         wdir_tracked: bool,
   182         p1_tracked: bool,
   188         p1_tracked: bool,
   183         p2_info: bool,
   189         p2_info: bool,
   184         mode_size: Option<(u32, u32)>,
   190         mode_size: Option<(u32, u32)>,
   185         mtime: Option<u32>,
   191         mtime: Option<TruncatedTimestamp>,
   186         fallback_exec: Option<bool>,
   192         fallback_exec: Option<bool>,
   187         fallback_symlink: Option<bool>,
   193         fallback_symlink: Option<bool>,
   188     ) -> Self {
   194     ) -> Self {
   189         if let Some((mode, size)) = mode_size {
   195         if let Some((mode, size)) = mode_size {
   190             // TODO: return an error for out of range values?
   196             // TODO: return an error for out of range values?
   191             assert!(mode & !RANGE_MASK_31BIT == 0);
   197             assert!(mode & !RANGE_MASK_31BIT == 0);
   192             assert!(size & !RANGE_MASK_31BIT == 0);
   198             assert!(size & !RANGE_MASK_31BIT == 0);
   193         }
       
   194         if let Some(mtime) = mtime {
       
   195             assert!(mtime & !RANGE_MASK_31BIT == 0);
       
   196         }
   199         }
   197         let mut flags = Flags::empty();
   200         let mut flags = Flags::empty();
   198         flags.set(Flags::WDIR_TRACKED, wdir_tracked);
   201         flags.set(Flags::WDIR_TRACKED, wdir_tracked);
   199         flags.set(Flags::P1_TRACKED, p1_tracked);
   202         flags.set(Flags::P1_TRACKED, p1_tracked);
   200         flags.set(Flags::P2_INFO, p2_info);
   203         flags.set(Flags::P2_INFO, p2_info);
   250                 } else {
   253                 } else {
   251                     // TODO: return an error for negative values?
   254                     // TODO: return an error for negative values?
   252                     let mode = u32::try_from(mode).unwrap();
   255                     let mode = u32::try_from(mode).unwrap();
   253                     let size = u32::try_from(size).unwrap();
   256                     let size = u32::try_from(size).unwrap();
   254                     let mtime = u32::try_from(mtime).unwrap();
   257                     let mtime = u32::try_from(mtime).unwrap();
       
   258                     let mtime =
       
   259                         TruncatedTimestamp::from_already_truncated(mtime, 0)
       
   260                             .unwrap();
   255                     Self {
   261                     Self {
   256                         flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED,
   262                         flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED,
   257                         mode_size: Some((mode, size)),
   263                         mode_size: Some((mode, size)),
   258                         mtime: Some(mtime),
   264                         mtime: Some(mtime),
   259                     }
   265                     }
   342     ) -> (
   348     ) -> (
   343         bool,
   349         bool,
   344         bool,
   350         bool,
   345         bool,
   351         bool,
   346         Option<(u32, u32)>,
   352         Option<(u32, u32)>,
   347         Option<u32>,
   353         Option<TruncatedTimestamp>,
   348         Option<bool>,
   354         Option<bool>,
   349         Option<bool>,
   355         Option<bool>,
   350     ) {
   356     ) {
   351         if !self.any_tracked() {
   357         if !self.any_tracked() {
   352             // TODO: return an Option instead?
   358             // TODO: return an Option instead?
   427         } else if self.flags.contains(Flags::P2_INFO) {
   433         } else if self.flags.contains(Flags::P2_INFO) {
   428             MTIME_UNSET
   434             MTIME_UNSET
   429         } else if !self.flags.contains(Flags::P1_TRACKED) {
   435         } else if !self.flags.contains(Flags::P1_TRACKED) {
   430             MTIME_UNSET
   436             MTIME_UNSET
   431         } else if let Some(mtime) = self.mtime {
   437         } else if let Some(mtime) = self.mtime {
   432             i32::try_from(mtime).unwrap()
   438             i32::try_from(mtime.truncated_seconds()).unwrap()
   433         } else {
   439         } else {
   434             MTIME_UNSET
   440             MTIME_UNSET
   435         }
   441         }
   436     }
   442     }
   437 
   443 
   499                 }
   505                 }
   500             }
   506             }
   501         }
   507         }
   502     }
   508     }
   503 
   509 
       
   510     pub fn truncated_mtime(&self) -> Option<TruncatedTimestamp> {
       
   511         self.mtime
       
   512     }
       
   513 
   504     pub fn drop_merge_data(&mut self) {
   514     pub fn drop_merge_data(&mut self) {
   505         if self.flags.contains(Flags::P2_INFO) {
   515         if self.flags.contains(Flags::P2_INFO) {
   506             self.flags.remove(Flags::P2_INFO);
   516             self.flags.remove(Flags::P2_INFO);
   507             self.mode_size = None;
   517             self.mode_size = None;
   508             self.mtime = None;
   518             self.mtime = None;
   511 
   521 
   512     pub fn set_possibly_dirty(&mut self) {
   522     pub fn set_possibly_dirty(&mut self) {
   513         self.mtime = None
   523         self.mtime = None
   514     }
   524     }
   515 
   525 
   516     pub fn set_clean(&mut self, mode: u32, size: u32, mtime: u32) {
   526     pub fn set_clean(
       
   527         &mut self,
       
   528         mode: u32,
       
   529         size: u32,
       
   530         mtime: TruncatedTimestamp,
       
   531     ) {
   517         let size = size & RANGE_MASK_31BIT;
   532         let size = size & RANGE_MASK_31BIT;
   518         let mtime = mtime & RANGE_MASK_31BIT;
       
   519         self.flags.insert(Flags::WDIR_TRACKED | Flags::P1_TRACKED);
   533         self.flags.insert(Flags::WDIR_TRACKED | Flags::P1_TRACKED);
   520         self.mode_size = Some((mode, size));
   534         self.mode_size = Some((mode, size));
   521         self.mtime = Some(mtime);
   535         self.mtime = Some(mtime);
   522     }
   536     }
   523 
   537 
   575     pub fn debug_tuple(&self) -> (u8, i32, i32, i32) {
   589     pub fn debug_tuple(&self) -> (u8, i32, i32, i32) {
   576         (self.state().into(), self.mode(), self.size(), self.mtime())
   590         (self.state().into(), self.mode(), self.size(), self.mtime())
   577     }
   591     }
   578 
   592 
   579     /// True if the stored mtime would be ambiguous with the current time
   593     /// True if the stored mtime would be ambiguous with the current time
   580     pub fn need_delay(&self, now: i32) -> bool {
   594     pub fn need_delay(&self, now: TruncatedTimestamp) -> bool {
   581         self.state() == EntryState::Normal && self.mtime() == now
   595         if let Some(mtime) = self.mtime {
       
   596             self.state() == EntryState::Normal
       
   597                 && mtime.truncated_seconds() == now.truncated_seconds()
       
   598         } else {
       
   599             false
       
   600         }
   582     }
   601     }
   583 }
   602 }
   584 
   603 
   585 impl EntryState {
   604 impl EntryState {
   586     pub fn is_tracked(self) -> bool {
   605     pub fn is_tracked(self) -> bool {