diff options
Diffstat (limited to 'vendor/gix-object/src/tree/mod.rs')
-rw-r--r-- | vendor/gix-object/src/tree/mod.rs | 138 |
1 files changed, 111 insertions, 27 deletions
diff --git a/vendor/gix-object/src/tree/mod.rs b/vendor/gix-object/src/tree/mod.rs index 89e4def48..7375f1c69 100644 --- a/vendor/gix-object/src/tree/mod.rs +++ b/vendor/gix-object/src/tree/mod.rs @@ -13,9 +13,17 @@ pub mod write; /// /// Used in [`mutable::Entry`][crate::tree::Entry] and [`EntryRef`]. #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct EntryMode(u16); + +/// A discretized version of ideal and valid values for entry modes. +/// +/// Note that even though it can represent every valid [mode](EntryMode), it might +/// loose information due to that as well. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash)] #[repr(u16)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum EntryMode { +pub enum EntryKind { /// A tree, or directory Tree = 0o040000u16, /// A file that is not executable @@ -28,31 +36,101 @@ pub enum EntryMode { Commit = 0o160000, } +impl From<EntryKind> for EntryMode { + fn from(value: EntryKind) -> Self { + EntryMode(value as u16) + } +} + +impl From<EntryMode> for EntryKind { + fn from(value: EntryMode) -> Self { + value.kind() + } +} + +/// Serialization +impl EntryKind { + /// Return the representation as used in the git internal format. + pub fn as_octal_str(&self) -> &'static BStr { + use EntryKind::*; + let bytes: &[u8] = match self { + Tree => b"40000", + Blob => b"100644", + BlobExecutable => b"100755", + Link => b"120000", + Commit => b"160000", + }; + bytes.into() + } +} + +impl std::ops::Deref for EntryMode { + type Target = u16; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + 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 + } + } + } + } + /// Return true if this entry mode represents a Tree/directory - pub fn is_tree(&self) -> bool { - *self == EntryMode::Tree + pub const fn is_tree(&self) -> bool { + self.0 == 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 + } + + /// Return true if this entry mode represents a symbolic link + pub const fn is_link(&self) -> bool { + self.0 == EntryKind::Link as u16 } /// Return true if this entry mode represents anything BUT Tree/directory - pub fn is_no_tree(&self) -> bool { - *self != EntryMode::Tree + pub const fn is_no_tree(&self) -> bool { + self.0 != EntryKind::Tree as u16 } /// Return true if the entry is any kind of blob. - pub fn is_blob(&self) -> bool { - matches!(self, EntryMode::Blob | EntryMode::BlobExecutable) + pub const fn is_blob(&self) -> bool { + matches!(self.kind(), EntryKind::Blob | EntryKind::BlobExecutable) + } + + /// Return true if the entry is an executable blob. + pub const fn is_executable(&self) -> bool { + matches!(self.kind(), EntryKind::BlobExecutable) } /// Return true if the entry is any kind of blob or symlink. - pub fn is_blob_or_symlink(&self) -> bool { - matches!(self, EntryMode::Blob | EntryMode::BlobExecutable | EntryMode::Link) + pub const fn is_blob_or_symlink(&self) -> bool { + matches!( + self.kind(), + EntryKind::Blob | EntryKind::BlobExecutable | EntryKind::Link + ) } /// Represent the mode as descriptive string. - pub fn as_str(&self) -> &'static str { - use EntryMode::*; - match self { + pub const fn as_str(&self) -> &'static str { + use EntryKind::*; + match self.kind() { Tree => "tree", Blob => "blob", BlobExecutable => "exe", @@ -60,6 +138,27 @@ impl EntryMode { Commit => "commit", } } + + /// Return the representation as used in the git internal format, which is octal and written + /// to the `backing` buffer. The respective sub-slice that was written to is returned. + pub fn as_bytes<'a>(&self, backing: &'a mut [u8; 6]) -> &'a BStr { + if self.0 == 0 { + std::slice::from_ref(&b'0') + } else { + let mut nb = 0; + let mut n = self.0; + while n > 0 { + let remainder = (n % 8) as u8; + backing[nb] = b'0' + remainder; + n /= 8; + nb += 1; + } + let res = &mut backing[..nb]; + res.reverse(); + res + } + .into() + } } /// An element of a [`TreeRef`][crate::TreeRef::entries]. @@ -124,18 +223,3 @@ impl Ord for Entry { }) } } - -/// Serialization -impl EntryMode { - /// Return the representation as used in the git internal format. - pub fn as_bytes(&self) -> &'static [u8] { - use EntryMode::*; - match self { - Tree => b"40000", - Blob => b"100644", - BlobExecutable => b"100755", - Link => b"120000", - Commit => b"160000", - } - } -} |