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