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(
11 Debug,
12 ToOutput,
13 InlineOutput,
14 Tagged,
15 ListHashes,
16 Topological,
17 ParseAsInline,
18 Clone,
19 Copy,
20 PartialEq,
21 Eq,
22 PartialOrd,
23 Ord,
24 Hash,
25 Size,
26)]
27pub struct Hash([u8; HASH_SIZE]);
28
29impl Display for Hash {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 for x in self.0 {
32 write!(f, "{x:X}")?;
33 }
34 Ok(())
35 }
36}
37
38pub struct HashNiche<N>(N);
39
40impl<N: ToInt<u8> + Add<B1>> Niche for HashNiche<N> {
41 type NeedsTag = B0;
42 type N = <Hash as Size>::Size;
43 fn niche() -> GenericArray<u8, Self::N> {
44 let mut niche = GenericArray::default();
45 let last_byte = niche.len() - 1;
46 niche[last_byte] = N::to_int();
47 niche
48 }
49 type Next = SomeNiche<HashNiche<Add1<N>>>;
50}
51
52impl MaybeHasNiche for Hash {
53 type MnArray = SomeNiche<HashNiche<U0>>;
54}
55
56impl<I: ParseInput> ParseInline<I> for Hash {
57 fn parse_inline(input: &mut I) -> crate::Result<Self> {
58 input
59 .parse_inline::<OptionalHash>()?
60 .get()
61 .ok_or(Error::Zero)
62 }
63}
64
65impl Hash {
66 pub(crate) const fn from_sha256(hash: [u8; HASH_SIZE]) -> Self {
67 Self(hash)
68 }
69
70 pub fn into_bytes(self) -> [u8; HASH_SIZE] {
71 self.0
72 }
73}
74
75impl Deref for Hash {
76 type Target = [u8; HASH_SIZE];
77
78 fn deref(&self) -> &Self::Target {
79 &self.0
80 }
81}
82
83impl AsRef<[u8]> for Hash {
84 fn as_ref(&self) -> &[u8] {
85 self.as_slice()
86 }
87}
88
89#[derive(
90 Debug,
91 Clone,
92 Copy,
93 PartialEq,
94 Eq,
95 PartialOrd,
96 Ord,
97 Hash,
98 ToOutput,
99 InlineOutput,
100 Parse,
101 ParseInline,
102 Tagged,
103 ListHashes,
104 Topological,
105 Size,
106 Default,
107)]
108pub struct OptionalHash([u8; HASH_SIZE]);
109
110impl Display for OptionalHash {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 if self.is_some() {
113 for x in self.0 {
114 write!(f, "{x:X}")?;
115 }
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]);
151
152 pub fn get(&self) -> Option<Hash> {
153 self.is_some().then_some(Hash(self.0))
154 }
155
156 pub fn is_some(&self) -> bool {
157 !self.is_none()
158 }
159
160 pub fn is_none(&self) -> bool {
161 *self == Self::NONE
162 }
163
164 pub fn unwrap(&self) -> Hash {
165 self.get().unwrap()
166 }
167
168 pub fn clear(&mut self) {
169 *self = Self::NONE;
170 }
171}
172
173impl PartialEq<Hash> for OptionalHash {
174 fn eq(&self, hash: &Hash) -> bool {
175 self.0 == hash.0
176 }
177}
178
179impl PartialEq<OptionalHash> for Hash {
180 fn eq(&self, hash: &OptionalHash) -> bool {
181 self.0 == hash.0
182 }
183}
184
185#[test]
186fn none_is_zeros() {
187 assert_eq!(
188 None::<Hash>.to_array().into_array(),
189 [
190 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,
191 0, 0, 0,
192 ]
193 );
194}
195
196#[test]
197fn none_none_is_one() {
198 assert_eq!(
199 None::<Option<Hash>>.to_array().into_array(),
200 [
201 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,
202 0, 0, 1,
203 ]
204 );
205}
206
207#[test]
208fn none_none_none_is_two() {
209 assert_eq!(
210 None::<Option<Option<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, 2,
214 ]
215 );
216}