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