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#[derive(
11    Debug,
12    ToOutput,
13    InlineOutput,
14    Tagged,
15    ListHashes,
16    Topological,
17    ParseAsInline,
18    Clone,
19    Copy,
20    PartialEq,
21    Eq,
22    PartialOrd,
23    Ord,
24    Hash,
25    Size,
26)]
27pub struct Hash([u8; HASH_SIZE]);
28
29impl Display for Hash {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        for x in self.0 {
32            write!(f, "{x:X}")?;
33        }
34        Ok(())
35    }
36}
37
38pub struct HashNiche<N>(N);
39
40impl<N: ToInt<u8> + Add<B1>> Niche for HashNiche<N> {
41    type NeedsTag = B0;
42    type N = <Hash as Size>::Size;
43    fn niche() -> GenericArray<u8, Self::N> {
44        let mut niche = GenericArray::default();
45        let last_byte = niche.len() - 1;
46        niche[last_byte] = N::to_int();
47        niche
48    }
49    type Next = SomeNiche<HashNiche<Add1<N>>>;
50}
51
52impl MaybeHasNiche for Hash {
53    type MnArray = SomeNiche<HashNiche<U0>>;
54}
55
56impl<I: ParseInput> ParseInline<I> for Hash {
57    fn parse_inline(input: &mut I) -> crate::Result<Self> {
58        input
59            .parse_inline::<OptionalHash>()?
60            .get()
61            .ok_or(Error::Zero)
62    }
63}
64
65impl Hash {
66    pub(crate) const fn from_sha256(hash: [u8; HASH_SIZE]) -> Self {
67        Self(hash)
68    }
69
70    pub fn into_bytes(self) -> [u8; HASH_SIZE] {
71        self.0
72    }
73}
74
75impl Deref for Hash {
76    type Target = [u8; HASH_SIZE];
77
78    fn deref(&self) -> &Self::Target {
79        &self.0
80    }
81}
82
83impl AsRef<[u8]> for Hash {
84    fn as_ref(&self) -> &[u8] {
85        self.as_slice()
86    }
87}
88
89#[derive(
90    Debug,
91    Clone,
92    Copy,
93    PartialEq,
94    Eq,
95    PartialOrd,
96    Ord,
97    Hash,
98    ToOutput,
99    InlineOutput,
100    Parse,
101    ParseInline,
102    Tagged,
103    ListHashes,
104    Topological,
105    Size,
106    Default,
107)]
108pub struct OptionalHash([u8; HASH_SIZE]);
109
110impl Display for OptionalHash {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        if self.is_some() {
113            for x in self.0 {
114                write!(f, "{x:X}")?;
115            }
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    pub const NONE: Self = Self([0; HASH_SIZE]);
151
152    pub fn get(&self) -> Option<Hash> {
153        self.is_some().then_some(Hash(self.0))
154    }
155
156    pub fn is_some(&self) -> bool {
157        !self.is_none()
158    }
159
160    pub fn is_none(&self) -> bool {
161        *self == Self::NONE
162    }
163
164    pub fn unwrap(&self) -> Hash {
165        self.get().unwrap()
166    }
167
168    pub fn clear(&mut self) {
169        *self = Self::NONE;
170    }
171}
172
173impl PartialEq<Hash> for OptionalHash {
174    fn eq(&self, hash: &Hash) -> bool {
175        self.0 == hash.0
176    }
177}
178
179impl PartialEq<OptionalHash> for Hash {
180    fn eq(&self, hash: &OptionalHash) -> bool {
181        self.0 == hash.0
182    }
183}
184
185#[test]
186fn none_is_zeros() {
187    assert_eq!(
188        None::<Hash>.to_array().into_array(),
189        [
190            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,
191            0, 0, 0,
192        ]
193    );
194}
195
196#[test]
197fn none_none_is_one() {
198    assert_eq!(
199        None::<Option<Hash>>.to_array().into_array(),
200        [
201            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,
202            0, 0, 1,
203        ]
204    );
205}
206
207#[test]
208fn none_none_none_is_two() {
209    assert_eq!(
210        None::<Option<Option<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, 2,
214        ]
215    );
216}