use alloc::string::{String, ToString};
use core::fmt;
use super::v1;
use crate::Felt;
use crate::account::account_id::AccountIdPrefixV1;
use crate::account::{AccountIdVersion, AccountType};
use crate::errors::AccountIdError;
use crate::utils::serde::{
ByteReader,
ByteWriter,
Deserializable,
DeserializationError,
Serializable,
};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum AccountIdPrefix {
V1(AccountIdPrefixV1),
}
impl AccountIdPrefix {
pub const SERIALIZED_SIZE: usize = 8;
pub fn new_unchecked(prefix: Felt) -> Self {
match v1::extract_version(prefix.as_canonical_u64())
.expect("prefix should contain a valid account ID version")
{
AccountIdVersion::Version1 => Self::V1(AccountIdPrefixV1::new_unchecked(prefix)),
}
}
pub fn new(prefix: Felt) -> Result<Self, AccountIdError> {
match v1::extract_version(prefix.as_canonical_u64())? {
AccountIdVersion::Version1 => AccountIdPrefixV1::new(prefix).map(Self::V1),
}
}
pub const fn as_felt(&self) -> Felt {
match self {
AccountIdPrefix::V1(id_prefix) => id_prefix.as_felt(),
}
}
pub fn as_u64(&self) -> u64 {
match self {
AccountIdPrefix::V1(id_prefix) => id_prefix.as_u64(),
}
}
pub fn account_type(&self) -> AccountType {
match self {
AccountIdPrefix::V1(id_prefix) => id_prefix.account_type(),
}
}
pub fn is_public(&self) -> bool {
self.account_type().is_public()
}
pub fn is_private(&self) -> bool {
self.account_type().is_private()
}
pub fn version(&self) -> AccountIdVersion {
match self {
AccountIdPrefix::V1(_) => AccountIdVersion::Version1,
}
}
pub fn to_hex(self) -> String {
match self {
AccountIdPrefix::V1(id_prefix) => id_prefix.to_hex(),
}
}
}
impl From<AccountIdPrefixV1> for AccountIdPrefix {
fn from(id: AccountIdPrefixV1) -> Self {
Self::V1(id)
}
}
impl From<AccountIdPrefix> for Felt {
fn from(id: AccountIdPrefix) -> Self {
match id {
AccountIdPrefix::V1(id_prefix) => id_prefix.into(),
}
}
}
impl From<AccountIdPrefix> for [u8; 8] {
fn from(id: AccountIdPrefix) -> Self {
match id {
AccountIdPrefix::V1(id_prefix) => id_prefix.into(),
}
}
}
impl From<AccountIdPrefix> for u64 {
fn from(id: AccountIdPrefix) -> Self {
match id {
AccountIdPrefix::V1(id_prefix) => id_prefix.into(),
}
}
}
impl TryFrom<[u8; 8]> for AccountIdPrefix {
type Error = AccountIdError;
fn try_from(value: [u8; 8]) -> Result<Self, Self::Error> {
let metadata_byte = value[7];
let version = v1::extract_version(metadata_byte as u64)?;
match version {
AccountIdVersion::Version1 => AccountIdPrefixV1::try_from(value).map(Self::V1),
}
}
}
impl TryFrom<u64> for AccountIdPrefix {
type Error = AccountIdError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
let element = Felt::try_from(value).map_err(|err| {
AccountIdError::AccountIdInvalidPrefixFieldElement(DeserializationError::InvalidValue(
err.to_string(),
))
})?;
Self::new(element)
}
}
impl TryFrom<Felt> for AccountIdPrefix {
type Error = AccountIdError;
fn try_from(element: Felt) -> Result<Self, Self::Error> {
Self::new(element)
}
}
impl PartialOrd for AccountIdPrefix {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for AccountIdPrefix {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
u64::from(*self).cmp(&u64::from(*other))
}
}
impl fmt::Display for AccountIdPrefix {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl Serializable for AccountIdPrefix {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
match self {
AccountIdPrefix::V1(id_prefix) => id_prefix.write_into(target),
}
}
fn get_size_hint(&self) -> usize {
match self {
AccountIdPrefix::V1(id_prefix) => id_prefix.get_size_hint(),
}
}
}
impl Deserializable for AccountIdPrefix {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
<[u8; 8]>::read_from(source)?
.try_into()
.map_err(|err: AccountIdError| DeserializationError::InvalidValue(err.to_string()))
}
}