1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! Hash type for the `libvctrl_handler` version control contracts.
//!
//! # Purpose
//! A [`Hash`](crate::Hash) is a fixed-size, 64-byte cryptographic digest that
//! uniquely identifies an object (blob, tree, commit, or tag) in the version
//! control system. It serves as the primary key for the
//! [`ObjectStore`](crate::ObjectStore) and
//! [`RefStore`](crate::RefStore).
//!
//! # Design rationale
//! The type is a tuple struct wrapping a `[u8; 64]` array. This provides
//! nominal typing: a `Hash` cannot be accidentally confused with another
//! 64-byte array (like a raw SHA-512 digest) because it is a distinct type.
//! It also allows implementing custom [`Display`](std::fmt::Display) and
//! [`Debug`](std::fmt::Debug) traits without violating the orphan rules.
//!
//! # Internal mechanism
//! The [`Hash`](crate::Hash) is `Copy` and `Clone` because 64 bytes is small
//! enough to be cheaply copied on the stack. The
//! [`from_bytes`](crate::Hash::from_bytes) constructor is a `const fn` that
//! validates the length and copies the bytes into the inner array. The `const`
//! context forces the use of a `while` loop instead of iterator methods, but
//! ensures the function can be evaluated at compile time if needed.
use crateHASH_LENGTH;
use crateVctrlError;
use fmt;
/// A 64-byte cryptographic hash used to identify version control objects.
///
/// # Purpose
/// This type represents the output of a 512-bit hash function (like SHA-512).
/// It is used to address and retrieve objects in the
/// [`ObjectStore`](crate::ObjectStore).
///
/// # Design rationale
/// By wrapping the byte array in a tuple struct, we prevent type confusion
/// with other 64-byte arrays. The inner array is private to ensure it can
/// only be constructed via [`Hash::from_bytes`](crate::Hash::from_bytes),
/// which enforces the length invariant.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::Hash;
///
/// let bytes = [0u8; 64];
/// let hash = Hash::from_bytes(&bytes).unwrap();
/// assert_eq!(hash.as_bytes(), &bytes);
/// ```
;
/// Formats the hash for debugging purposes.
///
/// # Design rationale
/// The default `Debug` implementation for arrays would print all 64 bytes,
/// which clutters log output. This implementation prints only the first 8
/// bytes (16 hex characters) followed by an ellipsis, which is sufficient to
/// distinguish between different hashes in logs.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::Hash;
///
/// let bytes = [0u8; 64];
/// let hash = Hash::from_bytes(&bytes).unwrap();
/// assert_eq!(format!("{hash:?}"), "Hash(0000000000000000…)");
/// ```
/// Formats the hash as a lowercase hexadecimal string.
///
/// # Design rationale
/// Hexadecimal is the standard representation for cryptographic hashes in
/// version control systems (e.g., Git object IDs). This implementation is
/// zero-allocation and writes directly to the formatter.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::Hash;
///
/// let bytes = [0u8; 64];
/// let hash = Hash::from_bytes(&bytes).unwrap();
/// assert_eq!(format!("{hash}"), "00".repeat(64));
/// ```