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:X}")?;
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 self.is_some() {
127            for x in self.0 {
128                write!(f, "{x:X}")?;
129            }
130        } else {
131            write!(f, "NONE")?;
132        }
133        Ok(())
134    }
135}
136
137impl MaybeHasNiche for OptionalHash {
138    type MnArray = SomeNiche<HashNiche<U1>>;
139}
140
141impl Equivalent<Option<Hash>> for OptionalHash {
142    fn into_equivalent(self) -> Option<Hash> {
143        self.get()
144    }
145
146    fn from_equivalent(object: Option<Hash>) -> Self {
147        object.map(Self::from).unwrap_or_default()
148    }
149}
150
151impl From<[u8; HASH_SIZE]> for OptionalHash {
152    fn from(hash: [u8; HASH_SIZE]) -> Self {
153        Self(hash)
154    }
155}
156
157impl From<Hash> for OptionalHash {
158    fn from(value: Hash) -> Self {
159        value.0.into()
160    }
161}
162
163impl OptionalHash {
164    /// No [`Hash`].
165    pub const NONE: Self = Self([0; HASH_SIZE]);
166
167    /// Get [`Hash`] if this isn't [`Self::NONE`].
168    pub fn get(&self) -> Option<Hash> {
169        self.is_some().then_some(Hash(self.0))
170    }
171
172    /// Check whether this is a [`Hash`].
173    pub fn is_some(&self) -> bool {
174        !self.is_none()
175    }
176
177    /// Check whether this is [`Self::NONE`].
178    pub fn is_none(&self) -> bool {
179        *self == Self::NONE
180    }
181
182    /// Get [`Hash`] or panic.
183    pub fn unwrap(&self) -> Hash {
184        self.get().unwrap()
185    }
186
187    /// Set to [`Self::NONE`].
188    pub fn clear(&mut self) {
189        *self = Self::NONE;
190    }
191}
192
193impl PartialEq<Hash> for OptionalHash {
194    fn eq(&self, hash: &Hash) -> bool {
195        self.0 == hash.0
196    }
197}
198
199impl PartialEq<OptionalHash> for Hash {
200    fn eq(&self, hash: &OptionalHash) -> bool {
201        self.0 == hash.0
202    }
203}
204
205impl ByteOrd for Hash {
206    fn bytes_cmp(&self, other: &Self) -> Ordering {
207        self.cmp(other)
208    }
209}
210
211#[test]
212fn none_is_zeros() {
213    assert_eq!(
214        None::<Hash>.to_array().into_array(),
215        [
216            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,
217            0, 0, 0,
218        ]
219    );
220}
221
222#[test]
223fn none_none_is_one() {
224    assert_eq!(
225        None::<Option<Hash>>.to_array().into_array(),
226        [
227            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,
228            0, 0, 1,
229        ]
230    );
231}
232
233#[test]
234fn none_none_none_is_two() {
235    assert_eq!(
236        None::<Option<Option<Hash>>>.to_array().into_array(),
237        [
238            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,
239            0, 0, 2,
240        ]
241    );
242}