#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
use std::convert::TryFrom;
use std::isize;
use std::str::FromStr;
#[derive(Debug, PartialEq)]
pub struct PluralOperands {
pub n: f64,
pub i: u64,
pub v: usize,
pub w: usize,
pub f: u64,
pub t: u64,
}
impl<'a> TryFrom<&'a str> for PluralOperands {
type Error = &'static str;
fn try_from(input: &'a str) -> Result<Self, Self::Error> {
let abs_str = if input.starts_with('-') {
&input[1..]
} else {
&input
};
let absolute_value = f64::from_str(&abs_str).map_err(|_| "Incorrect number passed!")?;
let integer_digits;
let num_fraction_digits0;
let num_fraction_digits;
let fraction_digits0;
let fraction_digits;
if let Some(dec_pos) = abs_str.find('.') {
let int_str = &abs_str[..dec_pos];
let dec_str = &abs_str[(dec_pos + 1)..];
integer_digits =
u64::from_str(&int_str).map_err(|_| "Could not convert string to integer!")?;
let backtrace = dec_str.trim_end_matches('0');
num_fraction_digits0 = dec_str.len() as usize;
num_fraction_digits = backtrace.len() as usize;
fraction_digits0 =
u64::from_str(dec_str).map_err(|_| "Could not convert string to integer!")?;
fraction_digits = u64::from_str(backtrace).unwrap_or(0);
} else {
integer_digits = absolute_value as u64;
num_fraction_digits0 = 0;
num_fraction_digits = 0;
fraction_digits0 = 0;
fraction_digits = 0;
}
Ok(PluralOperands {
n: absolute_value,
i: integer_digits,
v: num_fraction_digits0,
w: num_fraction_digits,
f: fraction_digits0,
t: fraction_digits,
})
}
}
macro_rules! impl_integer_type {
($ty:ident) => {
impl From<$ty> for PluralOperands {
fn from(input: $ty) -> Self {
PluralOperands {
n: input as f64,
i: input as u64,
v: 0,
w: 0,
f: 0,
t: 0,
}
}
}
};
($($ty:ident)+) => {
$(impl_integer_type!($ty);)+
};
}
macro_rules! impl_signed_integer_type {
($ty:ident) => {
impl TryFrom<$ty> for PluralOperands {
type Error = &'static str;
fn try_from(input: $ty) -> Result<Self, Self::Error> {
let x = (input as isize).checked_abs().ok_or("Number too big")?;
Ok(PluralOperands {
n: x as f64,
i: x as u64,
v: 0,
w: 0,
f: 0,
t: 0,
})
}
}
};
($($ty:ident)+) => {
$(impl_signed_integer_type!($ty);)+
};
}
macro_rules! impl_convert_type {
($ty:ident) => {
impl TryFrom<$ty> for PluralOperands {
type Error = &'static str;
fn try_from(input: $ty) -> Result<Self, Self::Error> {
let as_str: &str = &input.to_string();
PluralOperands::try_from(as_str)
}
}
};
($($ty:ident)+) => {
$(impl_convert_type!($ty);)+
};
}
impl_integer_type!(u8 u16 u32 u64 usize);
impl_signed_integer_type!(i8 i16 i32 i64 isize);
impl_convert_type!(f32 f64 String);