Skip to content

Commit

Permalink
Merge branch 'entry-mode-fixes'
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Jan 22, 2024
2 parents eb6aa8f + 82e85fd commit 35d2083
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 16 deletions.
39 changes: 23 additions & 16 deletions gix-object/src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ pub mod write;
/// The mode of items storable in a tree, similar to the file mode on a unix file system.
///
/// Used in [`mutable::Entry`][crate::tree::Entry] and [`EntryRef`].
///
/// Note that even though it can be created from any `u16`, it should be preferable to
/// create it by converting [`EntryKind`] into `EntryMode`.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EntryMode(u16);
pub struct EntryMode(pub u16);

/// A discretized version of ideal and valid values for entry modes.
///
Expand Down Expand Up @@ -72,46 +75,50 @@ impl std::ops::Deref for EntryMode {
}
}

const IFMT: u16 = 0o170000;

impl EntryMode {
/// Discretize the raw mode into an enum with well-known state while dropping unnecessary details.
pub const fn kind(&self) -> EntryKind {
match self.0 {
0o40000 => EntryKind::Tree,
0o120000 => EntryKind::Link,
0o160000 => EntryKind::Commit,
blob_mode => {
if blob_mode & 0o000100 == 0o000100 {
EntryKind::BlobExecutable
} else {
EntryKind::Blob
}
let etype = self.0 & IFMT;
if etype == 0o100000 {
if self.0 & 0o000100 == 0o000100 {
EntryKind::BlobExecutable
} else {
EntryKind::Blob
}
} else if etype == EntryKind::Link as u16 {
EntryKind::Link
} else if etype == EntryKind::Tree as u16 {
EntryKind::Tree
} else {
EntryKind::Commit
}
}

/// Return true if this entry mode represents a Tree/directory
pub const fn is_tree(&self) -> bool {
self.0 == EntryKind::Tree as u16
self.0 & IFMT == EntryKind::Tree as u16
}

/// Return true if this entry mode represents the commit of a submodule.
pub const fn is_commit(&self) -> bool {
self.0 == EntryKind::Commit as u16
self.0 & IFMT == EntryKind::Commit as u16
}

/// Return true if this entry mode represents a symbolic link
pub const fn is_link(&self) -> bool {
self.0 == EntryKind::Link as u16
self.0 & IFMT == EntryKind::Link as u16
}

/// Return true if this entry mode represents anything BUT Tree/directory
pub const fn is_no_tree(&self) -> bool {
self.0 != EntryKind::Tree as u16
self.0 & IFMT != EntryKind::Tree as u16
}

/// Return true if the entry is any kind of blob.
pub const fn is_blob(&self) -> bool {
matches!(self.kind(), EntryKind::Blob | EntryKind::BlobExecutable)
self.0 & IFMT == 0o100000
}

/// Return true if the entry is an executable blob.
Expand Down
36 changes: 36 additions & 0 deletions gix-object/tests/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,42 @@ mod entry_mode {
);
}

#[test]
fn is_methods() {
fn mode(kind: EntryKind) -> EntryMode {
kind.into()
}

assert!(mode(EntryKind::Blob).is_blob());
assert!(EntryMode(0o100645).is_blob());
assert_eq!(EntryMode(0o100645).kind(), EntryKind::Blob);
assert!(!EntryMode(0o100675).is_executable());
assert!(EntryMode(0o100700).is_executable());
assert_eq!(EntryMode(0o100700).kind(), EntryKind::BlobExecutable);
assert!(!mode(EntryKind::Blob).is_link());
assert!(mode(EntryKind::BlobExecutable).is_blob());
assert!(mode(EntryKind::BlobExecutable).is_executable());
assert!(mode(EntryKind::Blob).is_blob_or_symlink());
assert!(mode(EntryKind::BlobExecutable).is_blob_or_symlink());

assert!(!mode(EntryKind::Link).is_blob());
assert!(mode(EntryKind::Link).is_link());
assert!(EntryMode(0o121234).is_link());
assert_eq!(EntryMode(0o121234).kind(), EntryKind::Link);
assert!(mode(EntryKind::Link).is_blob_or_symlink());
assert!(mode(EntryKind::Tree).is_tree());
assert!(EntryMode(0o040101).is_tree());
assert_eq!(EntryMode(0o040101).kind(), EntryKind::Tree);
assert!(mode(EntryKind::Commit).is_commit());
assert!(EntryMode(0o167124).is_commit());
assert_eq!(EntryMode(0o167124).kind(), EntryKind::Commit);
assert_eq!(
EntryMode(0o000000).kind(),
EntryKind::Commit,
"commit is really 'anything else' as `kind()` can't fail"
);
}

#[test]
fn as_bytes() {
let mut buf = Default::default();
Expand Down

0 comments on commit 35d2083

Please sign in to comment.