use std::fmt;
use chrono_tz::Tz;
use crate::{
guess, json,
price::{self, price_cdr},
ParseError, Version,
};
pub fn parse_with_version(cdr_json: &str, version: Version) -> Result<ParseReport<'_>, ParseError> {
match version {
Version::V221 => {
let schema = &*crate::v221::CDR_SCHEMA;
let report =
json::parse_with_schema(cdr_json, schema).map_err(ParseError::from_cdr_err)?;
let json::Report {
element,
unexpected_fields,
} = report;
Ok(ParseReport {
cdr: Versioned::V221(element),
unexpected_fields,
})
}
Version::V211 => {
let schema = &*crate::v211::CDR_SCHEMA;
let report =
json::parse_with_schema(cdr_json, schema).map_err(ParseError::from_cdr_err)?;
let json::Report {
element,
unexpected_fields,
} = report;
Ok(ParseReport {
cdr: Versioned::V211(element),
unexpected_fields,
})
}
}
}
pub fn parse(cdr_json: &str) -> Result<guess::CdrVersion<'_>, ParseError> {
guess::cdr_version(cdr_json)
}
pub fn parse_and_report(cdr_json: &str) -> Result<guess::CdrReport<'_>, ParseError> {
guess::cdr_version_and_report(cdr_json)
}
pub fn price(
cdr_json: &str,
tariff_source: price::TariffSource,
timezone: Tz,
version: Version,
) -> Result<price::Report, price::Error> {
price_cdr(cdr_json, tariff_source, timezone, version)
}
#[derive(Debug)]
pub struct ParseReport<'buf> {
pub cdr: Versioned<'buf>,
pub unexpected_fields: json::UnexpectedFields<'buf>,
}
pub enum Versioned<'buf> {
V211(json::Element<'buf>),
V221(json::Element<'buf>),
}
impl fmt::Debug for Versioned<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
match self {
Versioned::V211(elem) | Versioned::V221(elem) => fmt::Debug::fmt(elem, f),
}
} else {
match self {
Versioned::V211(_) => f.write_str("V211(...)"),
Versioned::V221(_) => f.write_str("V221(...)"),
}
}
}
}
impl crate::Versioned for Versioned<'_> {
fn version(&self) -> Version {
match self {
Versioned::V211(_) => Version::V211,
Versioned::V221(_) => Version::V221,
}
}
}
impl<'buf> Versioned<'buf> {
pub fn into_element(self) -> json::Element<'buf> {
match self {
Versioned::V211(element) | Versioned::V221(element) => element,
}
}
pub fn as_element(&self) -> &json::Element<'buf> {
match self {
Versioned::V211(element) | Versioned::V221(element) => element,
}
}
}
#[derive(Debug)]
pub struct Unversioned<'buf>(json::Element<'buf>);
impl<'buf> Unversioned<'buf> {
pub(crate) fn new(elem: json::Element<'buf>) -> Self {
Self(elem)
}
pub fn into_element(self) -> json::Element<'buf> {
self.0
}
}
impl<'buf> crate::Unversioned for Unversioned<'buf> {
type Versioned = Versioned<'buf>;
fn force_into_versioned(self, version: Version) -> Versioned<'buf> {
match version {
Version::V221 => Versioned::V221(self.0),
Version::V211 => Versioned::V211(self.0),
}
}
}