summaryrefslogtreecommitdiffstats
path: root/vendor/gix-index/src/entry/flags.rs
blob: ec00a78db26dc64a5311ecafd200748e7adee061 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use bitflags::bitflags;

use crate::entry::Stage;

bitflags! {
    /// In-memory flags
    pub struct Flags: u32 {
        /// The mask to apply to obtain the stage number of an entry.
        const STAGE_MASK = 0x3000;
        /// If set, additional bits need to be written to storage.
        const EXTENDED = 0x4000;
        // TODO: could we use the pathlen ourselves to save 8 bytes? And how to handle longer paths than that? 0 as sentinel maybe?
        /// The mask to obtain the length of the path associated with this entry.
        const PATH_LEN = 0x0fff;
        /// If set, the entry be assumed to match with the version on the working tree, as a way to avoid `lstat()`  checks.
        const ASSUME_VALID = 1 << 15;
        /// Indicates that an entry needs to be updated as it's in-memory representation doesn't match what's on disk.
        const UPDATE = 1 << 16;
        /// Indicates an entry should be removed - this typically happens during writing, by simply skipping over them.
        const REMOVE = 1 << 17;
        /// Indicates that an entry is known to be uptodate.
        const UPTODATE = 1 << 18;
        /// Only temporarily used by unpack_trees() (in C)
        const ADDED = 1 << 19;

        /// Whether an up-to-date object hash exists for the entry.
        const HASHED = 1 << 20;
        /// Set if the filesystem monitor is valid.
        const FSMONITOR_VALID = 1 << 21;
        /// Remove in work directory
        const WORKTREE_REMOVE = 1 << 22;
        /// Set to indicate the entry exists in multiple stages at once due to conflicts.
        const CONFLICTED = 1 << 23;

        /// Indicates that the entry was already turned into a tree.
        const UNPACKED = 1 << 24;
        /// Only temporarily used by unpack_trees() (in C)
        const NEW_SKIP_WORKTREE = 1 << 25;

        /// temporarily mark paths matched by a path spec
        const PATHSPEC_MATCHED = 1 << 26;

        /// When the index is split, this indicates the entry is up-to-date in the shared portion of the index.
        const UPDATE_IN_BASE = 1 << 27;
        /// Indicates the entry name is present in the base/shared index, and thus doesn't have to be stored in this one.
        const STRIP_NAME = 1 << 28;

        ///
        /// stored at rest, see at_rest::FlagsExtended
        const INTENT_TO_ADD = 1 << 29;
        /// Stored at rest
        const SKIP_WORKTREE = 1 << 30;

        /// For future extension
        const EXTENDED_2 = 1 << 31;
    }
}

impl Flags {
    /// Return the stage as extracted from the bits of this instance.
    pub fn stage(&self) -> Stage {
        (*self & Flags::STAGE_MASK).bits >> 12
    }

    /// Transform ourselves to a storage representation to keep all flags which are to be persisted,
    /// skipping all extended flags. Note that the caller has to check for the `EXTENDED` bit to be present
    /// and write extended flags as well if so.
    pub fn to_storage(mut self) -> at_rest::Flags {
        at_rest::Flags::from_bits(
            {
                self.remove(Self::PATH_LEN);
                self
            }
            .bits() as u16,
        )
        .unwrap()
    }
}

pub(crate) mod at_rest {
    use bitflags::bitflags;

    bitflags! {
        /// Flags how they are serialized to a storage location
        pub struct Flags: u16 {
            /// A portion of a the flags that encodes the length of the path that follows.
            const PATH_LEN = 0x0fff;
            const STAGE_MASK = 0x3000;
            /// If set, there is more extended flags past this one
            const EXTENDED = 0x4000;
            /// If set, the entry be assumed to match with the version on the working tree, as a way to avoid `lstat()`  checks.
            const ASSUME_VALID = 0x8000;
        }
    }

    impl Flags {
        pub fn to_memory(self) -> super::Flags {
            super::Flags::from_bits(self.bits as u32).expect("PATHLEN is part of memory representation")
        }
    }

    bitflags! {
        /// Extended flags - add flags for serialization here and offset them down to u16.
        pub struct FlagsExtended: u16 {
            const INTENT_TO_ADD = 1 << (29 - 16);
            const SKIP_WORKTREE = 1 << (30 - 16);
        }
    }

    impl FlagsExtended {
        pub fn from_flags(flags: super::Flags) -> Self {
            Self::from_bits(((flags & (super::Flags::INTENT_TO_ADD | super::Flags::SKIP_WORKTREE)).bits >> 16) as u16)
                .expect("valid")
        }
        pub fn to_flags(self) -> Option<super::Flags> {
            super::Flags::from_bits((self.bits as u32) << 16)
        }
    }

    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn flags_from_bits_with_conflict() {
            let input = 0b1110_0010_1000_1011;
            assert_eq!(Flags::from_bits(input).unwrap().bits, input);
        }
    }
}