Skip to content

Commit a49ea4b

Browse files
bk2204gitster
authored andcommitted
rust: add a hash algorithm abstraction
This works very similarly to the existing one in C except that it doesn't provide any functionality to hash an object. We don't currently need that right now, but the use of those function pointers do make it substantially more difficult to write a bit-for-bit identical structure across the C/Rust interface, so omit them for now. Instead of the more customary "&self", use "self", because the former is the size of a pointer and the latter is the size of an integer on most systems. Don't define an unknown value but use an Option for that instead. Update the object ID structure to allow slicing the data appropriately for the algorithm. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent eec4151 commit a49ea4b

File tree

1 file changed

+142
-0
lines changed

1 file changed

+142
-0
lines changed

src/hash.rs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,145 @@ pub struct ObjectID {
1919
pub hash: [u8; GIT_MAX_RAWSZ],
2020
pub algo: u32,
2121
}
22+
23+
#[allow(dead_code)]
24+
impl ObjectID {
25+
pub fn as_slice(&self) -> &[u8] {
26+
match HashAlgorithm::from_u32(self.algo) {
27+
Some(algo) => &self.hash[0..algo.raw_len()],
28+
None => &self.hash,
29+
}
30+
}
31+
32+
pub fn as_mut_slice(&mut self) -> &mut [u8] {
33+
match HashAlgorithm::from_u32(self.algo) {
34+
Some(algo) => &mut self.hash[0..algo.raw_len()],
35+
None => &mut self.hash,
36+
}
37+
}
38+
}
39+
40+
/// A hash algorithm,
41+
#[repr(C)]
42+
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
43+
pub enum HashAlgorithm {
44+
SHA1 = 1,
45+
SHA256 = 2,
46+
}
47+
48+
#[allow(dead_code)]
49+
impl HashAlgorithm {
50+
const SHA1_NULL_OID: ObjectID = ObjectID {
51+
hash: [0u8; 32],
52+
algo: Self::SHA1 as u32,
53+
};
54+
const SHA256_NULL_OID: ObjectID = ObjectID {
55+
hash: [0u8; 32],
56+
algo: Self::SHA256 as u32,
57+
};
58+
59+
const SHA1_EMPTY_TREE: ObjectID = ObjectID {
60+
hash: *b"\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
61+
algo: Self::SHA1 as u32,
62+
};
63+
const SHA256_EMPTY_TREE: ObjectID = ObjectID {
64+
hash: *b"\x6e\xf1\x9b\x41\x22\x5c\x53\x69\xf1\xc1\x04\xd4\x5d\x8d\x85\xef\xa9\xb0\x57\xb5\x3b\x14\xb4\xb9\xb9\x39\xdd\x74\xde\xcc\x53\x21",
65+
algo: Self::SHA256 as u32,
66+
};
67+
68+
const SHA1_EMPTY_BLOB: ObjectID = ObjectID {
69+
hash: *b"\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
70+
algo: Self::SHA1 as u32,
71+
};
72+
const SHA256_EMPTY_BLOB: ObjectID = ObjectID {
73+
hash: *b"\x47\x3a\x0f\x4c\x3b\xe8\xa9\x36\x81\xa2\x67\xe3\xb1\xe9\xa7\xdc\xda\x11\x85\x43\x6f\xe1\x41\xf7\x74\x91\x20\xa3\x03\x72\x18\x13",
74+
algo: Self::SHA256 as u32,
75+
};
76+
77+
/// Return a hash algorithm based on the internal integer ID used by Git.
78+
///
79+
/// Returns `None` if the algorithm doesn't indicate a valid algorithm.
80+
pub const fn from_u32(algo: u32) -> Option<HashAlgorithm> {
81+
match algo {
82+
1 => Some(HashAlgorithm::SHA1),
83+
2 => Some(HashAlgorithm::SHA256),
84+
_ => None,
85+
}
86+
}
87+
88+
/// Return a hash algorithm based on the internal integer ID used by Git.
89+
///
90+
/// Returns `None` if the algorithm doesn't indicate a valid algorithm.
91+
pub const fn from_format_id(algo: u32) -> Option<HashAlgorithm> {
92+
match algo {
93+
0x73686131 => Some(HashAlgorithm::SHA1),
94+
0x73323536 => Some(HashAlgorithm::SHA256),
95+
_ => None,
96+
}
97+
}
98+
99+
/// The name of this hash algorithm as a string suitable for the configuration file.
100+
pub const fn name(self) -> &'static str {
101+
match self {
102+
HashAlgorithm::SHA1 => "sha1",
103+
HashAlgorithm::SHA256 => "sha256",
104+
}
105+
}
106+
107+
/// The format ID of this algorithm for binary formats.
108+
///
109+
/// Note that when writing this to a data format, it should be written in big-endian format
110+
/// explicitly.
111+
pub const fn format_id(self) -> u32 {
112+
match self {
113+
HashAlgorithm::SHA1 => 0x73686131,
114+
HashAlgorithm::SHA256 => 0x73323536,
115+
}
116+
}
117+
118+
/// The length of binary object IDs in this algorithm in bytes.
119+
pub const fn raw_len(self) -> usize {
120+
match self {
121+
HashAlgorithm::SHA1 => 20,
122+
HashAlgorithm::SHA256 => 32,
123+
}
124+
}
125+
126+
/// The length of object IDs in this algorithm in hexadecimal characters.
127+
pub const fn hex_len(self) -> usize {
128+
self.raw_len() * 2
129+
}
130+
131+
/// The number of bytes which is processed by one iteration of this algorithm's compression
132+
/// function.
133+
pub const fn block_size(self) -> usize {
134+
match self {
135+
HashAlgorithm::SHA1 => 64,
136+
HashAlgorithm::SHA256 => 64,
137+
}
138+
}
139+
140+
/// The object ID representing the empty blob.
141+
pub const fn empty_blob(self) -> &'static ObjectID {
142+
match self {
143+
HashAlgorithm::SHA1 => &Self::SHA1_EMPTY_BLOB,
144+
HashAlgorithm::SHA256 => &Self::SHA256_EMPTY_BLOB,
145+
}
146+
}
147+
148+
/// The object ID representing the empty tree.
149+
pub const fn empty_tree(self) -> &'static ObjectID {
150+
match self {
151+
HashAlgorithm::SHA1 => &Self::SHA1_EMPTY_TREE,
152+
HashAlgorithm::SHA256 => &Self::SHA256_EMPTY_TREE,
153+
}
154+
}
155+
156+
/// The object ID which is all zeros.
157+
pub const fn null_oid(self) -> &'static ObjectID {
158+
match self {
159+
HashAlgorithm::SHA1 => &Self::SHA1_NULL_OID,
160+
HashAlgorithm::SHA256 => &Self::SHA256_NULL_OID,
161+
}
162+
}
163+
}

0 commit comments

Comments
 (0)