1use std::fmt;
5
6use crate::error::{NeoError, NeoResult};
7use crate::NeoByteString;
8
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25pub struct Hash160([u8; 20]);
26
27#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32pub struct Hash256([u8; 32]);
33
34impl Hash160 {
35 pub const LENGTH: usize = 20;
37
38 pub const ZERO: Self = Self([0u8; 20]);
40
41 pub const fn from_bytes(bytes: [u8; 20]) -> Self {
43 Self(bytes)
44 }
45
46 pub fn try_from_slice(slice: &[u8]) -> NeoResult<Self> {
50 let bytes: [u8; 20] = slice.try_into().map_err(|_| {
51 NeoError::Custom(format!(
52 "Hash160 requires exactly 20 bytes, got {}",
53 slice.len()
54 ))
55 })?;
56 Ok(Self(bytes))
57 }
58
59 pub fn as_bytes(&self) -> &[u8; 20] {
61 &self.0
62 }
63
64 pub fn as_slice(&self) -> &[u8] {
66 &self.0
67 }
68
69 pub fn is_zero(&self) -> bool {
71 self.0 == [0u8; 20]
72 }
73
74 pub fn to_byte_string(&self) -> NeoByteString {
76 NeoByteString::from_slice(&self.0)
77 }
78}
79
80impl Hash256 {
81 pub const LENGTH: usize = 32;
83
84 pub const ZERO: Self = Self([0u8; 32]);
86
87 pub const fn from_bytes(bytes: [u8; 32]) -> Self {
89 Self(bytes)
90 }
91
92 pub fn try_from_slice(slice: &[u8]) -> NeoResult<Self> {
96 let bytes: [u8; 32] = slice.try_into().map_err(|_| {
97 NeoError::Custom(format!(
98 "Hash256 requires exactly 32 bytes, got {}",
99 slice.len()
100 ))
101 })?;
102 Ok(Self(bytes))
103 }
104
105 pub fn as_bytes(&self) -> &[u8; 32] {
107 &self.0
108 }
109
110 pub fn as_slice(&self) -> &[u8] {
112 &self.0
113 }
114
115 pub fn is_zero(&self) -> bool {
117 self.0 == [0u8; 32]
118 }
119
120 pub fn to_byte_string(&self) -> NeoByteString {
122 NeoByteString::from_slice(&self.0)
123 }
124}
125
126impl fmt::Display for Hash160 {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 write!(f, "0x")?;
129 for byte in &self.0 {
130 write!(f, "{:02x}", byte)?;
131 }
132 Ok(())
133 }
134}
135
136impl fmt::Display for Hash256 {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 write!(f, "0x")?;
139 for byte in &self.0 {
140 write!(f, "{:02x}", byte)?;
141 }
142 Ok(())
143 }
144}
145
146impl TryFrom<&[u8]> for Hash160 {
147 type Error = NeoError;
148 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
149 Self::try_from_slice(slice)
150 }
151}
152
153impl TryFrom<Vec<u8>> for Hash160 {
154 type Error = NeoError;
155 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
156 Self::try_from_slice(&vec)
157 }
158}
159
160impl TryFrom<NeoByteString> for Hash160 {
161 type Error = NeoError;
162 fn try_from(bs: NeoByteString) -> Result<Self, Self::Error> {
163 Self::try_from_slice(bs.as_slice())
164 }
165}
166
167impl From<Hash160> for NeoByteString {
168 fn from(h: Hash160) -> Self {
169 h.to_byte_string()
170 }
171}
172
173impl TryFrom<&[u8]> for Hash256 {
174 type Error = NeoError;
175 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
176 Self::try_from_slice(slice)
177 }
178}
179
180impl TryFrom<Vec<u8>> for Hash256 {
181 type Error = NeoError;
182 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
183 Self::try_from_slice(&vec)
184 }
185}
186
187impl TryFrom<NeoByteString> for Hash256 {
188 type Error = NeoError;
189 fn try_from(bs: NeoByteString) -> Result<Self, Self::Error> {
190 Self::try_from_slice(bs.as_slice())
191 }
192}
193
194impl From<Hash256> for NeoByteString {
195 fn from(h: Hash256) -> Self {
196 h.to_byte_string()
197 }
198}
199
200impl AsRef<[u8]> for Hash160 {
201 fn as_ref(&self) -> &[u8] {
202 &self.0
203 }
204}
205
206impl AsRef<[u8]> for Hash256 {
207 fn as_ref(&self) -> &[u8] {
208 &self.0
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn hash160_from_valid_bytes() {
218 let bytes = [0xABu8; 20];
219 let h = Hash160::from_bytes(bytes);
220 assert_eq!(h.as_bytes(), &[0xAB; 20]);
221 }
222
223 #[test]
224 fn hash160_try_from_wrong_length_fails() {
225 assert!(Hash160::try_from_slice(&[0u8; 19]).is_err());
226 assert!(Hash160::try_from_slice(&[0u8; 21]).is_err());
227 assert!(Hash160::try_from_slice(&[0u8; 0]).is_err());
228 }
229
230 #[test]
231 fn hash160_try_from_correct_length_succeeds() {
232 let h = Hash160::try_from_slice(&[0xFFu8; 20]).unwrap();
233 assert_eq!(h.as_bytes(), &[0xFF; 20]);
234 }
235
236 #[test]
237 fn hash160_zero() {
238 assert!(Hash160::ZERO.is_zero());
239 assert!(!Hash160::from_bytes([1; 20]).is_zero());
240 }
241
242 #[test]
243 fn hash256_from_valid_bytes() {
244 let bytes = [0xCDu8; 32];
245 let h = Hash256::from_bytes(bytes);
246 assert_eq!(h.as_bytes(), &[0xCD; 32]);
247 }
248
249 #[test]
250 fn hash256_try_from_wrong_length_fails() {
251 assert!(Hash256::try_from_slice(&[0u8; 31]).is_err());
252 assert!(Hash256::try_from_slice(&[0u8; 33]).is_err());
253 }
254
255 #[test]
256 fn hash256_try_from_correct_length_succeeds() {
257 let h = Hash256::try_from_slice(&[0xEEu8; 32]).unwrap();
258 assert_eq!(h.as_bytes(), &[0xEE; 32]);
259 }
260
261 #[test]
262 fn hash256_zero() {
263 assert!(Hash256::ZERO.is_zero());
264 assert!(!Hash256::from_bytes([1; 32]).is_zero());
265 }
266
267 #[test]
268 fn hash160_roundtrip_bytestring() {
269 let h = Hash160::from_bytes([0x42; 20]);
270 let bs: NeoByteString = h.clone().into();
271 let h2 = Hash160::try_from(bs).unwrap();
272 assert_eq!(h, h2);
273 }
274
275 #[test]
276 fn hash256_roundtrip_bytestring() {
277 let h = Hash256::from_bytes([0x42; 32]);
278 let bs: NeoByteString = h.clone().into();
279 let h2 = Hash256::try_from(bs).unwrap();
280 assert_eq!(h, h2);
281 }
282}