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 } |
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 } |
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 { |