1use std::{fmt::Display, ops::Add};
2
3use typenum::{Add1, B0, B1, ToInt, U0, U1};
4
5use crate::*;
6
7#[cfg(feature = "hex")]
8mod hex;
9
10#[derive(
12 Debug,
13 ToOutput,
14 InlineOutput,
15 Tagged,
16 ListHashes,
17 Topological,
18 ParseAsInline,
19 Clone,
20 Copy,
21 PartialEq,
22 Eq,
23 PartialOrd,
24 Ord,
25 Hash,
26 Size,
27)]
28pub struct Hash([u8; HASH_SIZE]);
29
30impl Default for Hash {
31 fn default() -> Self {
32 "".data_hash()
33 }
34}
35
36impl Display for Hash {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 for x in self.0 {
39 write!(f, "{x:02X}")?;
40 }
41 Ok(())
42 }
43}
44
45pub struct HashNiche<N>(N);
46
47impl<N: ToInt<u8> + Add<B1>> Niche for HashNiche<N> {
48 type NeedsTag = B0;
49 type Cut = B0;
50 type N = <Hash as Size>::Size;
51 fn niche() -> GenericArray<u8, Self::N> {
52 let mut niche = GenericArray::default();
53 let last_byte = niche.len() - 1;
54 niche[last_byte] = N::to_int();
55 niche
56 }
57 type Next = SomeNiche<HashNiche<Add1<N>>>;
58}
59
60impl MaybeHasNiche for Hash {
61 type MnArray = SomeNiche<HashNiche<U0>>;
62}
63
64impl<I: ParseInput> ParseInline<I> for Hash {
65 fn parse_inline(input: &mut I) -> crate::Result<Self> {
66 input
67 .parse_inline::<OptionalHash>()?
68 .get()
69 .ok_or(Error::Zero)
70 }
71}
72
73impl Hash {
74 pub(crate) const fn from_sha256(hash: [u8; HASH_SIZE]) -> Self {
75 Self(hash)
76 }
77
78 pub fn from_hasher(hasher: sha2::Sha256) -> Self {
79 Self::from_sha256(hasher.finalize().into())
80 }
81
82 pub fn into_bytes(self) -> [u8; HASH_SIZE] {
84 self.0
85 }
86}
87
88impl Deref for Hash {
89 type Target = [u8; HASH_SIZE];
90
91 fn deref(&self) -> &Self::Target {
92 &self.0
93 }
94}
95
96impl AsRef<[u8]> for Hash {
97 fn as_ref(&self) -> &[u8] {
98 self.as_slice()
99 }
100}
101
102#[derive(
104 Debug,
105 Clone,
106 Copy,
107 PartialEq,
108 Eq,
109 PartialOrd,
110 Ord,
111 Hash,
112 ToOutput,
113 InlineOutput,
114 Parse,
115 ParseInline,
116 Tagged,
117 ListHashes,
118 Topological,
119 Size,
120 Default,
121)]
122pub struct OptionalHash([u8; HASH_SIZE]);
123
124impl Display for OptionalHash {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 if let Some(hash) = self.get() {
127 write!(f, "{hash}")?;
128 } else {
129 write!(f, "NONE")?;
130 }
131 Ok(())
132 }
133}
134
135impl MaybeHasNiche for OptionalHash {
136 type MnArray = SomeNiche<HashNiche<U1>>;
137}
138
139impl Equivalent<Option<Hash>> for OptionalHash {
140 fn into_equivalent(self) -> Option<Hash> {
141 self.get()
142 }
143
144 fn from_equivalent(object: Option<Hash>) -> Self {
145 object.map(Self::from).unwrap_or_default()
146 }
147}
148
149impl From<[u8; HASH_SIZE]> for OptionalHash {
150 fn from(hash: [u8; HASH_SIZE]) -> Self {
151 Self(hash)
152 }
153}
154
155impl From<Hash> for OptionalHash {
156 fn from(value: Hash) -> Self {
157 value.0.into()
158 }
159}
160
161impl OptionalHash {
162 pub const NONE: Self = Self([0; HASH_SIZE]);
164
165 pub fn get(&self) -> Option<Hash> {
167 self.is_some().then_some(Hash(self.0))
168 }
169
170 pub fn is_some(&self) -> bool {
172 !self.is_none()
173 }
174
175 pub fn is_none(&self) -> bool {
177 *self == Self::NONE
178 }
179
180 pub fn unwrap(&self) -> Hash {
182 self.get().unwrap()
183 }
184
185 pub fn clear(&mut self) {
187 *self = Self::NONE;
188 }
189}
190
191impl PartialEq<Hash> for OptionalHash {
192 fn eq(&self, hash: &Hash) -> bool {
193 self.0 == hash.0
194 }
195}
196
197impl PartialEq<OptionalHash> for Hash {
198 fn eq(&self, hash: &OptionalHash) -> bool {
199 self.0 == hash.0
200 }
201}
202
203impl ByteOrd for Hash {
204 fn bytes_cmp(&self, other: &Self) -> Ordering {
205 self.cmp(other)
206 }
207}
208
209#[test]
210fn none_is_zeros() {
211 assert_eq!(
212 None::<Hash>.to_array().into_array(),
213 [
214 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
215 0, 0, 0,
216 ]
217 );
218}
219
220#[test]
221fn none_none_is_one() {
222 assert_eq!(
223 None::<Option<Hash>>.to_array().into_array(),
224 [
225 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
226 0, 0, 1,
227 ]
228 );
229}
230
231#[test]
232fn none_none_none_is_two() {
233 assert_eq!(
234 None::<Option<Option<Hash>>>.to_array().into_array(),
235 [
236 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
237 0, 0, 2,
238 ]
239 );
240}