| use bitflags::bitflags; |
| |
| use crate::entry::Stage; |
| |
| bitflags! { |
| /// In-memory flags. |
| /// |
| /// Notably, not all of these will be persisted but can be used to aid all kinds of operations. |
| #[derive(Debug, Clone, Copy, Eq, PartialEq)] |
| pub struct Flags: u32 { |
| // 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, up to 4095 characters without extension. |
| const PATH_LEN = 0x0fff; |
| /// The mask to apply to obtain the stage number of an entry, encoding three value: 0 = base, 1 = ours, 2 = theirs. |
| const STAGE_MASK = 1<<12 | 1<<13; |
| /// If set, additional bits need to be written to storage. |
| const EXTENDED = 1<<14; |
| /// 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 up-to-date. |
| 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; |
| |
| /// Created with `git add --intent-to-add` to mark empty entries that have their counter-part in the worktree, but not |
| /// yet in the object database. |
| 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_retain( |
| { |
| self.remove(Self::PATH_LEN); |
| self |
| } |
| .bits() as u16, |
| ) |
| } |
| } |
| |
| pub(crate) mod at_rest { |
| use bitflags::bitflags; |
| |
| bitflags! { |
| /// Flags how they are serialized to a storage location |
| #[derive(Copy, Clone, Debug)] |
| 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_retain(self.bits() as u32) |
| } |
| } |
| |
| bitflags! { |
| /// Extended flags - add flags for serialization here and offset them down to u16. |
| #[derive(Copy, Clone, Debug, PartialEq)] |
| 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_retain( |
| ((flags & (super::Flags::INTENT_TO_ADD | super::Flags::SKIP_WORKTREE)).bits() >> 16) as u16, |
| ) |
| } |
| 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_extended_conversion() { |
| assert_eq!( |
| FlagsExtended::all().to_flags(), |
| Some(super::super::Flags::INTENT_TO_ADD | super::super::Flags::SKIP_WORKTREE) |
| ); |
| assert_eq!( |
| FlagsExtended::from_flags(super::super::Flags::all()), |
| FlagsExtended::all() |
| ); |
| } |
| |
| #[test] |
| fn flags_from_bits_with_conflict() { |
| let input = 0b1110_0010_1000_1011; |
| assert_eq!(Flags::from_bits_retain(input).bits(), input); |
| } |
| } |
| } |