upend/src/addressing.rs

105 lines
2.9 KiB
Rust
Raw Normal View History

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};
use serde::export::Formatter;
use thiserror::private::DisplayAsDisplay;
2020-09-07 21:21:54 +02:00
#[derive(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]);
2020-09-14 01:16:01 +02:00
result.write_all(encode::u128(hash_func_type, &mut encode::u128_buffer()))?;
result.write_all(encode::usize(digest.len(), &mut encode::usize_buffer()))?;
result.write_all(digest.as_slice())?;
2020-09-07 21:21:54 +02:00
Ok(result.get_ref().clone())
}
2020-09-14 01:16:01 +02:00
pub fn decode(buffer: &[u8]) -> Result<Self> {
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)?))
}
}
impl std::fmt::Debug for Address {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_display())
}
}
2020-09-07 21:21:54 +02:00
#[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()));
}
}