git_object/tree/
mod.rs

1use std::cmp::Ordering;
2
3use crate::{
4    bstr::{BStr, BString},
5    tree,
6};
7
8mod ref_iter;
9///
10pub mod write;
11
12/// The mode of items storable in a tree, similar to the file mode on a unix file system.
13///
14/// Used in [mutable::Entry][crate::tree::Entry] and [EntryRef].
15#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash)]
16#[repr(u16)]
17#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
18pub enum EntryMode {
19    /// A tree, or directory
20    Tree = 0o040000u16,
21    /// A file that is not executable
22    Blob = 0o100644,
23    /// A file that is executable
24    BlobExecutable = 0o100755,
25    /// A symbolic link
26    Link = 0o120000,
27    /// A commit of a git submodule
28    Commit = 0o160000,
29}
30
31impl EntryMode {
32    /// Return true if this entry mode represents a Tree/directory
33    pub fn is_tree(&self) -> bool {
34        *self == EntryMode::Tree
35    }
36
37    /// Return true if this entry mode represents anything BUT Tree/directory
38    pub fn is_no_tree(&self) -> bool {
39        *self != EntryMode::Tree
40    }
41
42    /// Return true if the entry is any kind of blob.
43    pub fn is_blob(&self) -> bool {
44        matches!(self, EntryMode::Blob | EntryMode::BlobExecutable)
45    }
46
47    /// Represent the mode as descriptive string.
48    pub fn as_str(&self) -> &'static str {
49        use EntryMode::*;
50        match self {
51            Tree => "tree",
52            Blob => "blob",
53            BlobExecutable => "exe",
54            Link => "link",
55            Commit => "commit",
56        }
57    }
58}
59
60/// An element of a [`TreeRef`][crate::TreeRef::entries].
61#[derive(PartialEq, Eq, Debug, Hash, Clone)]
62#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
63pub struct EntryRef<'a> {
64    /// The kind of object to which `oid` is pointing.
65    pub mode: tree::EntryMode,
66    /// The name of the file in the parent tree.
67    pub filename: &'a BStr,
68    /// The id of the object representing the entry.
69    // TODO: figure out how these should be called. id or oid? It's inconsistent around the codebase.
70    // Answer: make it 'id', as in `git2`
71    #[cfg_attr(feature = "serde1", serde(borrow))]
72    pub oid: &'a git_hash::oid,
73}
74
75impl<'a> PartialOrd for EntryRef<'a> {
76    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
77        Some(self.cmp(other))
78    }
79}
80
81impl<'a> Ord for EntryRef<'a> {
82    /// Entries compare by the common portion of the filename. This is critical for proper functioning of algorithms working on trees.
83    fn cmp(&self, other: &Self) -> Ordering {
84        let len = self.filename.len().min(other.filename.len());
85        self.filename[..len].cmp(&other.filename[..len])
86    }
87}
88
89/// An entry in a [`Tree`][crate::Tree], similar to an entry in a directory.
90#[derive(PartialEq, Eq, Debug, Hash, Clone)]
91#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
92pub struct Entry {
93    /// The kind of object to which `oid` is pointing to.
94    pub mode: EntryMode,
95    /// The name of the file in the parent tree.
96    pub filename: BString,
97    /// The id of the object representing the entry.
98    pub oid: git_hash::ObjectId,
99}
100
101impl PartialOrd for Entry {
102    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
103        Some(self.cmp(other))
104    }
105}
106
107impl Ord for Entry {
108    /// Entries compare by the common portion of the filename. This is critical for proper functioning of algorithms working on trees.
109    fn cmp(&self, other: &Self) -> Ordering {
110        let common_len = self.filename.len().min(other.filename.len());
111        self.filename[..common_len]
112            .cmp(&other.filename[..common_len])
113            .then_with(|| self.filename.len().cmp(&other.filename.len()))
114    }
115}
116
117/// Serialization
118impl EntryMode {
119    /// Return the representation as used in the git internal format.
120    pub fn as_bytes(&self) -> &'static [u8] {
121        use EntryMode::*;
122        match self {
123            Tree => b"40000",
124            Blob => b"100644",
125            BlobExecutable => b"100755",
126            Link => b"120000",
127            Commit => b"160000",
128        }
129    }
130}