use crate::compat::rand::{distributions::Standard, prelude::Distribution, random, Rng};
use crate::compat::{
string::{String, ToString},
vec::Vec,
};
use crate::{AddressParseError, AddressParseErrorKind, Result, TransportType, LOCAL};
use core::fmt::{self, Debug, Display};
use core::ops::Deref;
use core::str::from_utf8;
use minicbor::{Decode, Encode};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Decode, Encode, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
#[rustfmt::skip]
#[cbor(map)] pub struct Address {
#[n(1)] tt: TransportType,
#[n(2)] inner: Vec<u8>,
}
impl Address {
pub fn new<S: Into<String>>(tt: TransportType, data: S) -> Self {
Self {
tt,
inner: data.into().as_bytes().to_vec(),
}
}
pub fn from_string<S: Into<String>>(s: S) -> Self {
match s.into().parse::<Address>() {
Ok(a) => a,
Err(e) => {
panic!("Invalid address string {}", e)
}
}
}
#[doc(hidden)]
pub fn without_type(&self) -> &str {
from_utf8(&self.inner).unwrap_or("<unprintable>")
}
pub fn random(tt: TransportType) -> Self {
Self { tt, ..random() }
}
pub fn random_local() -> Self {
Self {
tt: LOCAL,
..random()
}
}
pub fn random_tagged(_tag: &str) -> Self {
#[cfg(feature = "debugger")]
{
use core::sync::atomic::{AtomicU32, Ordering};
static COUNTER: AtomicU32 = AtomicU32::new(0);
let address = format!("{}_{}", _tag, COUNTER.fetch_add(1, Ordering::Relaxed),).into();
let address = Self {
tt: LOCAL,
..address
};
tracing::trace!("random_tagged => {}", address);
address
}
#[cfg(not(feature = "debugger"))]
Self::random_local()
}
pub fn transport_type(&self) -> TransportType {
self.tt
}
pub fn address(&self) -> &str {
from_utf8(self.inner.as_slice()).unwrap_or("Invalid UTF-8")
}
pub fn is_local(&self) -> bool {
self.tt == LOCAL
}
}
impl core::str::FromStr for Address {
type Err = AddressParseError;
fn from_str(s: &str) -> Result<Address, Self::Err> {
let buf: String = s.into();
let mut vec: Vec<_> = buf.split('#').collect();
if vec.len() == 1 {
Ok(Address {
tt: LOCAL,
inner: vec.remove(0).as_bytes().to_vec(),
})
}
else if vec.len() == 2 {
match str::parse(vec.remove(0)) {
Ok(tt) => Ok(Address {
tt: TransportType::new(tt),
inner: vec.remove(0).as_bytes().to_vec(),
}),
Err(e) => Err(AddressParseError::new(AddressParseErrorKind::InvalidType(
e,
))),
}
} else {
Err(AddressParseError::new(AddressParseErrorKind::MultipleSep))
}
}
}
impl Display for Address {
fn fmt<'a>(&'a self, f: &mut fmt::Formatter) -> fmt::Result {
let inner: &'a str = from_utf8(self.inner.as_slice()).unwrap_or("Invalid UTF-8");
write!(f, "{}#{}", self.tt, inner)
}
}
impl Debug for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<Self as Display>::fmt(self, f)
}
}
impl Deref for Address {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl From<String> for Address {
fn from(s: String) -> Self {
Self::from_string(s)
}
}
impl From<&String> for Address {
fn from(s: &String) -> Self {
Self::from_string(s.as_str())
}
}
impl<'a> From<&'a str> for Address {
fn from(s: &'a str) -> Self {
Self::from_string(s)
}
}
impl From<Vec<u8>> for Address {
fn from(data: Vec<u8>) -> Self {
Self {
tt: LOCAL,
inner: data,
}
}
}
impl From<(TransportType, Vec<u8>)> for Address {
fn from((tt, data): (TransportType, Vec<u8>)) -> Self {
Self { tt, inner: data }
}
}
impl<'a> From<(TransportType, &'a str)> for Address {
fn from((tt, data): (TransportType, &'a str)) -> Self {
Self {
tt,
inner: data.as_bytes().to_vec(),
}
}
}
impl<'a> From<(TransportType, &'a String)> for Address {
fn from((tt, inner): (TransportType, &'a String)) -> Self {
Self::from((tt, inner.as_str()))
}
}
impl From<(TransportType, String)> for Address {
fn from((transport, data): (TransportType, String)) -> Self {
Self::from((transport, data.as_str()))
}
}
impl<'a> From<&'a [u8]> for Address {
fn from(data: &'a [u8]) -> Self {
Self {
tt: LOCAL,
inner: data.to_vec(),
}
}
}
impl<'a> From<&'a [&u8]> for Address {
fn from(data: &'a [&u8]) -> Self {
Self {
tt: LOCAL,
inner: data.iter().map(|x| **x).collect(),
}
}
}
impl From<Address> for String {
fn from(address: Address) -> Self {
address.to_string()
}
}
impl Distribution<Address> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Address {
let address: [u8; 16] = rng.gen();
hex::encode(address).as_bytes().into()
}
}
impl Address {
pub(crate) fn manual_encode(&self, buffer: &mut Vec<u8>) {
buffer.push(self.tt.into());
crate::bare::write_slice(buffer, &self.inner);
}
pub(crate) fn encoded_size(&self) -> usize {
1 + crate::bare::size_of_slice(&self.inner)
}
pub(crate) fn manually_decode(slice: &[u8], index: &mut usize) -> Option<Address> {
if slice.len() - *index < 2 {
return None;
}
let tt = slice[*index];
*index += 1;
let inner = crate::bare::read_slice(slice, index)?;
Some(Address {
tt: TransportType::new(tt),
inner: inner.to_vec(),
})
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::Encodable;
#[test]
fn encode_and_manually_decode_address() {
let super_long_string = "a".repeat(250);
let address = Address::from_string("42#".to_string() + &super_long_string);
assert_eq!(address.address(), super_long_string.as_str());
let encoded = address.clone().encode().unwrap();
let decoded = Address::manually_decode(&encoded, &mut 0).unwrap();
assert_eq!(address, decoded);
}
#[test]
fn parse_addr_simple() {
let addr = Address::from_string("local_friend");
assert_eq!(
addr,
Address {
tt: LOCAL,
inner: "local_friend".as_bytes().to_vec(),
}
);
}
#[test]
fn parse_addr_with_type() {
let addr = Address::from_string("1#remote_friend");
assert_eq!(
addr,
Address {
tt: TransportType::new(1),
inner: "remote_friend".as_bytes().to_vec(),
}
);
}
#[test]
#[should_panic(expected = "Failed to parse address type:")]
fn parse_addr_invalid() {
Address::from_string("#,my_friend");
}
#[test]
#[should_panic(expected = "Invalid address string:")]
fn parse_addr_invalid_multiple_separators() {
let _ = Address::from_string("1#invalid#");
}
}