Skip to main content

object_rainbow/
hash.rs

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/// Valid [`Hash`]. Has restrictions on its byte layout (e.g. cannot be all zeroes);
11#[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:02X}")?;
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    /// Convert into raw bytes.
79    pub fn into_bytes(self) -> [u8; HASH_SIZE] {
80        self.0
81    }
82}
83
84impl FromOutput for Hash {
85    type Output = sha2::Sha256;
86}
87
88impl From<sha2::Sha256> for Hash {
89    fn from(hasher: sha2::Sha256) -> Self {
90        Self::from_sha256(hasher.finalize().into())
91    }
92}
93
94impl From<Hash> for [u8; HASH_SIZE] {
95    fn from(hash: Hash) -> Self {
96        hash.into_bytes()
97    }
98}
99
100impl Deref for Hash {
101    type Target = [u8; HASH_SIZE];
102
103    fn deref(&self) -> &Self::Target {
104        &self.0
105    }
106}
107
108impl AsRef<[u8]> for Hash {
109    fn as_ref(&self) -> &[u8] {
110        self.as_slice()
111    }
112}
113
114/// `Option<Hash>` but more explicitly represented as `[u8; HASH_SIZE]`.
115#[pod(no_niche, no_default)]
116pub struct OptionalHash([u8; HASH_SIZE]);
117
118/// in preparation for non-all-`0`s `None`
119impl Default for OptionalHash {
120    fn default() -> Self {
121        Self::NONE
122    }
123}
124
125impl Display for OptionalHash {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        if let Some(hash) = self.get() {
128            write!(f, "{hash}")?;
129        } else {
130            write!(f, "NONE")?;
131        }
132        Ok(())
133    }
134}
135
136impl MaybeHasNiche for OptionalHash {
137    type MnArray = SomeNiche<HashNiche<U1>>;
138}
139
140impl Equivalent<Option<Hash>> for OptionalHash {
141    fn into_equivalent(self) -> Option<Hash> {
142        self.get()
143    }
144
145    fn from_equivalent(object: Option<Hash>) -> Self {
146        object.map(Self::from).unwrap_or_default()
147    }
148}
149
150impl From<[u8; HASH_SIZE]> for OptionalHash {
151    fn from(hash: [u8; HASH_SIZE]) -> Self {
152        Self(hash)
153    }
154}
155
156impl From<Hash> for OptionalHash {
157    fn from(value: Hash) -> Self {
158        value.0.into()
159    }
160}
161
162impl OptionalHash {
163    /// No [`Hash`].
164    pub const NONE: Self = Self([0; HASH_SIZE]);
165
166    /// Get [`Hash`] if this isn't [`Self::NONE`].
167    pub fn get(&self) -> Option<Hash> {
168        self.is_some().then_some(Hash(self.0))
169    }
170
171    /// Check whether this is a [`Hash`].
172    pub fn is_some(&self) -> bool {
173        !self.is_none()
174    }
175
176    /// Check whether this is [`Self::NONE`].
177    pub fn is_none(&self) -> bool {
178        *self == Self::NONE
179    }
180
181    /// Get [`Hash`] or panic.
182    pub fn unwrap(&self) -> Hash {
183        self.get().unwrap()
184    }
185
186    /// Set to [`Self::NONE`].
187    pub fn clear(&mut self) {
188        *self = Self::NONE;
189    }
190}
191
192impl PartialEq<Hash> for OptionalHash {
193    fn eq(&self, hash: &Hash) -> bool {
194        self.0 == hash.0
195    }
196}
197
198impl PartialEq<OptionalHash> for Hash {
199    fn eq(&self, hash: &OptionalHash) -> bool {
200        self.0 == hash.0
201    }
202}
203
204impl ByteOrd for Hash {
205    fn bytes_cmp(&self, other: &Self) -> Ordering {
206        self.cmp(other)
207    }
208}
209
210#[test]
211fn none_is_zeros() {
212    assert_eq!(
213        &*None::<Hash>.to_array(),
214        &[
215            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,
216            0, 0, 0,
217        ]
218    );
219}
220
221#[test]
222fn none_none_is_one() {
223    assert_eq!(
224        &*None::<Option<Hash>>.to_array(),
225        &[
226            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,
227            0, 0, 1,
228        ]
229    );
230}
231
232#[test]
233fn none_none_none_is_two() {
234    assert_eq!(
235        &*None::<Option<Option<Hash>>>.to_array(),
236        &[
237            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,
238            0, 0, 2,
239        ]
240    );
241}