use super::ConversionError;
use std::{fmt, str::FromStr};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Units {
Wei,
Kwei,
Mwei,
Gwei,
Twei,
Pwei,
Ether,
Other(u32),
}
impl fmt::Display for Units {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad(self.as_num().to_string().as_str())
}
}
impl TryFrom<u32> for Units {
type Error = ConversionError;
fn try_from(value: u32) -> Result<Self, Self::Error> {
Ok(Units::Other(value))
}
}
impl TryFrom<i32> for Units {
type Error = ConversionError;
fn try_from(value: i32) -> Result<Self, Self::Error> {
Ok(Units::Other(value as u32))
}
}
impl TryFrom<usize> for Units {
type Error = ConversionError;
fn try_from(value: usize) -> Result<Self, Self::Error> {
Ok(Units::Other(value as u32))
}
}
impl TryFrom<String> for Units {
type Error = ConversionError;
fn try_from(value: String) -> Result<Self, Self::Error> {
Self::from_str(&value)
}
}
impl<'a> TryFrom<&'a String> for Units {
type Error = ConversionError;
fn try_from(value: &'a String) -> Result<Self, Self::Error> {
Self::from_str(value)
}
}
impl TryFrom<&str> for Units {
type Error = ConversionError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Self::from_str(value)
}
}
impl FromStr for Units {
type Err = ConversionError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s.to_lowercase().as_str() {
"eth" | "ether" => Units::Ether,
"pwei" | "milli" | "milliether" | "finney" => Units::Pwei,
"twei" | "micro" | "microether" | "szabo" => Units::Twei,
"gwei" | "nano" | "nanoether" | "shannon" => Units::Gwei,
"mwei" | "pico" | "picoether" | "lovelace" => Units::Mwei,
"kwei" | "femto" | "femtoether" | "babbage" => Units::Kwei,
"wei" => Units::Wei,
_ => return Err(ConversionError::UnrecognizedUnits(s.to_string())),
})
}
}
impl From<Units> for u32 {
fn from(units: Units) -> Self {
units.as_num()
}
}
impl From<Units> for i32 {
fn from(units: Units) -> Self {
units.as_num() as i32
}
}
impl From<Units> for usize {
fn from(units: Units) -> Self {
units.as_num() as usize
}
}
impl Units {
pub fn as_num(&self) -> u32 {
match self {
Units::Wei => 0,
Units::Kwei => 3,
Units::Mwei => 6,
Units::Gwei => 9,
Units::Twei => 12,
Units::Pwei => 15,
Units::Ether => 18,
Units::Other(inner) => *inner,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use Units::*;
#[test]
fn test_units() {
assert_eq!(Wei.as_num(), 0);
assert_eq!(Kwei.as_num(), 3);
assert_eq!(Mwei.as_num(), 6);
assert_eq!(Gwei.as_num(), 9);
assert_eq!(Twei.as_num(), 12);
assert_eq!(Pwei.as_num(), 15);
assert_eq!(Ether.as_num(), 18);
assert_eq!(Other(10).as_num(), 10);
assert_eq!(Other(20).as_num(), 20);
}
#[test]
fn test_into() {
assert_eq!(Units::try_from("wei").unwrap(), Wei);
assert_eq!(Units::try_from("kwei").unwrap(), Kwei);
assert_eq!(Units::try_from("mwei").unwrap(), Mwei);
assert_eq!(Units::try_from("gwei").unwrap(), Gwei);
assert_eq!(Units::try_from("twei").unwrap(), Twei);
assert_eq!(Units::try_from("pwei").unwrap(), Pwei);
assert_eq!(Units::try_from("ether").unwrap(), Ether);
assert_eq!(Units::try_from("wei".to_string()).unwrap(), Wei);
assert_eq!(Units::try_from("kwei".to_string()).unwrap(), Kwei);
assert_eq!(Units::try_from("mwei".to_string()).unwrap(), Mwei);
assert_eq!(Units::try_from("gwei".to_string()).unwrap(), Gwei);
assert_eq!(Units::try_from("twei".to_string()).unwrap(), Twei);
assert_eq!(Units::try_from("pwei".to_string()).unwrap(), Pwei);
assert_eq!(Units::try_from("ether".to_string()).unwrap(), Ether);
assert_eq!(Units::try_from(&"wei".to_string()).unwrap(), Wei);
assert_eq!(Units::try_from(&"kwei".to_string()).unwrap(), Kwei);
assert_eq!(Units::try_from(&"mwei".to_string()).unwrap(), Mwei);
assert_eq!(Units::try_from(&"gwei".to_string()).unwrap(), Gwei);
assert_eq!(Units::try_from(&"twei".to_string()).unwrap(), Twei);
assert_eq!(Units::try_from(&"pwei".to_string()).unwrap(), Pwei);
assert_eq!(Units::try_from(&"ether".to_string()).unwrap(), Ether);
}
}