2020-09-07 21:21:54 +02:00
|
|
|
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};
|
|
|
|
|
2020-09-12 14:27:45 +02:00
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
2020-09-07 21:21:54 +02:00
|
|
|
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<Vec<u8>> {
|
|
|
|
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<u8>) -> Result<Self> {
|
2020-09-12 14:27:45 +02:00
|
|
|
let (hash_func_type, rest) = unsigned_varint::decode::u128(buffer)?;
|
|
|
|
let (digest_len, rest) = unsigned_varint::decode::usize(rest)?;
|
2020-09-07 21:21:54 +02:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
}
|