1use crate::*;
2
3use base58::{FromBase58, ToBase58};
4use generic_array::typenum::{marker_traits::Unsigned, U32};
5use generic_array::GenericArray;
6use std::fmt;
7use std::hash::{Hash, Hasher};
8use std::str::FromStr;
9
10#[derive(Copy, Clone, PartialOrd, PartialEq, Ord, Eq)]
12pub struct HashValue(GenericArray<u8, U32>);
13pub const HASH_VALUE_LEN: usize = 32;
14
15impl std::fmt::Debug for HashValue {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 write!(f, "HashValue: {}", hex::encode(self.0.as_slice()))
18 }
19}
20
21impl From<GenericArray<u8, U32>> for HashValue {
22 fn from(hash: GenericArray<u8, U32>) -> Self {
23 Self(hash)
24 }
25}
26
27impl From<HashValue> for GenericArray<u8, U32> {
28 fn from(hash: HashValue) -> Self {
29 hash.0
30 }
31}
32
33impl AsRef<GenericArray<u8, U32>> for HashValue {
34 fn as_ref(&self) -> &GenericArray<u8, U32> {
35 &self.0
36 }
37}
38
39impl Default for HashValue {
40 fn default() -> Self {
41 Self(GenericArray::default())
42 }
43}
44
45impl RawFixedBytes for HashValue {
46 fn raw_bytes() -> Option<usize> {
47 Some(U32::to_usize())
48 }
49}
50
51impl RawEncode for HashValue {
52 fn raw_measure(&self, _purpose: &Option<RawEncodePurpose>) -> BuckyResult<usize> {
53 Ok(U32::to_usize())
54 }
55 fn raw_encode<'a>(
56 &self,
57 buf: &'a mut [u8],
58 _purpose: &Option<RawEncodePurpose>,
59 ) -> BuckyResult<&'a mut [u8]> {
60 let bytes = Self::raw_bytes().unwrap();
61 if buf.len() < bytes {
62 let msg = format!(
63 "not enough buffer for encode HashValue, except={}, got={}",
64 bytes,
65 buf.len()
66 );
67 error!("{}", msg);
68
69 return Err(BuckyError::new(BuckyErrorCode::OutOfLimit, msg));
70 }
71 unsafe {
72 std::ptr::copy(self.0.as_slice().as_ptr(), buf.as_mut_ptr(), bytes);
73 }
74
75 Ok(&mut buf[bytes..])
76 }
77}
78
79impl<'de> RawDecode<'de> for HashValue {
80 fn raw_decode(buf: &'de [u8]) -> BuckyResult<(Self, &'de [u8])> {
81 let bytes = Self::raw_bytes().unwrap();
82 if buf.len() < bytes {
83 let msg = format!(
84 "not enough buffer for decode HashValue, except={}, got={}",
85 bytes,
86 buf.len()
87 );
88 error!("{}", msg);
89
90 return Err(BuckyError::new(BuckyErrorCode::OutOfLimit, msg));
91 }
92 let mut hash = GenericArray::default();
93 unsafe {
94 std::ptr::copy(buf.as_ptr(), hash.as_mut_slice().as_mut_ptr(), bytes);
95 }
96 Ok((Self(hash), &buf[bytes..]))
97 }
98}
99
100impl From<&[u8; 32]> for HashValue {
101 fn from(hash: &[u8; 32]) -> Self {
102 Self(GenericArray::clone_from_slice(hash))
103 }
104}
105
106impl TryFrom<&[u8]> for HashValue {
107 type Error = BuckyError;
108 fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
109 if v.len() != 32 {
110 let msg = format!(
111 "HashValue expected bytes of length {} but it was {}",
112 32,
113 v.len()
114 );
115 error!("{}", msg);
116 return Err(BuckyError::new(BuckyErrorCode::InvalidData, msg));
117 }
118
119 let ar: [u8; 32] = v.try_into().unwrap();
120 Ok(Self(GenericArray::from(ar)))
121 }
122}
123
124impl TryFrom<Vec<u8>> for HashValue {
125 type Error = BuckyError;
126 fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
127 if v.len() != 32 {
128 let msg = format!(
129 "HashValue expected bytes of length {} but it was {}",
130 32,
131 v.len()
132 );
133 error!("{}", msg);
134 return Err(BuckyError::new(BuckyErrorCode::InvalidData, msg));
135 }
136
137 let ar: [u8; 32] = v.try_into().unwrap();
138 Ok(Self(GenericArray::from(ar)))
139 }
140}
141
142impl HashValue {
143 pub fn as_slice(&self) -> &[u8] {
144 self.0.as_slice()
145 }
146
147 pub fn as_mut_slice(&mut self) -> &mut [u8] {
148 self.0.as_mut_slice()
149 }
150
151 pub fn len() -> usize {
152 HASH_VALUE_LEN
153 }
154
155 pub fn to_hex_string(&self) -> String {
156 hex::encode(self.0.as_slice())
157 }
158
159 pub fn from_hex_string(s: &str) -> BuckyResult<Self> {
160 let ret = hex::decode(s).map_err(|e| {
161 let msg = format!("invalid hash value hex string: {}, {}", s, e);
162 error!("{}", msg);
163 BuckyError::new(BuckyErrorCode::InvalidFormat, msg)
164 })?;
165
166 Self::clone_from_slice(&ret)
167 }
168
169 pub fn to_base58(&self) -> String {
170 self.0.to_base58()
171 }
172
173 pub fn from_base58(s: &str) -> BuckyResult<Self> {
174 let buf = s.from_base58().map_err(|e| {
175 let msg = format!("convert base58 str to hashvalue failed, str={}, {:?}", s, e);
176 error!("{}", msg);
177 BuckyError::new(BuckyErrorCode::InvalidFormat, msg)
178 })?;
179
180 if buf.len() != 32 {
181 let msg = format!(
182 "convert base58 str to hashvalue failed, len unmatch: str={}",
183 s
184 );
185 return Err(BuckyError::new(BuckyErrorCode::InvalidFormat, msg));
186 }
187
188 Ok(Self::try_from(buf).unwrap())
189 }
190
191 pub fn clone_from_slice(hash: &[u8]) -> BuckyResult<Self> {
192 Self::try_from(hash)
193 }
194}
195
196impl std::fmt::Display for HashValue {
197 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 write!(f, "{}", self.to_hex_string())
199 }
200}
201
202impl FromStr for HashValue {
203 type Err = BuckyError;
204 fn from_str(s: &str) -> BuckyResult<Self> {
205 if s.len() == 64 {
206 Self::from_hex_string(s)
207 } else {
208 Self::from_base58(s)
209 }
210 }
211}
212
213impl Hash for HashValue {
214 fn hash<H: Hasher>(&self, state: &mut H) {
215 let mut buff = [0 as u8; 32];
216 let _ = self.raw_encode(buff.as_mut(), &None).unwrap();
217 state.write(buff.as_ref());
218 }
219}
220
221impl ProtobufTransform<HashValue> for Vec<u8> {
222 fn transform(value: HashValue) -> BuckyResult<Self> {
223 Ok(Vec::from(value.0.as_slice()))
224 }
225}
226
227impl ProtobufTransform<&HashValue> for Vec<u8> {
228 fn transform(value: &HashValue) -> BuckyResult<Self> {
229 Ok(Vec::from(value.0.as_slice()))
230 }
231}
232
233impl ProtobufTransform<Vec<u8>> for HashValue {
234 fn transform(value: Vec<u8>) -> BuckyResult<Self> {
235 if value.len() != HASH_VALUE_LEN {
236 return Err(BuckyError::new(
237 BuckyErrorCode::InvalidParam,
238 format!(
239 "try convert from vec<u8> to named object id failed, invalid len {}",
240 value.len()
241 ),
242 ));
243 }
244 let mut id = Self::default();
245 unsafe {
246 std::ptr::copy(value.as_ptr(), id.as_mut_slice().as_mut_ptr(), value.len());
247 }
248
249 Ok(id)
250 }
251}
252
253#[cfg(test)]
254mod test {
255 use std::str::FromStr;
256
257 use crate::*;
258
259 #[test]
260 fn test() {
261 let hash = hash_data("xxxx".as_bytes());
262 let hex_id = hash.to_hex_string();
263 let base58_id = hash.to_base58();
264
265 println!("{}, {}", hex_id, base58_id);
266
267 let ret = HashValue::from_str(&hex_id).unwrap();
268 let ret2 = HashValue::from_str(&base58_id).unwrap();
269
270 assert_eq!(ret, ret2);
271 }
272}