1use crate::*;
2
3use base58::{FromBase58, ToBase58};
4use generic_array::typenum::{marker_traits::Unsigned, U32};
5use generic_array::GenericArray;
6use serde::{Deserialize, Serialize};
7use std::fmt;
8use std::hash::{Hash, Hasher};
9use std::{
10 convert::{Into, TryFrom},
11 str::FromStr,
12};
13
14#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
16pub struct ChunkId(GenericArray<u8, U32>);
17
18impl Default for ChunkId {
19 fn default() -> Self {
20 Self(GenericArray::default())
21 }
22}
23
24impl Hash for ChunkId {
25 fn hash<H: Hasher>(&self, state: &mut H) {
26 let mut buff = [0 as u8; 32];
27 let _ = self.raw_encode(buff.as_mut(), &None).unwrap();
28 state.write(buff.as_ref());
29 }
30}
31
32impl std::fmt::Debug for ChunkId {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 write!(f, "ChunkId: {:?}", self.0.as_slice().to_base58())
35 }
36}
37
38impl std::fmt::Display for ChunkId {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 write!(f, "{}", self.0.as_slice().to_base58())
41 }
42}
43
44impl FromStr for ChunkId {
45 type Err = BuckyError;
46 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
47 if OBJECT_ID_BASE36_RANGE.contains(&s.len()) {
48 Self::from_base36(s)
49 } else {
50 Self::from_base58(s)
51 }
52 }
53}
54
55impl TryFrom<&ObjectId> for ChunkId {
56 type Error = BuckyError;
57
58 fn try_from(id: &ObjectId) -> Result<Self, Self::Error> {
59 let obj_type_code = id.obj_type_code();
60
61 if obj_type_code == ObjectTypeCode::Chunk {
62 Ok(Self(id.as_ref().clone()))
63 } else {
64 Err(
65 BuckyError::new(
66 BuckyErrorCode::InvalidParam,
67 format!("try convert from object id to named object id failed, mismatch obj_type_code, expect obj_type_code is: {}, current obj_type_code is:{}", ObjectTypeCode::Chunk.to_string(), obj_type_code.to_string())
68 )
69 )
70 }
71 }
72}
73
74impl ProtobufTransform<ChunkId> for Vec<u8> {
75 fn transform(value: ChunkId) -> BuckyResult<Self> {
76 Ok(Vec::from(value.0.as_slice()))
77 }
78}
79
80impl ProtobufTransform<&ChunkId> for Vec<u8> {
81 fn transform(value: &ChunkId) -> BuckyResult<Self> {
82 Ok(Vec::from(value.0.as_slice()))
83 }
84}
85
86impl ProtobufTransform<Vec<u8>> for ChunkId {
87 fn transform(value: Vec<u8>) -> BuckyResult<Self> {
88 if value.len() != U32::to_usize() {
89 return Err(BuckyError::new(
90 BuckyErrorCode::InvalidParam,
91 format!(
92 "try convert from vec<u8> to chunk id failed, invalid len {}",
93 value.len()
94 ),
95 ));
96 }
97 let mut id = Self::default();
98 unsafe {
99 std::ptr::copy(value.as_ptr(), id.as_mut_slice().as_mut_ptr(), value.len());
100 }
101
102 Ok(id)
103 }
104}
105
106impl From<[u8; 32]> for ChunkId {
107 fn from(v: [u8; 32]) -> Self {
108 Self(GenericArray::from(v))
109 }
110}
111
112impl From<Vec<u8>> for ChunkId {
113 fn from(v: Vec<u8>) -> Self {
114 let ar: [u8; 32] = v.try_into().unwrap_or_else(|v: Vec<u8>| {
115 panic!(
116 "ChunkId expected a Vec of length {} but it was {}",
117 32,
118 v.len()
119 )
120 });
121
122 Self(GenericArray::from(ar))
123 }
124}
125
126impl From<GenericArray<u8, U32>> for ChunkId {
127 fn from(chunk_id: GenericArray<u8, U32>) -> Self {
128 Self(chunk_id)
129 }
130}
131
132impl From<ChunkId> for GenericArray<u8, U32> {
133 fn from(hash: ChunkId) -> Self {
134 hash.0
135 }
136}
137
138impl AsRef<GenericArray<u8, U32>> for ChunkId {
139 fn as_ref(&self) -> &GenericArray<u8, U32> {
140 &self.0
141 }
142}
143
144impl ChunkId {
145 pub fn as_slice(&self) -> &[u8] {
146 self.0.as_slice()
147 }
148
149 pub fn obj_type_code(&self) -> Option<ObjectTypeCode> {
150 Some(ObjectTypeCode::Chunk)
151 }
152
153 pub fn object_id(&self) -> ObjectId {
154 ObjectId::clone_from_slice(self.as_slice()).unwrap()
155 }
156
157 pub fn as_object_id(&self) -> &ObjectId {
158 unsafe { std::mem::transmute::<&ChunkId, &ObjectId>(&self) }
159 }
160
161 fn as_mut_slice(&mut self) -> &mut [u8] {
162 self.0.as_mut_slice()
163 }
164
165 pub fn to_string(&self) -> String {
166 self.0.as_slice().to_base58()
167 }
168
169 pub fn to_base36(&self) -> String {
170 self.0.as_slice().to_base36()
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 chunk id failed, str:{}, {:?}", s, e);
176 error!("{}", msg);
177 BuckyError::new(BuckyErrorCode::ParseError, msg)
178 })?;
179
180 if buf.len() != U32::to_usize() {
181 let msg = format!(
182 "convert base58 str to chunk id failed, str's len not matched:{}, len:{}",
183 s,
184 buf.len()
185 );
186 return Err(BuckyError::new(BuckyErrorCode::ParseError, msg));
187 }
188
189 Ok(Self::from(buf))
190 }
191
192 pub fn from_base36(s: &str) -> BuckyResult<Self> {
193 let buf = s.from_base36().map_err(|e| {
194 let msg = format!("convert base36 str to chunk id failed, str:{}, {:?}", s, e);
195 error!("{}", msg);
196 BuckyError::new(BuckyErrorCode::ParseError, msg)
197 })?;
198
199 if buf.len() != U32::to_usize() {
200 let msg = format!(
201 "convert base36 str to chunk id failed, str's len not matched:{}, len:{}",
202 s,
203 buf.len()
204 );
205 return Err(BuckyError::new(BuckyErrorCode::ParseError, msg));
206 }
207
208 Ok(Self::from(buf))
209 }
210
211 pub async fn calculate(data: &[u8]) -> BuckyResult<Self> {
212 let hash = hash_data(data);
213 Ok(ChunkId::new(&hash, data.len() as u32))
214 }
215
216 pub fn calculate_sync(data: &[u8]) -> BuckyResult<Self> {
217 let hash = hash_data(data);
218 Ok(ChunkId::new(&hash, data.len() as u32))
219 }
220
221 pub fn new(hash_value: &HashValue, len: u32) -> Self {
222 let hash = hash_value.as_slice();
223
224 let mut id = Self::default();
225 let chunkid = id.as_mut_slice();
226 chunkid[0] = 0b_01000000 | (ObjectTypeCode::Chunk.to_u16() as u8) << 4 >> 2;
227 unsafe {
229 *(chunkid[1..5].as_mut_ptr() as *mut u32) = len;
230 }
231 chunkid[5..].copy_from_slice(&hash[0..27]);
232 id
233 }
234
235 pub fn hash(&self) -> &[u8] {
236 let chunkid = self.as_slice();
237 &chunkid[5..]
238 }
239
240 pub fn len(&self) -> usize {
241 let chunkid = self.as_slice();
242 return unsafe { *(chunkid[1..5].as_ptr() as *const u32) } as usize;
243 }
244}
245
246impl RawFixedBytes for ChunkId {
247 fn raw_bytes() -> Option<usize> {
248 Some(U32::to_usize())
249 }
250}
251
252impl RawEncode for ChunkId {
253 fn raw_measure(&self, _purpose: &Option<RawEncodePurpose>) -> Result<usize, BuckyError> {
254 Ok(U32::to_usize())
255 }
256
257 fn raw_encode<'a>(
258 &self,
259 buf: &'a mut [u8],
260 _purpose: &Option<RawEncodePurpose>,
261 ) -> Result<&'a mut [u8], BuckyError> {
262 let bytes = Self::raw_bytes().unwrap();
263 if buf.len() < bytes {
264 let msg = format!(
265 "not enough buffer for encode ChunkId, except={}, got={}",
266 bytes,
267 buf.len()
268 );
269 error!("{}", msg);
270
271 return Err(BuckyError::new(BuckyErrorCode::OutOfLimit, msg));
272 }
273 unsafe {
274 std::ptr::copy(self.0.as_slice().as_ptr(), buf.as_mut_ptr(), bytes);
275 }
276
277 Ok(&mut buf[bytes..])
278 }
279}
280
281impl<'de> RawDecode<'de> for ChunkId {
282 fn raw_decode(buf: &'de [u8]) -> Result<(Self, &'de [u8]), BuckyError> {
283 let bytes = Self::raw_bytes().unwrap();
284 if buf.len() < bytes {
285 let msg = format!(
286 "not enough buffer for decode ChunkId, except={}, got={}",
287 bytes,
288 buf.len()
289 );
290 error!("{}", msg);
291
292 return Err(BuckyError::new(BuckyErrorCode::OutOfLimit, msg));
293 }
294 let mut _id = Self::default();
295 unsafe {
296 std::ptr::copy(buf.as_ptr(), _id.0.as_mut_slice().as_mut_ptr(), bytes);
297 }
298 Ok((_id, &buf[bytes..]))
299 }
300}
301
302use super::raw_diff::{RawDiff, RawPatch};
303
304impl RawDiff for ChunkId {
305 fn diff_measure(&self, right: &Self) -> BuckyResult<usize> {
306 let data = self.as_ref();
307 let r = right.as_ref();
308 data.diff_measure(r)
309 }
310
311 fn diff<'d>(&self, right: &Self, buf: &'d mut [u8]) -> BuckyResult<&'d mut [u8]> {
312 let size = self.diff_measure(right).map_err(|e| {
313 log::error!("ChunkId::diff error:{}", e);
314 e
315 })?;
316 if buf.len() < size {
317 return Err(BuckyError::new(
318 BuckyErrorCode::OutOfLimit,
319 "[raw_diff] not enough buffer for chunk_id",
320 ));
321 }
322
323 self.as_ref().diff(right.as_ref(), buf)
324 }
325}
326
327impl<'de> RawPatch<'de> for ChunkId {
328 fn patch(self, buf: &'de [u8]) -> BuckyResult<(Self, &'de [u8])> {
329 let data: GenericArray<u8, U32> = self.into();
330 let (data, buf) = data.patch(buf).map_err(|e| {
331 log::error!("ChunkId::patch error:{}", e);
332 e
333 })?;
334 Ok((ChunkId::from(data), buf))
335 }
336}
337
338#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Serialize, Deserialize)]
344pub enum ChunkState {
345 Unknown = 0,
346 NotFound = 1, Pending = 2, OnAir = 3,
349 Ready = 4, Ignore = 5, }
352
353impl ChunkState {
354 pub fn as_u8(&self) -> u8 {
355 u8::from(self)
356 }
357}
358
359impl TryFrom<u8> for ChunkState {
366 type Error = BuckyError;
367
368 fn try_from(value: u8) -> Result<Self, Self::Error> {
369 match value {
370 0 => Ok(ChunkState::Unknown),
371 1 => Ok(ChunkState::NotFound),
372 2 => Ok(ChunkState::Pending),
373 3 => Ok(ChunkState::OnAir),
374 4 => Ok(ChunkState::Ready),
375 5 => Ok(ChunkState::Ignore),
376 _ => {
377 let msg = format!("unknown chunk-state: {}", value);
378 error!("{}", msg);
379 Err(BuckyError::new(BuckyErrorCode::InvalidData, msg))
380 }
381 }
382 }
383}
384
385impl From<ChunkState> for u8 {
386 fn from(value: ChunkState) -> Self {
387 let r = &value;
388 r.into()
389 }
390}
391
392impl From<&ChunkState> for u8 {
393 fn from(value: &ChunkState) -> Self {
394 match value {
395 ChunkState::Unknown => 0,
396 ChunkState::NotFound => 1,
397 ChunkState::Pending => 2,
398 ChunkState::OnAir => 3,
399 ChunkState::Ready => 4,
400 ChunkState::Ignore => 5,
401 }
402 }
403}
404
405#[cfg(test)]
418mod test {
419 use super::ChunkId;
420 use crate::*;
421
422 use std::convert::TryFrom;
423 use std::str::FromStr;
424 use generic_array::typenum::{marker_traits::Unsigned, U32};
425
426 #[test]
427 fn chunk() {
428 let hash = HashValue::default();
429 let chunk_id = ChunkId::new(&hash, 100);
430 let chunk_id_str = chunk_id.to_string();
431 let chunk_id_str2 = chunk_id.as_object_id().to_string();
432 assert_eq!(chunk_id_str, chunk_id_str2);
433 println!("chunk_id_str:{}", chunk_id_str);
434
435 let chunk_id_from_str = ChunkId::from_str(&chunk_id_str).unwrap();
436 println!("chunk_id_from_str:{:?}", chunk_id_from_str);
437
438 assert_eq!(chunk_id.obj_type_code().unwrap(), ObjectTypeCode::Chunk);
439
440 let obj_id = chunk_id.object_id();
442 assert_eq!(obj_id.obj_type_code(), ObjectTypeCode::Chunk);
443
444 {
445 let new_chunk_id = ChunkId::try_from(&obj_id).unwrap();
446 assert_eq!(new_chunk_id, chunk_id);
447 }
448
449 assert_eq!(U32::to_usize(), 32);
450 }
451}