use alloc::string::ToString;
use bech32::Bech32m;
use bech32::primitives::decode::CheckedHrpstring;
use miden_processor::DeserializationError;
use crate::AddressError;
use crate::account::{AccountId, AccountStorageMode};
use crate::address::{AddressType, NetworkId};
use crate::errors::Bech32Error;
use crate::note::NoteTag;
use crate::utils::serde::{ByteWriter, Deserializable, Serializable};
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AddressId {
AccountId(AccountId),
}
impl AddressId {
pub fn address_type(&self) -> AddressType {
match self {
AddressId::AccountId(_) => AddressType::AccountId,
}
}
pub fn default_note_tag_len(&self) -> u8 {
match self {
AddressId::AccountId(id) => {
if id.storage_mode() == AccountStorageMode::Network {
NoteTag::DEFAULT_NETWORK_TAG_LENGTH
} else {
NoteTag::DEFAULT_LOCAL_TAG_LENGTH
}
},
}
}
pub(crate) fn decode(bech32_string: &str) -> Result<(NetworkId, Self), AddressError> {
let checked_string = CheckedHrpstring::new::<Bech32m>(bech32_string).map_err(|source| {
AddressError::Bech32DecodeError(Bech32Error::DecodeError(source.to_string().into()))
})?;
let hrp = checked_string.hrp();
let network_id = NetworkId::from_hrp(hrp);
let mut byte_iter = checked_string.byte_iter();
let address_byte = byte_iter.next().ok_or_else(|| {
AddressError::Bech32DecodeError(Bech32Error::InvalidDataLength {
expected: 1,
actual: byte_iter.len(),
})
})?;
let address_type = AddressType::try_from(address_byte)?;
let identifier = match address_type {
AddressType::AccountId => AccountId::from_bech32_byte_iter(byte_iter)
.map_err(AddressError::AccountIdDecodeError)
.map(AddressId::AccountId)?,
};
Ok((network_id, identifier))
}
}
impl From<AccountId> for AddressId {
fn from(id: AccountId) -> Self {
Self::AccountId(id)
}
}
impl Serializable for AddressId {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
target.write_u8(self.address_type() as u8);
match self {
AddressId::AccountId(id) => {
id.write_into(target);
},
}
}
}
impl Deserializable for AddressId {
fn read_from<R: miden_core::utils::ByteReader>(
source: &mut R,
) -> Result<Self, DeserializationError> {
let address_type: u8 = source.read_u8()?;
let address_type = AddressType::try_from(address_type)
.map_err(|err| DeserializationError::InvalidValue(err.to_string()))?;
match address_type {
AddressType::AccountId => {
let id: AccountId = source.read()?;
Ok(AddressId::AccountId(id))
},
}
}
}