ocpi-tariffs 0.20.0

OCPI tariff calculations
Documentation
use std::fmt;

use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};

use crate::{json, number, Number};

/// A value of kilo watt hours.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Default)]
#[serde(transparent)]
pub struct Kwh(Number);

impl json::FromJson<'_, '_> for Kwh {
    type WarningKind = number::WarningKind;

    fn from_json(elem: &'_ json::Element<'_>) -> crate::Verdict<Self, Self::WarningKind> {
        Ok(Number::from_json(elem)?.map(Kwh))
    }
}

impl Kwh {
    pub(crate) fn from_decimal(d: Decimal) -> Self {
        Self(Number::from_decimal(d))
    }

    pub fn zero() -> Self {
        Self(Number::default())
    }

    /// Saturating addition
    #[must_use]
    pub fn saturating_add(self, other: Self) -> Self {
        Self(self.0.saturating_add(other.0))
    }

    /// Saturating subtraction
    #[must_use]
    pub fn saturating_sub(self, other: Self) -> Self {
        Self(self.0.saturating_sub(other.0))
    }

    pub fn watt_hours(self) -> Number {
        self.0.saturating_mul(Number::from(1000))
    }

    pub fn from_watt_hours(num: Number) -> Self {
        Self(
            num.checked_div(Number::from(1000))
                .expect("divisor is non-zero"),
        )
    }

    /// Round this number to the OCPI specified amount of decimals.
    #[must_use]
    pub fn rescale(self) -> Self {
        Self(self.0.rescale())
    }

    #[must_use]
    pub fn round_dp(self, digits: u32) -> Self {
        Self(self.0.round_dp(digits))
    }
}

impl From<Kwh> for Decimal {
    fn from(value: Kwh) -> Self {
        value.0.into()
    }
}

impl From<Kwh> for Number {
    fn from(value: Kwh) -> Self {
        value.0
    }
}

impl fmt::Display for Kwh {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:.4}", self.0)
    }
}

/// A value of kilo watts.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
#[serde(transparent)]
pub struct Kw(Number);

impl json::FromJson<'_, '_> for Kw {
    type WarningKind = number::WarningKind;

    fn from_json(elem: &'_ json::Element<'_>) -> crate::Verdict<Self, Self::WarningKind> {
        Ok(Number::from_json(elem)?.map(Kw))
    }
}

impl From<Kw> for Decimal {
    fn from(value: Kw) -> Self {
        value.0.into()
    }
}

/// A value of amperes.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
#[serde(transparent)]
pub struct Ampere(Number);

impl json::FromJson<'_, '_> for Ampere {
    type WarningKind = number::WarningKind;

    fn from_json(elem: &'_ json::Element<'_>) -> crate::Verdict<Self, Self::WarningKind> {
        Ok(Number::from_json(elem)?.map(Ampere))
    }
}

impl From<Ampere> for Decimal {
    fn from(value: Ampere) -> Self {
        value.0.into()
    }
}

#[cfg(test)]
mod test {
    use crate::Number;

    use super::{Ampere, Kw, Kwh};

    impl From<u64> for Kw {
        fn from(value: u64) -> Self {
            Self(value.into())
        }
    }

    impl From<u64> for Kwh {
        fn from(value: u64) -> Self {
            Self(value.into())
        }
    }

    impl From<Number> for Ampere {
        fn from(value: Number) -> Self {
            Self(value)
        }
    }
}