use crate::MescError;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash)]
pub struct ChainId(String);
impl ChainId {
pub fn to_hex(&self) -> Result<String, MescError> {
let ChainId(chain_id) = self;
if chain_id.starts_with("0x") {
Ok(chain_id.clone())
} else {
match chain_id.parse::<u64>() {
Ok(number) => Ok(format!("0x{:x}", number)),
Err(_) => Err(MescError::IntegrityError("bad chain_id".to_string())),
}
}
}
pub fn to_hex_256(&self) -> Result<String, MescError> {
let ChainId(chain_id) = self;
if chain_id.starts_with("0x") {
Ok(chain_id.clone())
} else {
match chain_id.parse::<u64>() {
Ok(number) => Ok(format!("0x{:016x}", number)),
Err(_) => Err(MescError::IntegrityError("bad chain_id".to_string())),
}
}
}
pub fn as_str(&self) -> &str {
let ChainId(chain_id) = self;
chain_id.as_str()
}
}
impl PartialOrd for ChainId {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ChainId {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
let self_string: String = match self.to_hex() {
Ok(s) => s[2..].to_string(),
Err(_) => return std::cmp::Ordering::Greater,
};
let other_string = match other.to_hex() {
Ok(s) => s[2..].to_string(),
Err(_) => return std::cmp::Ordering::Greater,
};
let self_str = format!("{:>079}", self_string);
let other_str = format!("{:>079}", other_string);
self_str.cmp(&other_str)
}
}
impl std::fmt::Display for ChainId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
macro_rules! impl_from_uint_for_chainid {
($($t:ty),*) => {
$(
impl From<$t> for ChainId {
fn from(value: $t) -> ChainId {
ChainId(value.to_string())
}
}
)*
};
}
impl_from_uint_for_chainid!(u8, u16, u32, u64, u128, usize);
pub trait TryIntoChainId {
fn try_into_chain_id(self) -> Result<ChainId, MescError>;
}
impl TryIntoChainId for ChainId {
fn try_into_chain_id(self) -> Result<ChainId, MescError> {
Ok(self)
}
}
impl TryIntoChainId for String {
fn try_into_chain_id(self) -> Result<ChainId, MescError> {
if !self.is_empty() && self.chars().all(|c| c.is_ascii_digit()) {
Ok(ChainId(self))
} else {
Err(MescError::InvalidChainId(self))
}
}
}
impl TryIntoChainId for &str {
fn try_into_chain_id(self) -> Result<ChainId, MescError> {
if self.chars().all(|c| c.is_ascii_digit()) {
Ok(ChainId(self.to_string()))
} else {
Err(MescError::InvalidChainId(self.to_string()))
}
}
}
macro_rules! impl_try_into_chain_id_for_integer {
($($t:ty),*) => {
$(
impl TryIntoChainId for $t {
fn try_into_chain_id(self) -> Result<ChainId, MescError> {
Ok(ChainId(self.to_string()))
}
}
)*
};
}
impl_try_into_chain_id_for_integer!(u8, u16, u32, u64, u128, usize);
impl TryIntoChainId for &[u8] {
fn try_into_chain_id(self) -> Result<ChainId, MescError> {
Err(MescError::NotImplemented("binary chain_id".to_string()))
}
}