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