use core::convert::TryFrom;
use core::fmt::{Display, Error as FmtError, Formatter};
use ibc_proto::protobuf::Protobuf;
use num_rational::Ratio;
use serde::{Deserialize, Serialize};
use ibc_proto::ibc::lightclients::tendermint::v1::Fraction;
use tendermint::trust_threshold::TrustThresholdFraction;
use crate::core::ics02_client::error::Error;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TrustThreshold(Ratio<u64>);
impl TrustThreshold {
pub const ONE_THIRD: Self = Self(Ratio::new_raw(1, 3));
pub const TWO_THIRDS: Self = Self(Ratio::new_raw(2, 3));
pub const CLIENT_STATE_RESET: Self = Self(Ratio::new_raw(0, 0));
pub fn new(numerator: u64, denominator: u64) -> Result<Self, Error> {
if numerator > denominator || denominator == 0 {
return Err(Error::invalid_trust_threshold(numerator, denominator));
}
Ok(Self(Ratio::new(numerator, denominator)))
}
pub fn numerator(&self) -> u64 {
*self.0.numer()
}
pub fn denominator(&self) -> u64 {
*self.0.denom()
}
}
impl From<TrustThresholdFraction> for TrustThreshold {
fn from(t: TrustThresholdFraction) -> Self {
Self(Ratio::new_raw(t.numerator(), t.denominator()))
}
}
impl TryFrom<TrustThreshold> for TrustThresholdFraction {
type Error = Error;
fn try_from(t: TrustThreshold) -> Result<TrustThresholdFraction, Error> {
TrustThresholdFraction::new(t.numerator(), t.denominator())
.map_err(|_| Error::failed_trust_threshold_conversion(t.numerator(), t.denominator()))
}
}
impl Protobuf<Fraction> for TrustThreshold {}
impl From<TrustThreshold> for Fraction {
fn from(t: TrustThreshold) -> Self {
Fraction {
numerator: t.numerator(),
denominator: t.denominator(),
}
}
}
impl TryFrom<Fraction> for TrustThreshold {
type Error = Error;
fn try_from(value: Fraction) -> Result<Self, Self::Error> {
Self::new(value.numerator, value.denominator)
}
}
impl Default for TrustThreshold {
fn default() -> Self {
Self::ONE_THIRD
}
}
impl Display for TrustThreshold {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(f, "{}/{}", self.numerator(), self.denominator())
}
}
impl Serialize for TrustThreshold {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
#[derive(Serialize)]
struct TrustThreshold {
numerator: u64,
denominator: u64,
}
let tt = TrustThreshold {
numerator: self.numerator(),
denominator: self.denominator(),
};
tt.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for TrustThreshold {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
struct TrustThreshold {
numerator: u64,
denominator: u64,
}
let tt = TrustThreshold::deserialize(deserializer)?;
Self::new(tt.numerator, tt.denominator).map_err(serde::de::Error::custom)
}
}