ocpi-tariffs 0.51.0

OCPI tariff calculations
Documentation
//! Types for parsing all tariff versions.

use std::convert::Infallible;

use crate::{
    define_enum_from_json, json, schema,
    tariff::Warning,
    warning::{self, IntoCaveat as _},
    Enum, FromSchema, IntoEnum, Verdict,
};

/// Type of tariff component.
///
/// See: <https://github.com/ocpi/ocpi/blob/release-2.2.1-bugfixes/mod_tariffs.asciidoc#mod_tariffs_tariffdimensiontype_enum>.
/// See: <https://github.com/ocpi/ocpi/blob/release-2.1.1-bugfixes/mod_tariffs.md#44-tariffdimensiontype-enum>.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub(crate) enum DimensionType {
    /// Defined in kWh, `step_size` multiplier: 1 Wh.
    Energy,
    /// Flat fee, no unit for `step_size`.
    Flat,
    /// Time not charging: defined in hours, `step_size` multiplier: 1 second.
    ParkingTime,
    /// Time charging: defined in hours, `step_size` multiplier: 1 second.
    Time,
}

impl FromSchema<'_, schema::v211::TariffDimensionType> for DimensionType {
    type Warning = Infallible;

    fn from_schema(source: &schema::v211::TariffDimensionType) -> Verdict<Self, Self::Warning> {
        use schema::v211::TariffDimensionType;

        let v = match source {
            TariffDimensionType::Energy => Self::Energy,
            TariffDimensionType::Flat => Self::Flat,
            TariffDimensionType::ParkingTime => Self::ParkingTime,
            TariffDimensionType::Time => Self::Time,
        };

        Ok(v.into_infallible_caveat())
    }
}

impl FromSchema<'_, schema::v221::TariffDimensionType> for DimensionType {
    type Warning = Infallible;

    fn from_schema(source: &schema::v221::TariffDimensionType) -> Verdict<Self, Self::Warning> {
        use schema::v221::TariffDimensionType;

        let v = match source {
            TariffDimensionType::Energy => Self::Energy,
            TariffDimensionType::Flat => Self::Flat,
            TariffDimensionType::ParkingTime => Self::ParkingTime,
            TariffDimensionType::Time => Self::Time,
        };

        Ok(v.into_infallible_caveat())
    }
}

impl IntoEnum for DimensionType {
    fn enum_from_str(s: &str) -> Enum<Self> {
        let dt = if s.eq_ignore_ascii_case("energy") {
            DimensionType::Energy
        } else if s.eq_ignore_ascii_case("flat") {
            DimensionType::Flat
        } else if s.eq_ignore_ascii_case("parking_time") {
            DimensionType::ParkingTime
        } else if s.eq_ignore_ascii_case("time") {
            DimensionType::Time
        } else {
            return Enum::Unknown(s.to_owned());
        };

        Enum::Known(dt)
    }
}

define_enum_from_json!(DimensionType, display_name: "DimensionType", warning_id: "dimension_type");

impl json::FromJson<'_> for u64 {
    type Warning = Warning;

    fn from_json(elem: &'_ json::Element<'_>) -> Verdict<Self, Self::Warning> {
        let warnings = warning::Set::new();
        let Some(s) = elem.as_number_str() else {
            return warnings.bail(
                elem,
                Warning::FieldInvalidType {
                    expected_type: json::ValueKind::Number,
                },
            );
        };

        let n = match s.parse::<u64>() {
            Ok(n) => n,
            Err(err) => {
                return warnings.bail(elem, Warning::field_invalid_value(s, err.to_string()));
            }
        };

        Ok(n.into_caveat(warnings))
    }
}