#[cfg(test)]
mod test;
#[cfg(test)]
mod test_reasonable_str;
#[cfg(test)]
mod test_rust_decimal_arbitrary_precision;
pub mod cdr;
pub mod country;
pub mod currency;
pub mod datetime;
pub mod duration;
mod energy;
pub mod enumeration;
pub mod generate;
pub mod guess;
pub mod json;
pub mod lint;
pub mod money;
pub mod number;
pub mod price;
pub mod string;
pub mod tariff;
pub mod timezone;
mod v211;
mod v221;
pub mod warning;
pub mod weekday;
use std::{collections::BTreeSet, fmt};
use warning::IntoCaveat;
use weekday::Weekday;
#[doc(inline)]
pub use duration::{ToDuration, ToHoursDecimal};
#[doc(inline)]
pub use energy::{Ampere, Kw, Kwh};
#[doc(inline)]
use enumeration::{Enum, IntoEnum};
#[doc(inline)]
pub use money::{Cost, Money, Price, Vat, VatApplicable};
#[doc(inline)]
pub use warning::{Caveat, Verdict, VerdictExt, Warning};
pub type UnexpectedFields = BTreeSet<String>;
pub type TariffId = String;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Version {
V221,
V211,
}
impl Versioned for Version {
fn version(&self) -> Version {
*self
}
}
impl fmt::Display for Version {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Version::V221 => f.write_str("v221"),
Version::V211 => f.write_str("v211"),
}
}
}
pub trait Versioned: fmt::Debug {
fn version(&self) -> Version;
}
pub trait Unversioned: fmt::Debug {
type Versioned: Versioned;
fn force_into_versioned(self, version: Version) -> Self::Versioned;
}
pub struct ParseError {
object: ObjectType,
kind: ParseErrorKind,
}
#[derive(Debug)]
pub enum ParseErrorKind {
Internal(Box<dyn std::error::Error + Send + Sync + 'static>),
Json(json::Error),
ShouldBeAnObject,
SizeExceedsMax,
}
impl fmt::Display for ParseErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Internal(_) => f.write_str("internal"),
Self::Json(error) => write!(f, "{error}"),
Self::ShouldBeAnObject => f.write_str("The element should be an object."),
Self::SizeExceedsMax => write!(
f,
"The input `&str` exceeds the max reasonable bytes `{}`.",
ReasonableStr::MAX_STR_INPUT_LEN
),
}
}
}
impl Warning for ParseErrorKind {
fn id(&self) -> warning::Id {
match self {
Self::Internal(_) => warning::Id::from_static("internal"),
Self::Json(error) => error.id(),
Self::ShouldBeAnObject => warning::Id::from_static("should_be_an_object"),
Self::SizeExceedsMax => warning::Id::from_static("size_exceeds_max"),
}
}
}
impl std::error::Error for ParseError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self.kind {
ParseErrorKind::Internal(err) => Some(&**err),
ParseErrorKind::Json(err) => Some(err),
ParseErrorKind::ShouldBeAnObject | ParseErrorKind::SizeExceedsMax => None,
}
}
}
impl fmt::Debug for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "while deserializing {:?}: ", self.object)?;
match &self.kind {
ParseErrorKind::Internal(err) => write!(f, "{err}"),
ParseErrorKind::Json(err) => write!(f, "{err}"),
ParseErrorKind::ShouldBeAnObject => f.write_str("The root element should be an object"),
ParseErrorKind::SizeExceedsMax => write!(
f,
"The input `&str` exceeds the max reasonable bytes `{}`.",
ReasonableStr::MAX_STR_INPUT_LEN
),
}
}
}
impl ParseError {
fn from_cdr_err(err: json::Error) -> Self {
Self {
object: ObjectType::Cdr,
kind: ParseErrorKind::Json(err),
}
}
fn from_tariff_err(err: json::Error) -> Self {
Self {
object: ObjectType::Tariff,
kind: ParseErrorKind::Json(err),
}
}
fn cdr_should_be_object() -> ParseError {
Self {
object: ObjectType::Cdr,
kind: ParseErrorKind::ShouldBeAnObject,
}
}
fn tariff_should_be_object() -> ParseError {
Self {
object: ObjectType::Tariff,
kind: ParseErrorKind::ShouldBeAnObject,
}
}
fn from_kind(object: ObjectType) -> impl FnOnce(ParseErrorKind) -> Self {
move |kind| Self { object, kind }
}
pub fn kind(&self) -> &ParseErrorKind {
&self.kind
}
pub fn into_parts(self) -> (ObjectType, ParseErrorKind) {
(self.object, self.kind)
}
}
#[derive(Copy, Clone)]
struct ReasonableStr<'buf>(&'buf str);
impl<'buf> ReasonableStr<'buf> {
const MEGA_BYTE: usize = 1024 * 1024;
const MAX_STR_INPUT_LEN: usize = 5 * Self::MEGA_BYTE;
fn new(s: &'buf str) -> Result<ReasonableStr<'buf>, ParseErrorKind> {
if s.len() >= Self::MAX_STR_INPUT_LEN {
return Err(ParseErrorKind::SizeExceedsMax);
}
Ok(Self(s))
}
fn into_inner(self) -> &'buf str {
self.0
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ObjectType {
Cdr,
Tariff,
}
impl fmt::Display for ObjectType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ObjectType::Cdr => f.write_str("CDR"),
ObjectType::Tariff => f.write_str("tariff"),
}
}
}
trait SaturatingAdd {
#[must_use]
fn saturating_add(self, other: Self) -> Self;
}
trait SaturatingSub {
#[must_use]
fn saturating_sub(self, other: Self) -> Self;
}
struct DisplayOption<T>(Option<T>)
where
T: fmt::Display;
impl<T> fmt::Display for DisplayOption<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
Some(v) => fmt::Display::fmt(v, f),
None => f.write_str("∅"),
}
}
}