@@ -13,9 +13,17 @@ pub mod write;
1313///
1414/// Used in [`mutable::Entry`][crate::tree::Entry] and [`EntryRef`].
1515#[ derive( Clone , Copy , PartialEq , Eq , Debug , Ord , PartialOrd , Hash ) ]
16+ #[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
17+ pub struct EntryMode ( u16 ) ;
18+
19+ /// A discretized version of ideal and valid values for entry modes.
20+ ///
21+ /// Note that even though it can represent every valid [mode](EntryMode), it might
22+ /// loose information due to that as well.
23+ #[ derive( Clone , Copy , PartialEq , Eq , Debug , Ord , PartialOrd , Hash ) ]
1624#[ repr( u16 ) ]
1725#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
18- pub enum EntryMode {
26+ pub enum EntryKind {
1927 /// A tree, or directory
2028 Tree = 0o040000u16 ,
2129 /// A file that is not executable
@@ -28,38 +36,129 @@ pub enum EntryMode {
2836 Commit = 0o160000 ,
2937}
3038
39+ impl From < EntryKind > for EntryMode {
40+ fn from ( value : EntryKind ) -> Self {
41+ EntryMode ( value as u16 )
42+ }
43+ }
44+
45+ impl From < EntryMode > for EntryKind {
46+ fn from ( value : EntryMode ) -> Self {
47+ value. kind ( )
48+ }
49+ }
50+
51+ /// Serialization
52+ impl EntryKind {
53+ /// Return the representation as used in the git internal format.
54+ pub fn as_octal_str ( & self ) -> & ' static BStr {
55+ use EntryKind :: * ;
56+ let bytes: & [ u8 ] = match self {
57+ Tree => b"40000" ,
58+ Blob => b"100644" ,
59+ BlobExecutable => b"100755" ,
60+ Link => b"120000" ,
61+ Commit => b"160000" ,
62+ } ;
63+ bytes. into ( )
64+ }
65+ }
66+
67+ impl std:: ops:: Deref for EntryMode {
68+ type Target = u16 ;
69+
70+ fn deref ( & self ) -> & Self :: Target {
71+ & self . 0
72+ }
73+ }
74+
3175impl EntryMode {
76+ /// Discretize the raw mode into an enum with well-known state while dropping unnecessary details.
77+ pub const fn kind ( & self ) -> EntryKind {
78+ match self . 0 {
79+ 0o40000 => EntryKind :: Tree ,
80+ 0o120000 => EntryKind :: Link ,
81+ 0o160000 => EntryKind :: Commit ,
82+ blob_mode => {
83+ if blob_mode & 0o000100 == 0o000100 {
84+ EntryKind :: BlobExecutable
85+ } else {
86+ EntryKind :: Blob
87+ }
88+ }
89+ }
90+ }
91+
3292 /// Return true if this entry mode represents a Tree/directory
33- pub fn is_tree ( & self ) -> bool {
34- * self == EntryMode :: Tree
93+ pub const fn is_tree ( & self ) -> bool {
94+ self . 0 == EntryKind :: Tree as u16
95+ }
96+
97+ /// Return true if this entry mode represents the commit of a submodule.
98+ pub const fn is_commit ( & self ) -> bool {
99+ self . 0 == EntryKind :: Commit as u16
100+ }
101+
102+ /// Return true if this entry mode represents a symbolic link
103+ pub const fn is_link ( & self ) -> bool {
104+ self . 0 == EntryKind :: Link as u16
35105 }
36106
37107 /// Return true if this entry mode represents anything BUT Tree/directory
38- pub fn is_no_tree ( & self ) -> bool {
39- * self != EntryMode :: Tree
108+ pub const fn is_no_tree ( & self ) -> bool {
109+ self . 0 != EntryKind :: Tree as u16
40110 }
41111
42112 /// Return true if the entry is any kind of blob.
43- pub fn is_blob ( & self ) -> bool {
44- matches ! ( self , EntryMode :: Blob | EntryMode :: BlobExecutable )
113+ pub const fn is_blob ( & self ) -> bool {
114+ matches ! ( self . kind( ) , EntryKind :: Blob | EntryKind :: BlobExecutable )
115+ }
116+
117+ /// Return true if the entry is an executable blob.
118+ pub const fn is_executable ( & self ) -> bool {
119+ matches ! ( self . kind( ) , EntryKind :: BlobExecutable )
45120 }
46121
47122 /// Return true if the entry is any kind of blob or symlink.
48- pub fn is_blob_or_symlink ( & self ) -> bool {
49- matches ! ( self , EntryMode :: Blob | EntryMode :: BlobExecutable | EntryMode :: Link )
123+ pub const fn is_blob_or_symlink ( & self ) -> bool {
124+ matches ! (
125+ self . kind( ) ,
126+ EntryKind :: Blob | EntryKind :: BlobExecutable | EntryKind :: Link
127+ )
50128 }
51129
52130 /// Represent the mode as descriptive string.
53- pub fn as_str ( & self ) -> & ' static str {
54- use EntryMode :: * ;
55- match self {
131+ pub const fn as_str ( & self ) -> & ' static str {
132+ use EntryKind :: * ;
133+ match self . kind ( ) {
56134 Tree => "tree" ,
57135 Blob => "blob" ,
58136 BlobExecutable => "exe" ,
59137 Link => "link" ,
60138 Commit => "commit" ,
61139 }
62140 }
141+
142+ /// Return the representation as used in the git internal format, which is octal and written
143+ /// to the `backing` buffer. The respective sub-slice that was written to is returned.
144+ pub fn as_bytes < ' a > ( & self , backing : & ' a mut [ u8 ; 6 ] ) -> & ' a BStr {
145+ if self . 0 == 0 {
146+ std:: slice:: from_ref ( & b'0' )
147+ } else {
148+ let mut nb = 0 ;
149+ let mut n = self . 0 ;
150+ while n > 0 {
151+ let remainder = ( n % 8 ) as u8 ;
152+ backing[ nb] = b'0' + remainder;
153+ n /= 8 ;
154+ nb += 1 ;
155+ }
156+ let res = & mut backing[ ..nb] ;
157+ res. reverse ( ) ;
158+ res
159+ }
160+ . into ( )
161+ }
63162}
64163
65164/// An element of a [`TreeRef`][crate::TreeRef::entries].
@@ -124,18 +223,3 @@ impl Ord for Entry {
124223 } )
125224 }
126225}
127-
128- /// Serialization
129- impl EntryMode {
130- /// Return the representation as used in the git internal format.
131- pub fn as_bytes ( & self ) -> & ' static [ u8 ] {
132- use EntryMode :: * ;
133- match self {
134- Tree => b"40000" ,
135- Blob => b"100644" ,
136- BlobExecutable => b"100755" ,
137- Link => b"120000" ,
138- Commit => b"160000" ,
139- }
140- }
141- }
0 commit comments