@@ -32,14 +32,35 @@ impl Error for InvalidHashAlgorithm {}
3232
3333/// A binary object ID.
3434#[ repr( C ) ]
35- #[ derive( Debug , Clone , Ord , PartialOrd , Eq , PartialEq ) ]
35+ #[ derive( Clone , Ord , PartialOrd , Eq , PartialEq ) ]
3636pub struct ObjectID {
3737 pub hash : [ u8 ; GIT_MAX_RAWSZ ] ,
3838 pub algo : u32 ,
3939}
4040
4141#[ allow( dead_code) ]
4242impl ObjectID {
43+ /// Return a new object ID with the given algorithm and hash.
44+ ///
45+ /// `hash` must be exactly the proper length for `algo` and this function panics if it is not.
46+ /// The extra internal storage of `hash`, if any, is zero filled.
47+ pub fn new ( algo : HashAlgorithm , hash : & [ u8 ] ) -> Self {
48+ let mut data = [ 0u8 ; GIT_MAX_RAWSZ ] ;
49+ // This verifies that the length of `hash` is correct.
50+ data[ 0 ..algo. raw_len ( ) ] . copy_from_slice ( hash) ;
51+ Self {
52+ hash : data,
53+ algo : algo as u32 ,
54+ }
55+ }
56+
57+ /// Return the algorithm for this object ID.
58+ ///
59+ /// If the algorithm set internally is not valid, this function panics.
60+ pub fn algo ( & self ) -> Result < HashAlgorithm , InvalidHashAlgorithm > {
61+ HashAlgorithm :: from_u32 ( self . algo ) . ok_or ( InvalidHashAlgorithm ( self . algo ) )
62+ }
63+
4364 pub fn as_slice ( & self ) -> Result < & [ u8 ] , InvalidHashAlgorithm > {
4465 match HashAlgorithm :: from_u32 ( self . algo ) {
4566 Some ( algo) => Ok ( & self . hash [ 0 ..algo. raw_len ( ) ] ) ,
@@ -55,6 +76,41 @@ impl ObjectID {
5576 }
5677}
5778
79+ impl Display for ObjectID {
80+ /// Format this object ID as a hex object ID.
81+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
82+ let hash = self . as_slice ( ) . unwrap ( ) ;
83+ for x in hash {
84+ write ! ( f, "{:02x}" , x) ?;
85+ }
86+ Ok ( ( ) )
87+ }
88+ }
89+
90+ impl Debug for ObjectID {
91+ /// Format this object ID as a hex object ID with a colon and name appended to it.
92+ ///
93+ /// ```
94+ /// assert_eq!(
95+ /// format!("{:?}", HashAlgorithm::SHA256.null_oid()),
96+ /// "0000000000000000000000000000000000000000000000000000000000000000:sha256"
97+ /// );
98+ /// ```
99+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
100+ let hash = match self . as_slice ( ) {
101+ Ok ( hash) => hash,
102+ Err ( _) => & self . hash ,
103+ } ;
104+ for x in hash {
105+ write ! ( f, "{:02x}" , x) ?;
106+ }
107+ match self . algo ( ) {
108+ Ok ( algo) => write ! ( f, ":{}" , algo. name( ) ) ,
109+ Err ( e) => write ! ( f, ":invalid-hash-algo-{}" , e. 0 ) ,
110+ }
111+ }
112+ }
113+
58114/// A hash algorithm,
59115#[ repr( C ) ]
60116#[ derive( Debug , Copy , Clone , Ord , PartialOrd , Eq , PartialEq ) ]
@@ -192,3 +248,78 @@ pub mod c {
192248 pub fn hash_algo_ptr_by_number ( n : u32 ) -> * const c_void ;
193249 }
194250}
251+
252+ #[ cfg( test) ]
253+ mod tests {
254+ use super :: HashAlgorithm ;
255+
256+ fn all_algos ( ) -> & ' static [ HashAlgorithm ] {
257+ & [ HashAlgorithm :: SHA1 , HashAlgorithm :: SHA256 ]
258+ }
259+
260+ #[ test]
261+ fn format_id_round_trips ( ) {
262+ for algo in all_algos ( ) {
263+ assert_eq ! (
264+ * algo,
265+ HashAlgorithm :: from_format_id( algo. format_id( ) ) . unwrap( )
266+ ) ;
267+ }
268+ }
269+
270+ #[ test]
271+ fn offset_round_trips ( ) {
272+ for algo in all_algos ( ) {
273+ assert_eq ! ( * algo, HashAlgorithm :: from_u32( * algo as u32 ) . unwrap( ) ) ;
274+ }
275+ }
276+
277+ #[ test]
278+ fn slices_have_correct_length ( ) {
279+ for algo in all_algos ( ) {
280+ for oid in [ algo. null_oid ( ) , algo. empty_blob ( ) , algo. empty_tree ( ) ] {
281+ assert_eq ! ( oid. as_slice( ) . unwrap( ) . len( ) , algo. raw_len( ) ) ;
282+ }
283+ }
284+ }
285+
286+ #[ test]
287+ fn object_ids_format_correctly ( ) {
288+ let entries = & [
289+ (
290+ HashAlgorithm :: SHA1 . null_oid ( ) ,
291+ "0000000000000000000000000000000000000000" ,
292+ "0000000000000000000000000000000000000000:sha1" ,
293+ ) ,
294+ (
295+ HashAlgorithm :: SHA1 . empty_blob ( ) ,
296+ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" ,
297+ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391:sha1" ,
298+ ) ,
299+ (
300+ HashAlgorithm :: SHA1 . empty_tree ( ) ,
301+ "4b825dc642cb6eb9a060e54bf8d69288fbee4904" ,
302+ "4b825dc642cb6eb9a060e54bf8d69288fbee4904:sha1" ,
303+ ) ,
304+ (
305+ HashAlgorithm :: SHA256 . null_oid ( ) ,
306+ "0000000000000000000000000000000000000000000000000000000000000000" ,
307+ "0000000000000000000000000000000000000000000000000000000000000000:sha256" ,
308+ ) ,
309+ (
310+ HashAlgorithm :: SHA256 . empty_blob ( ) ,
311+ "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813" ,
312+ "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813:sha256" ,
313+ ) ,
314+ (
315+ HashAlgorithm :: SHA256 . empty_tree ( ) ,
316+ "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321" ,
317+ "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321:sha256" ,
318+ ) ,
319+ ] ;
320+ for ( oid, display, debug) in entries {
321+ assert_eq ! ( format!( "{}" , oid) , * display) ;
322+ assert_eq ! ( format!( "{:?}" , oid) , * debug) ;
323+ }
324+ }
325+ }
0 commit comments