use base64::display::Base64Display;
use base64::engine::general_purpose::STANDARD;
use base64::{DecodeError, Engine};
use chrono::format::{Fixed, Item, ParseError};
use chrono::{DateTime, Utc};
use serde_bytes::ByteBuf;
use std::error::Error;
use std::f64;
use std::fmt;
use std::iter;
use std::num::ParseFloatError;
use std::str::FromStr;
use uuid::Uuid;
use crate::{BearerToken, ResourceIdentifier, SafeLong};
pub trait Plain {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
}
impl<T> Plain for &T
where
T: ?Sized + Plain,
{
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
Plain::fmt(&**self, fmt)
}
}
macro_rules! as_display {
($t:ty) => {
impl Plain for $t {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, fmt)
}
}
};
}
as_display!(bool);
as_display!(i32);
as_display!(ResourceIdentifier);
as_display!(SafeLong);
as_display!(str);
as_display!(String);
as_display!(Uuid);
impl Plain for BearerToken {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.as_str(), fmt)
}
}
impl Plain for DateTime<Utc> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(
&self.format_with_items(iter::once(Item::Fixed(Fixed::RFC3339))),
fmt,
)
}
}
impl Plain for f64 {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
if *self == f64::INFINITY {
fmt::Display::fmt("Infinity", fmt)
} else if *self == f64::NEG_INFINITY {
fmt::Display::fmt("-Infinity", fmt)
} else {
fmt::Display::fmt(self, fmt)
}
}
}
impl Plain for [u8] {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&Base64Display::new(self, &STANDARD), fmt)
}
}
impl Plain for Vec<u8> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
Plain::fmt(&**self, fmt)
}
}
impl Plain for ByteBuf {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
Plain::fmt(&**self, fmt)
}
}
pub trait ToPlain {
fn to_plain(&self) -> String;
}
impl<T> ToPlain for T
where
T: ?Sized + Plain,
{
fn to_plain(&self) -> String {
struct Adaptor<T>(T);
impl<T> fmt::Display for Adaptor<T>
where
T: Plain,
{
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
Plain::fmt(&self.0, fmt)
}
}
Adaptor(self).to_string()
}
}
pub trait FromPlain: Sized {
type Err;
fn from_plain(s: &str) -> Result<Self, Self::Err>;
}
macro_rules! as_from_str {
($t:ty) => {
impl FromPlain for $t {
type Err = <$t as FromStr>::Err;
#[inline]
fn from_plain(s: &str) -> Result<Self, Self::Err> {
s.parse()
}
}
};
}
as_from_str!(BearerToken);
as_from_str!(bool);
as_from_str!(i32);
as_from_str!(ResourceIdentifier);
as_from_str!(SafeLong);
as_from_str!(String);
as_from_str!(Uuid);
impl FromPlain for ByteBuf {
type Err = ParseBinaryError;
#[inline]
fn from_plain(s: &str) -> Result<ByteBuf, ParseBinaryError> {
let buf = STANDARD.decode(s).map_err(ParseBinaryError)?;
Ok(ByteBuf::from(buf))
}
}
#[derive(Debug)]
pub struct ParseBinaryError(DecodeError);
impl fmt::Display for ParseBinaryError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, fmt)
}
}
impl Error for ParseBinaryError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.0.source()
}
}
impl FromPlain for DateTime<Utc> {
type Err = ParseError;
#[inline]
fn from_plain(s: &str) -> Result<DateTime<Utc>, ParseError> {
DateTime::parse_from_rfc3339(s).map(|t| t.with_timezone(&Utc))
}
}
impl FromPlain for f64 {
type Err = ParseFloatError;
#[inline]
fn from_plain(s: &str) -> Result<f64, ParseFloatError> {
match s {
"Infinity" => Ok(f64::INFINITY),
"-Infinity" => Ok(f64::NEG_INFINITY),
s => s.parse(),
}
}
}
#[derive(Debug, Default)]
pub struct ParseEnumError(());
impl ParseEnumError {
#[inline]
pub fn new() -> ParseEnumError {
ParseEnumError(())
}
}
impl fmt::Display for ParseEnumError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("invalid enum variant")
}
}
impl Error for ParseEnumError {}