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