1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
use bytes::Bytes; use blake2::VarBlake2b; use digest::{Update, VariableOutput}; use serde::ser::{Serialize, Serializer}; use serde::de::{self, Deserialize, Deserializer}; use std::result; #[derive(Debug, Clone, PartialEq)] pub struct Blob { pub id: String, pub bytes: Bytes, } impl Blob { pub fn create(bytes: Bytes) -> Blob { let id = Self::hash(&bytes); Blob { id, bytes, } } pub fn hash(bytes: &[u8]) -> String { let mut h = VarBlake2b::new(32).unwrap(); h.update(bytes); let output = h.finalize_boxed(); Self::encode_hash(&output) } #[inline] fn encode_hash(bytes: &[u8]) -> String { let x = bs58::encode(bytes).into_string(); format!("{:0<44}", x) } } impl Serialize for Blob { #[inline] fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error> where S: Serializer, { let s = base64::encode(&self.bytes); serializer.serialize_str(&s) } } impl<'de> Deserialize<'de> for Blob { #[inline] fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error> where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; let bytes = base64::decode(&s) .map_err(de::Error::custom)?; Ok(Blob::create(Bytes::from(bytes))) } } pub trait BlobState { fn register_blob(&self, blob: Blob) -> String; } #[cfg(test)] mod tests { use super::*; use serde_json; #[inline] fn blob() -> (Bytes, Blob) { let bytes = Bytes::from(&b"asdf"[..]); (bytes.clone(), Blob::create(bytes)) } #[test] fn verify_create_blob() { let (bytes, blob) = blob(); assert_eq!(blob, Blob { id: String::from("DTTV3EjpHBNJx3Zw7eJsVPm4bYXKmNkJQpVNkcvTtTSz"), bytes, }); } #[test] fn test_serialize() { let (_, blob) = blob(); let json = serde_json::to_string(&blob).unwrap(); assert_eq!(&json, "\"YXNkZg==\""); } #[test] fn test_deserialize() { let (_, blob1) = blob(); let blob2: Blob = serde_json::from_str("\"YXNkZg==\"").unwrap(); assert_eq!(blob1, blob2); } #[test] fn test_hash_encoding() { let x = bs58::decode("22es54J4FbFtpb5D1MtBazVuum4TcqCQ7M9JkmYdmJ8W") .into_vec() .unwrap(); let x = Blob::encode_hash(&x); assert_eq!(x.len(), 44); assert_eq!(x, "22es54J4FbFtpb5D1MtBazVuum4TcqCQ7M9JkmYdmJ8W"); } #[test] fn test_hash_encoding_padding() { let x = bs58::decode("r6edvU326yvpXLubYacXXSxf2HzqCgzqHUQvpWyNwei") .into_vec() .unwrap(); let x = Blob::encode_hash(&x); assert_eq!(x.len(), 44); assert_eq!(x, "r6edvU326yvpXLubYacXXSxf2HzqCgzqHUQvpWyNwei0"); } }