git_index/entry/flags.rs
1use bitflags::bitflags;
2
3use crate::entry::Stage;
4
5bitflags! {
6 /// In-memory flags
7 pub struct Flags: u32 {
8 /// The mask to apply to obtain the stage number of an entry.
9 const STAGE_MASK = 0x3000;
10 /// If set, additional bits need to be written to storage.
11 const EXTENDED = 0x4000;
12 // TODO: could we use the pathlen ourselves to save 8 bytes? And how to handle longer paths than that? 0 as sentinel maybe?
13 /// The mask to obtain the length of the path associated with this entry.
14 const PATH_LEN = 0x0fff;
15 /// If set, the entry be assumed to match with the version on the working tree, as a way to avoid `lstat()` checks.
16 const ASSUME_VALID = 1 << 15;
17 /// Indicates that an entry needs to be updated as it's in-memory representation doesn't match what's on disk.
18 const UPDATE = 1 << 16;
19 /// Indicates an entry should be removed - this typically happens during writing, by simply skipping over them.
20 const REMOVE = 1 << 17;
21 /// Indicates that an entry is known to be uptodate.
22 const UPTODATE = 1 << 18;
23 /// Only temporarily used by unpack_trees() (in C)
24 const ADDED = 1 << 19;
25
26 /// Whether an up-to-date object hash exists for the entry.
27 const HASHED = 1 << 20;
28 /// Set if the filesystem monitor is valid.
29 const FSMONITOR_VALID = 1 << 21;
30 /// Remove in work directory
31 const WORKTREE_REMOVE = 1 << 22;
32 /// Set to indicate the entry exists in multiple stages at once due to conflicts.
33 const CONFLICTED = 1 << 23;
34
35 /// Indicates that the entry was already turned into a tree.
36 const UNPACKED = 1 << 24;
37 /// Only temporarily used by unpack_trees() (in C)
38 const NEW_SKIP_WORKTREE = 1 << 25;
39
40 /// temporarily mark paths matched by a path spec
41 const PATHSPEC_MATCHED = 1 << 26;
42
43 /// When the index is split, this indicates the entry is up-to-date in the shared portion of the index.
44 const UPDATE_IN_BASE = 1 << 27;
45 /// Indicates the entry name is present in the base/shared index, and thus doesn't have to be stored in this one.
46 const STRIP_NAME = 1 << 28;
47
48 ///
49 /// stored at rest, see at_rest::FlagsExtended
50 const INTENT_TO_ADD = 1 << 29;
51 /// Stored at rest
52 const SKIP_WORKTREE = 1 << 30;
53
54 /// For future extension
55 const EXTENDED_2 = 1 << 31;
56 }
57}
58
59impl Flags {
60 /// Return the stage as extracted from the bits of this instance.
61 pub fn stage(&self) -> Stage {
62 (*self & Flags::STAGE_MASK).bits >> 12
63 }
64
65 /// Transform ourselves to a storage representation to keep all flags which are to be persisted,
66 /// skipping all extended flags. Note that the caller has to check for the `EXTENDED` bit to be present
67 /// and write extended flags as well if so.
68 pub fn to_storage(mut self) -> at_rest::Flags {
69 at_rest::Flags::from_bits(
70 {
71 self.remove(Self::PATH_LEN);
72 self
73 }
74 .bits() as u16,
75 )
76 .unwrap()
77 }
78}
79
80pub(crate) mod at_rest {
81 use bitflags::bitflags;
82
83 bitflags! {
84 /// Flags how they are serialized to a storage location
85 pub struct Flags: u16 {
86 /// A portion of a the flags that encodes the length of the path that follows.
87 const PATH_LEN = 0x0fff;
88 const STAGE_MASK = 0x3000;
89 /// If set, there is more extended flags past this one
90 const EXTENDED = 0x4000;
91 /// If set, the entry be assumed to match with the version on the working tree, as a way to avoid `lstat()` checks.
92 const ASSUME_VALID = 0x8000;
93 }
94 }
95
96 impl Flags {
97 pub fn to_memory(self) -> super::Flags {
98 super::Flags::from_bits(self.bits as u32).expect("PATHLEN is part of memory representation")
99 }
100 }
101
102 bitflags! {
103 /// Extended flags - add flags for serialization here and offset them down to u16.
104 pub struct FlagsExtended: u16 {
105 const INTENT_TO_ADD = 1 << (29 - 16);
106 const SKIP_WORKTREE = 1 << (30 - 16);
107 }
108 }
109
110 impl FlagsExtended {
111 pub fn from_flags(flags: super::Flags) -> Self {
112 Self::from_bits(((flags & (super::Flags::INTENT_TO_ADD | super::Flags::SKIP_WORKTREE)).bits >> 16) as u16)
113 .expect("valid")
114 }
115 pub fn to_flags(self) -> Option<super::Flags> {
116 super::Flags::from_bits((self.bits as u32) << 16)
117 }
118 }
119
120 #[cfg(test)]
121 mod tests {
122 use super::*;
123
124 #[test]
125 fn flags_from_bits_with_conflict() {
126 let input = 0b1110_0010_1000_1011;
127 assert_eq!(Flags::from_bits(input).unwrap().bits, input);
128 }
129 }
130}