Repository: unionlabs/union
File: lib/unionlabs/src/ibc/lightclients/tendermint/fraction.rs (Rust)

Code before:
use std::num::{NonZeroU64, TryFromIntError};

use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Fraction {
    pub numerator: u64,
    pub denominator: NonZeroU64,
}

impl From<Fraction> for protos::ibc::lightclients::tendermint::v1::Fraction {
    fn from(value: Fraction) -> Self {
        Self {
            numerator: value.numerator,
            denominator: value.denominator.get(),
        }
    }
}

// Expect non-zero denominator.
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
#[error("zero denominator")]
pub struct ZeroDenominatorError {
    cause: TryFromIntError,
}

impl From<TryFromIntError> for ZeroDenominatorError {
    fn from(value: TryFromIntError) -> Self {
        ZeroDenominatorError { cause: value }
    }
}

impl TryFrom<protos::ibc::lightclients::tendermint::v1::Fraction> for Fraction {
    type Error = ZeroDenominatorError;

    fn try_from(
        value: protos::ibc::lightclients::tendermint::v1::Fraction,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            numerator: value.numerator,
            denominator: NonZeroU64::try_from(value.denominator)?,
        })
    }
}

// TODO(benluelo): This will be replaced with tendermint once the solidity contract types are regenerated
#[cfg(feature = "ethabi")]
impl From<Fraction> for contracts::glue::IbcLightclientsTendermintV1FractionData {
    fn from(value: Fraction) -> Self {

Review comment (suggestion):
@benluelo Not sure what to do here. In Java we wrap the cause error, because the root cause often has the most interesting details.

Code after:
use std::num::NonZeroU64;

use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Fraction {
    pub numerator: u64,
    pub denominator: NonZeroU64,
}

impl From<Fraction> for protos::ibc::lightclients::tendermint::v1::Fraction {
    fn from(value: Fraction) -> Self {
        Self {
            numerator: value.numerator,
            denominator: value.denominator.get(),
        }
    }
}

#[derive(Debug)]
pub enum TryFromFractionError {
    ZeroDenominator,
}

impl TryFrom<protos::ibc::lightclients::tendermint::v1::Fraction> for Fraction {
    type Error = TryFromFractionError;

    fn try_from(
        value: protos::ibc::lightclients::tendermint::v1::Fraction,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            numerator: value.numerator,
            denominator: value
                .denominator
                .try_into()
                .map_err(|_| TryFromFractionError::ZeroDenominator)?,
        })
    }
}

// TODO(benluelo): This will be replaced with tendermint once the solidity contract types are regenerated
#[cfg(feature = "ethabi")]
impl From<Fraction> for contracts::glue::IbcLightclientsTendermintV1FractionData {
    fn from(value: Fraction) -> Self {
        Self {
            numerator: value.numerator,
            denominator: value.denominator.get(),
        }
    }