use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::fmt;
use std::ops::Deref;
use crate::binary::Binary;
#[derive(
Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, JsonSchema,
)]
pub struct Addr(String);
impl Addr {
pub fn unchecked(input: impl Into<String>) -> Addr {
Addr(input.into())
}
#[inline]
pub fn as_str(&self) -> &str {
self.0.as_str()
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}
#[inline]
pub fn into_string(self) -> String {
self.0
}
}
impl fmt::Display for Addr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.0)
}
}
impl AsRef<str> for Addr {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl PartialEq<&str> for Addr {
fn eq(&self, rhs: &&str) -> bool {
self.0 == *rhs
}
}
impl PartialEq<Addr> for &str {
fn eq(&self, rhs: &Addr) -> bool {
*self == rhs.0
}
}
impl PartialEq<String> for Addr {
fn eq(&self, rhs: &String) -> bool {
&self.0 == rhs
}
}
impl PartialEq<Addr> for String {
fn eq(&self, rhs: &Addr) -> bool {
self == &rhs.0
}
}
impl From<Addr> for String {
fn from(addr: Addr) -> Self {
addr.0
}
}
impl From<&Addr> for String {
fn from(addr: &Addr) -> Self {
addr.0.clone()
}
}
impl From<Addr> for Cow<'_, Addr> {
fn from(addr: Addr) -> Self {
Cow::Owned(addr)
}
}
impl<'a> From<&'a Addr> for Cow<'a, Addr> {
fn from(addr: &'a Addr) -> Self {
Cow::Borrowed(addr)
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, JsonSchema)]
pub struct CanonicalAddr(pub Binary);
impl From<&[u8]> for CanonicalAddr {
fn from(source: &[u8]) -> Self {
Self(source.into())
}
}
impl From<Vec<u8>> for CanonicalAddr {
fn from(source: Vec<u8>) -> Self {
Self(source.into())
}
}
impl From<CanonicalAddr> for Vec<u8> {
fn from(source: CanonicalAddr) -> Vec<u8> {
source.0.into()
}
}
impl Deref for CanonicalAddr {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl CanonicalAddr {
pub fn as_slice(&self) -> &[u8] {
self.0.as_slice()
}
}
impl fmt::Display for CanonicalAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for byte in self.0.as_slice() {
write!(f, "{:02X}", byte)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::hash_map::DefaultHasher;
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
#[test]
fn addr_unchecked_works() {
let a = Addr::unchecked("123");
let aa = Addr::unchecked(String::from("123"));
let b = Addr::unchecked("be");
assert_eq!(a, aa);
assert_ne!(a, b);
}
#[test]
fn addr_as_str_works() {
let addr = Addr::unchecked("literal-string");
assert_eq!(addr.as_str(), "literal-string");
}
#[test]
fn addr_as_bytes_works() {
let addr = Addr::unchecked("literal-string");
assert_eq!(
addr.as_bytes(),
[108, 105, 116, 101, 114, 97, 108, 45, 115, 116, 114, 105, 110, 103]
);
}
#[test]
fn addr_implements_display() {
let addr = Addr::unchecked("cos934gh9034hg04g0h134");
let embedded = format!("Address: {}", addr);
assert_eq!(embedded, "Address: cos934gh9034hg04g0h134");
assert_eq!(addr.to_string(), "cos934gh9034hg04g0h134");
}
#[test]
fn addr_implements_as_ref_for_str() {
let addr = Addr::unchecked("literal-string");
assert_eq!(addr.as_ref(), "literal-string");
}
#[test]
fn addr_implements_partial_eq_with_str() {
let addr = Addr::unchecked("cos934gh9034hg04g0h134");
assert_eq!(addr, "cos934gh9034hg04g0h134");
assert_eq!("cos934gh9034hg04g0h134", addr);
}
#[test]
fn addr_implements_partial_eq_with_string() {
let addr = Addr::unchecked("cos934gh9034hg04g0h134");
assert_eq!(addr, String::from("cos934gh9034hg04g0h134"));
assert_eq!(String::from("cos934gh9034hg04g0h134"), addr);
}
#[test]
fn addr_implements_into_string() {
let addr = Addr::unchecked("cos934gh9034hg04g0h134");
let string: String = addr.into();
assert_eq!(string, "cos934gh9034hg04g0h134");
let addr = Addr::unchecked("cos934gh9034hg04g0h134");
let addr_ref = &addr;
let string: String = addr_ref.into();
assert_eq!(string, "cos934gh9034hg04g0h134");
}
#[test]
fn canonical_addr_from_slice() {
let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
let canonical_addr_slice = CanonicalAddr::from(bytes);
assert_eq!(canonical_addr_slice.as_slice(), &[0u8, 187, 61, 11, 250, 0]);
let bytes: Vec<u8> = vec![0u8, 187, 61, 11, 250, 0];
let canonical_addr_vec = CanonicalAddr::from(bytes);
assert_eq!(canonical_addr_vec.as_slice(), &[0u8, 187, 61, 11, 250, 0]);
}
#[test]
fn canonical_addr_from_vec_works() {
let original = vec![0u8, 187, 61, 11, 250, 0];
let original_ptr = original.as_ptr();
let addr: CanonicalAddr = original.into();
assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
assert_eq!((addr.0).0.as_ptr(), original_ptr, "must not be copied");
let original = vec![0u8, 187, 61, 11, 250, 0];
let original_ptr = original.as_ptr();
let addr = CanonicalAddr::from(original);
assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
assert_eq!((addr.0).0.as_ptr(), original_ptr, "must not be copied");
}
#[test]
fn canonical_addr_into_vec_works() {
let original = CanonicalAddr::from(vec![0u8, 187, 61, 11, 250, 0]);
let original_ptr = (original.0).0.as_ptr();
let vec: Vec<u8> = original.into();
assert_eq!(vec.as_slice(), [0u8, 187, 61, 11, 250, 0]);
assert_eq!(vec.as_ptr(), original_ptr, "must not be copied");
let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]);
let original_ptr = (original.0).0.as_ptr();
let vec = Vec::<u8>::from(original);
assert_eq!(vec.as_slice(), [7u8, 35, 49, 101, 0, 255]);
assert_eq!(vec.as_ptr(), original_ptr, "must not be copied");
}
#[test]
fn canonical_addr_len() {
let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
let canonical_addr = CanonicalAddr::from(bytes);
assert_eq!(canonical_addr.len(), bytes.len());
}
#[test]
fn canonical_addr_is_empty() {
let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
let canonical_addr = CanonicalAddr::from(bytes);
assert!(!canonical_addr.is_empty());
let empty_canonical_addr = CanonicalAddr::from(vec![]);
assert!(empty_canonical_addr.is_empty());
}
#[test]
fn canonical_addr_implements_display() {
let bytes: &[u8] = &[
0x12, 0x03, 0xab, 0x00, 0xff,
];
let address = CanonicalAddr::from(bytes);
let embedded = format!("Address: {}", address);
assert_eq!(embedded, "Address: 1203AB00FF");
assert_eq!(address.to_string(), "1203AB00FF");
}
#[test]
fn canonical_addr_implements_deref() {
let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
let canonical_addr = CanonicalAddr::from(bytes);
assert_eq!(*canonical_addr, [0u8, 187, 61, 11, 250, 0]);
let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
let canonical_addr = CanonicalAddr::from(bytes);
assert_eq!(canonical_addr.len(), 6);
let canonical_addr_slice: &[u8] = &canonical_addr;
assert_eq!(canonical_addr_slice, &[0u8, 187, 61, 11, 250, 0]);
}
#[test]
fn canonical_addr_implements_hash() {
let alice1 = CanonicalAddr(Binary::from([0, 187, 61, 11, 250, 0]));
let mut hasher = DefaultHasher::new();
alice1.hash(&mut hasher);
let alice1_hash = hasher.finish();
let alice2 = CanonicalAddr(Binary::from([0, 187, 61, 11, 250, 0]));
let mut hasher = DefaultHasher::new();
alice2.hash(&mut hasher);
let alice2_hash = hasher.finish();
let bob = CanonicalAddr(Binary::from([16, 21, 33, 0, 255, 9]));
let mut hasher = DefaultHasher::new();
bob.hash(&mut hasher);
let bob_hash = hasher.finish();
assert_eq!(alice1_hash, alice2_hash);
assert_ne!(alice1_hash, bob_hash);
}
#[test]
fn canonical_addr_can_be_used_in_hash_set() {
let alice1 = CanonicalAddr(Binary::from([0, 187, 61, 11, 250, 0]));
let alice2 = CanonicalAddr(Binary::from([0, 187, 61, 11, 250, 0]));
let bob = CanonicalAddr(Binary::from([16, 21, 33, 0, 255, 9]));
let mut set = HashSet::new();
set.insert(alice1.clone());
set.insert(alice2.clone());
set.insert(bob.clone());
assert_eq!(set.len(), 2);
let set1 = HashSet::<CanonicalAddr>::from_iter(vec![bob.clone(), alice1.clone()]);
let set2 = HashSet::from_iter(vec![alice1, alice2, bob]);
assert_eq!(set1, set2);
}
fn flexible<'a>(a: impl Into<Cow<'a, Addr>>) -> String {
a.into().into_owned().to_string()
}
#[test]
fn addr_into_cow() {
let value = "wasmeucn0ur0ncny2308ry";
let addr = Addr::unchecked(value);
assert_eq!(value, &flexible(&addr));
assert_eq!(value, &flexible(addr));
}
}