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