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