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:X}")?;
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 self.is_some() {
127 for x in self.0 {
128 write!(f, "{x:X}")?;
129 }
130 } else {
131 write!(f, "NONE")?;
132 }
133 Ok(())
134 }
135}
136
137impl MaybeHasNiche for OptionalHash {
138 type MnArray = SomeNiche<HashNiche<U1>>;
139}
140
141impl Equivalent<Option<Hash>> for OptionalHash {
142 fn into_equivalent(self) -> Option<Hash> {
143 self.get()
144 }
145
146 fn from_equivalent(object: Option<Hash>) -> Self {
147 object.map(Self::from).unwrap_or_default()
148 }
149}
150
151impl From<[u8; HASH_SIZE]> for OptionalHash {
152 fn from(hash: [u8; HASH_SIZE]) -> Self {
153 Self(hash)
154 }
155}
156
157impl From<Hash> for OptionalHash {
158 fn from(value: Hash) -> Self {
159 value.0.into()
160 }
161}
162
163impl OptionalHash {
164 pub const NONE: Self = Self([0; HASH_SIZE]);
166
167 pub fn get(&self) -> Option<Hash> {
169 self.is_some().then_some(Hash(self.0))
170 }
171
172 pub fn is_some(&self) -> bool {
174 !self.is_none()
175 }
176
177 pub fn is_none(&self) -> bool {
179 *self == Self::NONE
180 }
181
182 pub fn unwrap(&self) -> Hash {
184 self.get().unwrap()
185 }
186
187 pub fn clear(&mut self) {
189 *self = Self::NONE;
190 }
191}
192
193impl PartialEq<Hash> for OptionalHash {
194 fn eq(&self, hash: &Hash) -> bool {
195 self.0 == hash.0
196 }
197}
198
199impl PartialEq<OptionalHash> for Hash {
200 fn eq(&self, hash: &OptionalHash) -> bool {
201 self.0 == hash.0
202 }
203}
204
205impl ByteOrd for Hash {
206 fn bytes_cmp(&self, other: &Self) -> Ordering {
207 self.cmp(other)
208 }
209}
210
211#[test]
212fn none_is_zeros() {
213 assert_eq!(
214 None::<Hash>.to_array().into_array(),
215 [
216 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,
217 0, 0, 0,
218 ]
219 );
220}
221
222#[test]
223fn none_none_is_one() {
224 assert_eq!(
225 None::<Option<Hash>>.to_array().into_array(),
226 [
227 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,
228 0, 0, 1,
229 ]
230 );
231}
232
233#[test]
234fn none_none_none_is_two() {
235 assert_eq!(
236 None::<Option<Option<Hash>>>.to_array().into_array(),
237 [
238 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,
239 0, 0, 2,
240 ]
241 );
242}