use std::{
collections::HashMap,
fmt,
fmt::{Formatter, Write},
};
use itertools::Itertools;
use crate::common::address::{Address, address_translation::AddressTranslation};
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Addresses {
Direct(Vec<Address>),
Translated(HashMap<Address, Address>),
}
impl Addresses {
pub fn try_from_address_str(address_str: impl AsRef<str>) -> crate::Result<Self> {
let address = address_str.as_ref().parse()?;
Ok(Self::from_address(address))
}
pub fn from_address(address: Address) -> Self {
Self::Direct(Vec::from([address]))
}
pub fn try_from_addresses_str(addresses_str: impl IntoIterator<Item = impl AsRef<str>>) -> crate::Result<Self> {
let addresses: Vec<Address> =
addresses_str.into_iter().map(|address_str| address_str.as_ref().parse()).try_collect()?;
Ok(Self::from_addresses(addresses))
}
pub fn from_addresses(addresses: impl IntoIterator<Item = Address>) -> Self {
Self::Direct(addresses.into_iter().collect())
}
pub fn try_from_translation_str(addresses_str: HashMap<impl AsRef<str>, impl AsRef<str>>) -> crate::Result<Self> {
let mut addresses = HashMap::new();
for (address_key, address_value) in addresses_str.into_iter() {
addresses.insert(address_key.as_ref().parse()?, address_value.as_ref().parse()?);
}
Ok(Self::from_translation(addresses))
}
pub fn from_translation(addresses: HashMap<Address, Address>) -> Self {
Self::Translated(addresses)
}
pub fn len(&self) -> usize {
match self {
Addresses::Direct(vec) => vec.len(),
Addresses::Translated(map) => map.len(),
}
}
pub fn contains(&self, address: &Address) -> bool {
match self {
Addresses::Direct(vec) => vec.contains(address),
Addresses::Translated(map) => map.contains_key(address),
}
}
pub(crate) fn addresses(&self) -> AddressIter<'_> {
match self {
Addresses::Direct(vec) => AddressIter::Direct(vec.iter()),
Addresses::Translated(map) => AddressIter::Translated(map.keys()),
}
}
pub(crate) fn address_translation(&self) -> AddressTranslation {
match self {
Addresses::Direct(addresses) => AddressTranslation::Mapping(
addresses.into_iter().map(|address| (address.clone(), address.clone())).collect(),
),
Addresses::Translated(translation) => AddressTranslation::Mapping(translation.clone()),
}
}
pub(crate) fn exclude_addresses(&mut self, excluded_addresses: &Addresses) {
match self {
Addresses::Direct(addresses) => {
addresses.retain(|address| excluded_addresses.contains(address));
}
Addresses::Translated(translation) => translation.retain(|address, _| excluded_addresses.contains(address)),
}
}
}
impl fmt::Display for Addresses {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Addresses::Direct(addresses) => {
f.write_char('[')?;
for (i, address) in addresses.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
write!(f, "{address}")?;
}
f.write_char(']')
}
Addresses::Translated(translation) => {
f.write_char('{')?;
for (i, (public, private)) in translation.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
write!(f, "{public}: {private}")?;
}
f.write_char('}')
}
}
}
}
impl Default for Addresses {
fn default() -> Self {
Self::Direct(Vec::default())
}
}
pub(crate) enum AddressIter<'a> {
Direct(std::slice::Iter<'a, Address>),
Translated(std::collections::hash_map::Keys<'a, Address, Address>),
}
impl<'a> Iterator for AddressIter<'a> {
type Item = &'a Address;
fn next(&mut self) -> Option<Self::Item> {
match self {
AddressIter::Direct(iter) => iter.next(),
AddressIter::Translated(iter) => iter.next(),
}
}
}