use std::fmt;
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use crate::{json, number, Number};
#[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())
}
#[must_use]
pub fn saturating_add(self, other: Self) -> Self {
Self(self.0.saturating_add(other.0))
}
#[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"),
)
}
#[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)
}
}
#[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()
}
}
#[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)
}
}
}