@@ -13,9 +13,17 @@ pub mod write;
13
13
///
14
14
/// Used in [`mutable::Entry`][crate::tree::Entry] and [`EntryRef`].
15
15
#[ 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 ) ]
16
24
#[ repr( u16 ) ]
17
25
#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
18
- pub enum EntryMode {
26
+ pub enum EntryKind {
19
27
/// A tree, or directory
20
28
Tree = 0o040000u16 ,
21
29
/// A file that is not executable
@@ -28,38 +36,129 @@ pub enum EntryMode {
28
36
Commit = 0o160000 ,
29
37
}
30
38
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
+
31
75
impl 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
+
32
92
/// 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
35
105
}
36
106
37
107
/// 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
40
110
}
41
111
42
112
/// 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 )
45
120
}
46
121
47
122
/// 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
+ )
50
128
}
51
129
52
130
/// 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 ( ) {
56
134
Tree => "tree" ,
57
135
Blob => "blob" ,
58
136
BlobExecutable => "exe" ,
59
137
Link => "link" ,
60
138
Commit => "commit" ,
61
139
}
62
140
}
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
+ }
63
162
}
64
163
65
164
/// An element of a [`TreeRef`][crate::TreeRef::entries].
@@ -124,18 +223,3 @@ impl Ord for Entry {
124
223
} )
125
224
}
126
225
}
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