use std::convert::TryInto; use std::io::prelude::*; use std::io::Cursor; use anyhow::{anyhow, Result}; use unsigned_varint::encode; use uuid::Uuid; use crate::hash::{encode, Hash}; #[derive(Debug, Clone, PartialEq)] pub enum Address { Hash(Hash), UUID(Uuid), } // multihash KangarooTwelve const KANGAROO_TWELVE: u128 = 0x1d01; // multihash identity const IDENTITY: u128 = 0x00; impl Address { pub fn encode(&self) -> Result> { let (hash_func_type, digest) = match self { Self::Hash(hash) => (KANGAROO_TWELVE, hash.0.clone()), Self::UUID(uuid) => (IDENTITY, uuid.as_bytes().to_vec()), }; let mut result = Cursor::new(vec![0u8; 0]); result.write(encode::u128(hash_func_type, &mut encode::u128_buffer()))?; result.write(encode::usize(digest.len(), &mut encode::usize_buffer()))?; result.write(digest.as_slice())?; Ok(result.get_ref().clone()) } pub fn decode(buffer: &Vec) -> Result { let (hash_func_type, rest) = unsigned_varint::decode::u128(buffer)?; let (digest_len, rest) = unsigned_varint::decode::usize(rest)?; let digest = rest; if digest_len != digest.len() { Err(anyhow!( "Actual digest length does not match declared digest length." )) } else { match hash_func_type { KANGAROO_TWELVE => Ok(Self::Hash(Hash(Vec::from(digest)))), IDENTITY => Ok(Self::UUID(uuid::Uuid::from_bytes( TryInto::<[u8; 16]>::try_into(digest).unwrap(), ))), _ => Err(anyhow!("Unknown hash function type.")), } } } } impl std::fmt::Display for Address { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", encode(self.encode().map_err(|_| std::fmt::Error)?)) } } #[cfg(test)] mod tests { use uuid::Uuid; use crate::addressing::Address; use crate::hash::Hash; #[test] fn test_hash_codec() { let addr = Address::Hash(Hash(vec![1, 2, 3, 4, 5])); let encoded = addr.encode(); assert!(encoded.is_ok()); let decoded = Address::decode(&encoded.unwrap()); assert!(decoded.is_ok()); assert_eq!(format!("{}", addr), format!("{}", decoded.unwrap())); } #[test] fn test_uuid_codec() { let addr = Address::UUID(Uuid::new_v4()); let encoded = addr.encode(); assert!(encoded.is_ok()); let decoded = Address::decode(&encoded.unwrap()); assert!(decoded.is_ok()); assert_eq!(format!("{}", addr), format!("{}", decoded.unwrap())); } }