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