1use crate::error::{GitError, Result};
2use std::fmt;
3
4#[derive(Clone, Copy, PartialEq, Eq, Hash)]
5pub struct GitHash(pub [u8; 20]);
6
7impl GitHash {
8 pub fn from_hex(s: &str) -> Result<Self> {
9 if s.len() != 40 {
10 return Err(GitError::InvalidHash(format!(
11 "expected 40 hex chars, got {}: {:?}",
12 s.len(),
13 s
14 )));
15 }
16 let mut bytes = [0u8; 20];
17 hex::decode_to_slice(s, &mut bytes)
18 .map_err(|e| GitError::InvalidHash(format!("{e}: {s:?}")))?;
19 Ok(Self(bytes))
20 }
21
22 pub fn from_bytes(b: &[u8]) -> Result<Self> {
23 b.try_into()
24 .map(|arr: [u8; 20]| Self(arr))
25 .map_err(|_| GitError::InvalidHash(format!("expected 20 bytes, got {}", b.len())))
26 }
27
28 pub fn as_bytes(&self) -> &[u8; 20] {
29 &self.0
30 }
31
32 pub fn to_hex(&self) -> String {
33 hex::encode(self.0)
34 }
35
36 pub fn object_path(&self) -> (String, String) {
37 let hex = self.to_hex();
38 (hex[..2].to_string(), hex[2..].to_string())
39 }
40}
41
42impl fmt::Debug for GitHash {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 write!(f, "GitHash({})", self.to_hex())
45 }
46}
47
48impl fmt::Display for GitHash {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 write!(f, "{}", self.to_hex())
51 }
52}