object_rainbow/
hash.rs

1use std::ops::Add;
2
3use typenum::{Add1, B0, B1, ToInt, U0, U1};
4
5use crate::*;
6
7#[derive(
8    Debug,
9    ToOutput,
10    InlineOutput,
11    Tagged,
12    ListHashes,
13    Topological,
14    ParseAsInline,
15    Clone,
16    Copy,
17    PartialEq,
18    Eq,
19    PartialOrd,
20    Ord,
21    Hash,
22    Size,
23)]
24pub struct Hash([u8; HASH_SIZE]);
25
26pub struct HashNiche<N>(N);
27
28impl<N: ToInt<u8> + Add<B1>> Niche for HashNiche<N> {
29    type NeedsTag = B0;
30    type N = <Hash as Size>::Size;
31    fn niche() -> GenericArray<u8, Self::N> {
32        let mut niche = GenericArray::default();
33        let last_byte = niche.len() - 1;
34        niche[last_byte] = N::to_int();
35        niche
36    }
37    type Next = SomeNiche<HashNiche<Add1<N>>>;
38}
39
40impl MaybeHasNiche for Hash {
41    type MnArray = SomeNiche<HashNiche<U0>>;
42}
43
44impl<I: ParseInput> ParseInline<I> for Hash {
45    fn parse_inline(input: &mut I) -> crate::Result<Self> {
46        input
47            .parse_inline::<OptionalHash>()?
48            .get()
49            .ok_or(Error::Zero)
50    }
51}
52
53impl Hash {
54    pub(crate) const fn from_sha256(hash: [u8; HASH_SIZE]) -> Self {
55        Self(hash)
56    }
57}
58
59impl Deref for Hash {
60    type Target = [u8; HASH_SIZE];
61
62    fn deref(&self) -> &Self::Target {
63        &self.0
64    }
65}
66
67impl AsRef<[u8]> for Hash {
68    fn as_ref(&self) -> &[u8] {
69        self.as_slice()
70    }
71}
72
73#[derive(
74    Debug,
75    Clone,
76    Copy,
77    PartialEq,
78    Eq,
79    PartialOrd,
80    Ord,
81    Hash,
82    ToOutput,
83    InlineOutput,
84    Parse,
85    ParseInline,
86    Tagged,
87    ListHashes,
88    Topological,
89    Size,
90    Default,
91)]
92pub struct OptionalHash([u8; HASH_SIZE]);
93
94impl MaybeHasNiche for OptionalHash {
95    type MnArray = SomeNiche<HashNiche<U1>>;
96}
97
98impl Equivalent<Option<Hash>> for OptionalHash {
99    fn into_equivalent(self) -> Option<Hash> {
100        self.get()
101    }
102
103    fn from_equivalent(object: Option<Hash>) -> Self {
104        object.map(Self::from).unwrap_or_default()
105    }
106}
107
108impl From<[u8; HASH_SIZE]> for OptionalHash {
109    fn from(hash: [u8; HASH_SIZE]) -> Self {
110        Self(hash)
111    }
112}
113
114impl From<Hash> for OptionalHash {
115    fn from(value: Hash) -> Self {
116        value.0.into()
117    }
118}
119
120impl OptionalHash {
121    pub const NONE: Self = Self([0; HASH_SIZE]);
122
123    pub fn get(&self) -> Option<Hash> {
124        self.is_some().then_some(Hash(self.0))
125    }
126
127    pub fn is_some(&self) -> bool {
128        !self.is_none()
129    }
130
131    pub fn is_none(&self) -> bool {
132        *self == Self::NONE
133    }
134
135    pub(crate) fn unwrap(&self) -> Hash {
136        self.get().unwrap()
137    }
138
139    pub(crate) fn clear(&mut self) {
140        *self = Self::NONE;
141    }
142}
143
144impl PartialEq<Hash> for OptionalHash {
145    fn eq(&self, hash: &Hash) -> bool {
146        self.0 == hash.0
147    }
148}
149
150impl PartialEq<OptionalHash> for Hash {
151    fn eq(&self, hash: &OptionalHash) -> bool {
152        self.0 == hash.0
153    }
154}
155
156#[test]
157fn none_is_zeros() {
158    assert_eq!(
159        None::<Hash>.to_array().into_array(),
160        [
161            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,
162            0, 0, 0,
163        ]
164    );
165}
166
167#[test]
168fn none_none_is_one() {
169    assert_eq!(
170        None::<Option<Hash>>.to_array().into_array(),
171        [
172            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,
173            0, 0, 1,
174        ]
175    );
176}
177
178#[test]
179fn none_none_none_is_two() {
180    assert_eq!(
181        None::<Option<Option<Hash>>>.to_array().into_array(),
182        [
183            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,
184            0, 0, 2,
185        ]
186    );
187}