2021-02-19 21:45:33 +01:00
|
|
|
use crate::hash::{decode, encode, Hash};
|
|
|
|
use anyhow::{anyhow, Result};
|
|
|
|
use serde::de::Visitor;
|
|
|
|
use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
|
2020-09-07 21:21:54 +02:00
|
|
|
use std::convert::TryInto;
|
2021-02-19 21:45:33 +01:00
|
|
|
use std::fmt;
|
2020-09-07 21:21:54 +02:00
|
|
|
use std::io::prelude::*;
|
|
|
|
use std::io::Cursor;
|
2021-02-07 20:18:55 +01:00
|
|
|
use std::str::FromStr;
|
2021-02-18 19:20:52 +01:00
|
|
|
use thiserror::private::DisplayAsDisplay;
|
2021-02-19 21:45:33 +01:00
|
|
|
use unsigned_varint::encode;
|
|
|
|
use uuid::Uuid;
|
2020-09-07 21:21:54 +02:00
|
|
|
|
2020-09-12 22:50:14 +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> {
|
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() {
|
2021-02-19 22:18:31 +01:00
|
|
|
Err(anyhow!(format!(
|
|
|
|
"Actual digest length ({}) does not match declared digest length ({}).",
|
|
|
|
digest.len(),
|
|
|
|
digest_len
|
|
|
|
)))
|
2020-09-07 21:21:54 +02:00
|
|
|
} 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.")),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-19 21:45:33 +01:00
|
|
|
impl Serialize for Address {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
|
|
|
serializer.serialize_str(encode(self.encode().map_err(ser::Error::custom)?).as_str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct AddressVisitor;
|
|
|
|
|
|
|
|
impl<'de> Visitor<'de> for AddressVisitor {
|
|
|
|
type Value = Address;
|
|
|
|
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
formatter.write_str("a valid UpEnd address (hash/UUID) as a multi-hashed string")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_str<E>(self, str: &str) -> Result<Self::Value, E>
|
|
|
|
where
|
|
|
|
E: de::Error,
|
|
|
|
{
|
|
|
|
let bytes = decode(str).map_err(de::Error::custom)?;
|
|
|
|
Ok(Address::decode(bytes.as_ref()).map_err(de::Error::custom)?)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'de> Deserialize<'de> for Address {
|
|
|
|
fn deserialize<D>(deserializer: D) -> Result<Address, D::Error>
|
|
|
|
where
|
|
|
|
D: Deserializer<'de>,
|
|
|
|
{
|
|
|
|
deserializer.deserialize_str(AddressVisitor)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-07 20:18:55 +01:00
|
|
|
impl FromStr for Address {
|
|
|
|
type Err = anyhow::Error;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
2021-02-19 22:35:05 +01:00
|
|
|
Address::decode(decode(s)?.as_ref())
|
2021-02-07 20:18:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-07 21:21:54 +02:00
|
|
|
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)?))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-12 22:50:14 +02:00
|
|
|
impl std::fmt::Debug for Address {
|
2021-02-18 19:20:52 +01:00
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
2020-09-12 22:50:14 +02:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
}
|