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 into_bytes(self) -> [u8; HASH_SIZE] {
80 self.0
81 }
82}
83
84impl FromOutput for Hash {
85 type Output = sha2::Sha256;
86}
87
88impl From<sha2::Sha256> for Hash {
89 fn from(hasher: sha2::Sha256) -> Self {
90 Self::from_sha256(hasher.finalize().into())
91 }
92}
93
94impl From<Hash> for [u8; HASH_SIZE] {
95 fn from(hash: Hash) -> Self {
96 hash.into_bytes()
97 }
98}
99
100impl Deref for Hash {
101 type Target = [u8; HASH_SIZE];
102
103 fn deref(&self) -> &Self::Target {
104 &self.0
105 }
106}
107
108impl AsRef<[u8]> for Hash {
109 fn as_ref(&self) -> &[u8] {
110 self.as_slice()
111 }
112}
113
114#[pod(no_niche, no_default)]
116pub struct OptionalHash([u8; HASH_SIZE]);
117
118impl Default for OptionalHash {
120 fn default() -> Self {
121 Self::NONE
122 }
123}
124
125impl Display for OptionalHash {
126 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127 if let Some(hash) = self.get() {
128 write!(f, "{hash}")?;
129 } else {
130 write!(f, "NONE")?;
131 }
132 Ok(())
133 }
134}
135
136impl MaybeHasNiche for OptionalHash {
137 type MnArray = SomeNiche<HashNiche<U1>>;
138}
139
140impl Equivalent<Option<Hash>> for OptionalHash {
141 fn into_equivalent(self) -> Option<Hash> {
142 self.get()
143 }
144
145 fn from_equivalent(object: Option<Hash>) -> Self {
146 object.map(Self::from).unwrap_or_default()
147 }
148}
149
150impl From<[u8; HASH_SIZE]> for OptionalHash {
151 fn from(hash: [u8; HASH_SIZE]) -> Self {
152 Self(hash)
153 }
154}
155
156impl From<Hash> for OptionalHash {
157 fn from(value: Hash) -> Self {
158 value.0.into()
159 }
160}
161
162impl OptionalHash {
163 pub const NONE: Self = Self([0; HASH_SIZE]);
165
166 pub fn get(&self) -> Option<Hash> {
168 self.is_some().then_some(Hash(self.0))
169 }
170
171 pub fn is_some(&self) -> bool {
173 !self.is_none()
174 }
175
176 pub fn is_none(&self) -> bool {
178 *self == Self::NONE
179 }
180
181 pub fn unwrap(&self) -> Hash {
183 self.get().unwrap()
184 }
185
186 pub fn clear(&mut self) {
188 *self = Self::NONE;
189 }
190}
191
192impl PartialEq<Hash> for OptionalHash {
193 fn eq(&self, hash: &Hash) -> bool {
194 self.0 == hash.0
195 }
196}
197
198impl PartialEq<OptionalHash> for Hash {
199 fn eq(&self, hash: &OptionalHash) -> bool {
200 self.0 == hash.0
201 }
202}
203
204impl ByteOrd for Hash {
205 fn bytes_cmp(&self, other: &Self) -> Ordering {
206 self.cmp(other)
207 }
208}
209
210#[test]
211fn none_is_zeros() {
212 assert_eq!(
213 &*None::<Hash>.to_array(),
214 &[
215 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,
216 0, 0, 0,
217 ]
218 );
219}
220
221#[test]
222fn none_none_is_one() {
223 assert_eq!(
224 &*None::<Option<Hash>>.to_array(),
225 &[
226 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,
227 0, 0, 1,
228 ]
229 );
230}
231
232#[test]
233fn none_none_none_is_two() {
234 assert_eq!(
235 &*None::<Option<Option<Hash>>>.to_array(),
236 &[
237 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,
238 0, 0, 2,
239 ]
240 );
241}