#![warn(
anonymous_parameters,
bare_trait_objects,
missing_debug_implementations,
missing_docs,
trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unused_results,
variant_size_differences
)]
#![forbid(unsafe_code)]
use std::cmp::Ordering;
use std::error::Error;
use std::fmt;
use std::str::FromStr;
pub mod multiples;
pub use multiples::*;
pub type Size = SpecificSize<Any>;
#[derive(Copy, Clone, Debug)]
pub struct SpecificSize<M = Any> {
value: f64,
multiple: M,
}
impl<M: Multiple> SpecificSize<M> {
pub fn new<V>(value: V, multiple: M) -> Result<SpecificSize<M>, InvalidValueError>
where
V: Into<f64>,
{
let value = value.into();
if is_valid_value(value) {
Ok(SpecificSize { value, multiple })
} else {
Err(InvalidValueError)
}
}
pub fn into<M2>(self) -> SpecificSize<M2>
where
M2: Multiple,
{
let (value, any) = M::into_any(self);
M2::from_any(value, any)
}
pub fn value(self) -> f64 {
self.value
}
pub fn multiple(self) -> M {
self.multiple
}
pub fn to_bytes(self) -> u64 {
let (value, any) = M::into_any(self);
Byte::from_any(value, any).value as u64
}
}
fn is_valid_value(value: f64) -> bool {
use std::num::FpCategory::*;
matches!(value.classify(), Normal | Zero)
}
impl<M: Multiple> FromStr for SpecificSize<M> {
type Err = ParsingError;
fn from_str(input: &str) -> Result<SpecificSize<M>, Self::Err> {
let input = input.trim();
if input.is_empty() {
return Err(ParsingError::EmptyInput);
}
let multiple_index = input
.chars()
.position(|c| !(c.is_numeric() || c == '.'))
.ok_or(ParsingError::MissingMultiple)?;
if multiple_index == 0 {
return Err(ParsingError::MissingValue);
}
let (value, multiple) = &input.split_at(multiple_index);
let value = value.parse().map_err(|_| ParsingError::InvalidValue)?;
if is_valid_value(value) {
let multiple = multiple.trim().parse()?;
Ok(M::from_any(value, multiple))
} else {
Err(ParsingError::InvalidValue)
}
}
}
#[cfg(feature = "enable-serde")]
impl<'de, M> serde_core::Deserialize<'de> for SpecificSize<M>
where
M: Multiple,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde_core::Deserializer<'de>,
{
use std::marker::PhantomData;
use serde_core::de::{Error, Visitor};
struct SpecificSizeVisitor<M>(PhantomData<M>);
impl<'de, M: Multiple> Visitor<'de> for SpecificSizeVisitor<M> {
type Value = SpecificSize<M>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("size")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: Error,
{
s.parse().map_err(Error::custom)
}
}
deserializer.deserialize_str(SpecificSizeVisitor(PhantomData))
}
}
#[cfg(feature = "enable-serde")]
impl<M> serde_core::Serialize for SpecificSize<M>
where
M: Multiple + fmt::Display,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde_core::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
const CMP_MARGIN: f64 = 0.000_000_01;
impl<LM, RM> PartialEq<SpecificSize<RM>> for SpecificSize<LM>
where
LM: Multiple + Copy,
RM: Multiple + Copy,
{
fn eq(&self, other: &SpecificSize<RM>) -> bool {
let (left, right) = into_same_multiples(*self, *other);
let diff = left - right;
diff.abs() < CMP_MARGIN
}
}
impl<M> Eq for SpecificSize<M> where M: Multiple + Copy {}
impl<LM, RM> PartialOrd<SpecificSize<RM>> for SpecificSize<LM>
where
LM: Multiple + Copy,
RM: Multiple + Copy,
{
fn partial_cmp(&self, other: &SpecificSize<RM>) -> Option<Ordering> {
let (left, right) = into_same_multiples(*self, *other);
left.partial_cmp(&right)
}
}
fn into_same_multiples<LM, RM>(left: SpecificSize<LM>, right: SpecificSize<RM>) -> (f64, f64)
where
LM: Multiple,
RM: Multiple,
{
let (left_value, left_multiple) = LM::into_any(left);
let (right_value, right_multiple) = RM::into_any(right);
let multiply = left_multiple.multiple_of_bytes() / right_multiple.multiple_of_bytes();
(left_value * multiply, right_value)
}
impl<M: fmt::Display> fmt::Display for SpecificSize<M> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(precision) = f.precision() {
write!(f, "{:.*} {}", precision, self.value, self.multiple)
} else {
write!(f, "{} {}", self.value, self.multiple)
}
}
}
pub trait Multiple: Sized {
fn from_any(value: f64, multiple: Any) -> SpecificSize<Self>;
fn into_any(size: SpecificSize<Self>) -> (f64, Any);
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct InvalidValueError;
impl fmt::Display for InvalidValueError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
ParsingError::InvalidValue.fmt(f)
}
}
impl Error for InvalidValueError {}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ParsingError {
EmptyInput,
MissingValue,
InvalidValue,
MissingMultiple,
InvalidMultiple,
}
impl fmt::Display for ParsingError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad(match *self {
ParsingError::EmptyInput => "input is empty",
ParsingError::MissingValue => "no value",
ParsingError::InvalidValue => "invalid value",
ParsingError::MissingMultiple => "no multiple",
ParsingError::InvalidMultiple => "invalid multiple",
})
}
}
impl Error for ParsingError {}