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}