use super::Error;
use super::util::to_arr;
use hex::{FromHex, ToHex};
use std::{fmt, ops};
use std::str::FromStr;
pub const ADDRESS_BYTES: usize = 20;
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Address(pub [u8; ADDRESS_BYTES]);
impl Address {
pub fn try_from(data: &[u8]) -> Result<Self, Error> {
if data.len() != ADDRESS_BYTES {
return Err(Error::InvalidLength(data.len()));
}
Ok(Address(to_arr(data)))
}
}
impl ops::Deref for Address {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<[u8; ADDRESS_BYTES]> for Address {
fn from(bytes: [u8; ADDRESS_BYTES]) -> Self {
Address(bytes)
}
}
impl FromStr for Address {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() != ADDRESS_BYTES * 2 && !s.starts_with("0x") {
return Err(Error::InvalidHexLength(s.to_string()));
}
let value = if s.starts_with("0x") {
s.split_at(2).1
} else {
s
};
Address::try_from(Vec::from_hex(&value)?.as_slice())
}
}
impl fmt::Display for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "0x{}", self.0.to_hex())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_display_zero_address() {
assert_eq!(
Address::default().to_string(),
"0x0000000000000000000000000000000000000000"
);
}
#[test]
fn should_display_real_address() {
let addr = Address(
[
0x0e,
0x7c,
0x04,
0x51,
0x10,
0xb8,
0xdb,
0xf2,
0x97,
0x65,
0x04,
0x73,
0x80,
0x89,
0x89,
0x19,
0xc5,
0xcb,
0x56,
0xf4,
],
);
assert_eq!(
addr.to_string(),
"0x0e7c045110b8dbf29765047380898919c5cb56f4"
);
}
#[test]
fn should_parse_real_address() {
let addr = Address(
[
0x0e,
0x7c,
0x04,
0x51,
0x10,
0xb8,
0xdb,
0xf2,
0x97,
0x65,
0x04,
0x73,
0x80,
0x89,
0x89,
0x19,
0xc5,
0xcb,
0x56,
0xf4,
],
);
assert_eq!(
"0x0e7c045110b8dbf29765047380898919c5cb56f4"
.parse::<Address>()
.unwrap(),
addr
);
}
#[test]
fn should_parse_real_address_without_prefix() {
let addr = Address(
[
0x0e,
0x7c,
0x04,
0x51,
0x10,
0xb8,
0xdb,
0xf2,
0x97,
0x65,
0x04,
0x73,
0x80,
0x89,
0x89,
0x19,
0xc5,
0xcb,
0x56,
0xf4,
],
);
assert_eq!(
"0e7c045110b8dbf29765047380898919c5cb56f4"
.parse::<Address>()
.unwrap(),
addr
);
}
#[test]
fn should_catch_wrong_address_encoding() {
assert!(
"0x___c045110b8dbf29765047380898919c5cb56f4"
.parse::<Address>()
.is_err()
);
}
#[test]
fn should_catch_wrong_address_insufficient_length() {
assert!(
"0x0e7c045110b8dbf297650473808989"
.parse::<Address>()
.is_err()
);
}
#[test]
fn should_catch_wrong_address_excess_length() {
assert!(
"0x0e7c045110b8dbf29765047380898919c5cb56f400000000"
.parse::<Address>()
.is_err()
);
}
#[test]
fn should_catch_wrong_address_prefix() {
assert!(
"0_0e7c045110b8dbf29765047380898919c5cb56f4"
.parse::<Address>()
.is_err()
);
}
#[test]
fn should_catch_missing_address_prefix() {
assert!("_".parse::<Address>().is_err());
}
#[test]
fn should_catch_empty_address_string() {
assert!("".parse::<Address>().is_err());
}
}