intl_pluralrules/
operands.rs1#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
52use std::convert::TryFrom;
53use std::isize;
54use std::str::FromStr;
55
56#[derive(Debug, PartialEq)]
58pub struct PluralOperands {
59 pub n: f64,
61 pub i: u64,
63 pub v: usize,
65 pub w: usize,
67 pub f: u64,
69 pub t: u64,
71}
72
73impl<'a> TryFrom<&'a str> for PluralOperands {
74 type Error = &'static str;
75
76 fn try_from(input: &'a str) -> Result<Self, Self::Error> {
77 let abs_str = if input.starts_with('-') {
78 &input[1..]
79 } else {
80 &input
81 };
82
83 let absolute_value = f64::from_str(&abs_str).map_err(|_| "Incorrect number passed!")?;
84
85 let integer_digits;
86 let num_fraction_digits0;
87 let num_fraction_digits;
88 let fraction_digits0;
89 let fraction_digits;
90
91 if let Some(dec_pos) = abs_str.find('.') {
92 let int_str = &abs_str[..dec_pos];
93 let dec_str = &abs_str[(dec_pos + 1)..];
94
95 integer_digits =
96 u64::from_str(&int_str).map_err(|_| "Could not convert string to integer!")?;
97
98 let backtrace = dec_str.trim_end_matches('0');
99
100 num_fraction_digits0 = dec_str.len() as usize;
101 num_fraction_digits = backtrace.len() as usize;
102 fraction_digits0 =
103 u64::from_str(dec_str).map_err(|_| "Could not convert string to integer!")?;
104 fraction_digits = u64::from_str(backtrace).unwrap_or(0);
105 } else {
106 integer_digits = absolute_value as u64;
107 num_fraction_digits0 = 0;
108 num_fraction_digits = 0;
109 fraction_digits0 = 0;
110 fraction_digits = 0;
111 }
112
113 Ok(PluralOperands {
114 n: absolute_value,
115 i: integer_digits,
116 v: num_fraction_digits0,
117 w: num_fraction_digits,
118 f: fraction_digits0,
119 t: fraction_digits,
120 })
121 }
122}
123
124macro_rules! impl_integer_type {
125 ($ty:ident) => {
126 impl From<$ty> for PluralOperands {
127 fn from(input: $ty) -> Self {
128 PluralOperands {
130 n: input as f64,
131 i: input as u64,
132 v: 0,
133 w: 0,
134 f: 0,
135 t: 0,
136 }
137 }
138 }
139 };
140 ($($ty:ident)+) => {
141 $(impl_integer_type!($ty);)+
142 };
143}
144
145macro_rules! impl_signed_integer_type {
146 ($ty:ident) => {
147 impl TryFrom<$ty> for PluralOperands {
148 type Error = &'static str;
149 fn try_from(input: $ty) -> Result<Self, Self::Error> {
150 let x = (input as isize).checked_abs().ok_or("Number too big")?;
152 Ok(PluralOperands {
153 n: x as f64,
154 i: x as u64,
155 v: 0,
156 w: 0,
157 f: 0,
158 t: 0,
159 })
160 }
161 }
162 };
163 ($($ty:ident)+) => {
164 $(impl_signed_integer_type!($ty);)+
165 };
166}
167
168macro_rules! impl_convert_type {
169 ($ty:ident) => {
170 impl TryFrom<$ty> for PluralOperands {
171 type Error = &'static str;
172 fn try_from(input: $ty) -> Result<Self, Self::Error> {
173 let as_str: &str = &input.to_string();
174 PluralOperands::try_from(as_str)
175 }
176 }
177 };
178 ($($ty:ident)+) => {
179 $(impl_convert_type!($ty);)+
180 };
181}
182
183impl_integer_type!(u8 u16 u32 u64 usize);
184impl_signed_integer_type!(i8 i16 i32 i64 isize);
185impl_convert_type!(f32 f64 String);