diff --git a/cli/src/addressing.rs b/cli/src/addressing.rs deleted file mode 100644 index 7852574..0000000 --- a/cli/src/addressing.rs +++ /dev/null @@ -1,190 +0,0 @@ -use anyhow::{anyhow, Result}; -use multihash::{Code, Multihash, MultihashDigest}; -use serde::de::Visitor; -use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer}; -use std::fmt; -use std::str::FromStr; -use thiserror::private::DisplayAsDisplay; -use upend_base::hash::{b58_decode, b58_encode, Hash, Hashable}; -use uuid::Uuid; - -#[derive(Clone, Eq, PartialEq, Hash)] -pub enum Address { - Hash(Hash), - Uuid(Uuid), - Attribute(String), - Url(String), -} - -// multihash SHA2-256 -const SHA2_256: u64 = 0x12; -// multihash identity -const IDENTITY: u64 = 0x00; - -impl Address { - pub fn encode(&self) -> Result> { - let hash = match self { - Self::Hash(hash) => Multihash::wrap(SHA2_256, &hash.0).map_err(|err| anyhow!(err))?, - Self::Uuid(uuid) => { - Code::Identity.digest(&[vec![b'U'], uuid.as_bytes().to_vec()].concat()) - } - Self::Attribute(attribute) => { - Code::Identity.digest(&[&[b'A'], attribute.as_bytes()].concat()) - } - Self::Url(url) => Code::Identity.digest(&[&[b'X'], url.as_bytes()].concat()), - }; - - Ok(hash.to_bytes()) - } - - pub fn decode(buffer: &[u8]) -> Result { - let multihash = Multihash::from_bytes(buffer) - .map_err(|err| anyhow!("Error decoding address: {}", err))?; - - match multihash.code() { - SHA2_256 => Ok(Self::Hash(Hash(multihash.digest().to_vec()))), - IDENTITY => { - let digest = multihash.digest().to_owned(); - let digest_content: Vec = digest.clone().into_iter().skip(1).collect(); - match digest[0] { - b'U' => Ok(Self::Uuid(uuid::Uuid::from_slice( - digest_content.as_slice(), - )?)), - b'A' => Ok(Self::Attribute(String::from_utf8(digest_content)?)), - b'X' => Ok(Self::Url(String::from_utf8(digest_content)?)), - _ => Err(anyhow!("Error decoding address: Unknown identity marker.")), - } - } - _ => Err(anyhow!( - "Error decoding address: Unknown hash function type." - )), - } - } -} - -impl Serialize for Address { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer, - { - serializer.serialize_str(b58_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(self, str: &str) -> Result - where - E: de::Error, - { - let bytes = b58_decode(str) - .map_err(|e| de::Error::custom(format!("Error deserializing address: {}", e)))?; - Address::decode(bytes.as_ref()) - .map_err(|e| de::Error::custom(format!("Error deserializing address: {}", e))) - } -} - -impl<'de> Deserialize<'de> for Address { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(AddressVisitor) - } -} - -impl FromStr for Address { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - Address::decode( - b58_decode(s) - .map_err(|e| anyhow!("Error deserializing address: {}", e))? - .as_ref(), - ) - } -} - -impl std::fmt::Display for Address { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - b58_encode(self.encode().map_err(|_| std::fmt::Error)?) - ) - } -} - -impl std::fmt::Debug for Address { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "Address<{}>: {}", - match self { - Address::Hash(_) => "Hash", - Address::Uuid(_) => "UUID", - Address::Attribute(_) => "Attribute", - Address::Url(_) => "URL", - }, - self.as_display() - ) - } -} - -pub trait Addressable: Hashable { - fn address(&self) -> Result
{ - Ok(Address::Hash(self.hash()?)) - } -} - -#[cfg(test)] -mod tests { - use anyhow::Result; - use uuid::Uuid; - - use crate::addressing::Address; - use upend_base::hash::Hash; - - #[test] - fn test_hash_codec() -> Result<()> { - let addr = Address::Hash(Hash(vec![1, 2, 3, 4, 5])); - let encoded = addr.encode()?; - let decoded = Address::decode(&encoded)?; - assert_eq!(addr, decoded); - Ok(()) - } - - #[test] - fn test_uuid_codec() -> Result<()> { - let addr = Address::Uuid(Uuid::new_v4()); - let encoded = addr.encode()?; - let decoded = Address::decode(&encoded)?; - assert_eq!(addr, decoded); - Ok(()) - } - - #[test] - fn test_attribute_codec() -> Result<()> { - let addr = Address::Attribute(String::from("ATTRIBUTE")); - let encoded = addr.encode()?; - let decoded = Address::decode(&encoded)?; - assert_eq!(addr, decoded); - Ok(()) - } - - #[test] - fn test_url_codec() -> Result<()> { - let addr = Address::Url(String::from("https://upend.dev")); - let encoded = addr.encode()?; - let decoded = Address::decode(&encoded)?; - assert_eq!(addr, decoded); - Ok(()) - } -}