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