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