1use std::{collections::HashMap, f64::consts, fmt::Display, sync::LazyLock};
4
5use rust_decimal::{prelude::FromPrimitive, Decimal, MathematicalOps};
6use rust_decimal_macros::dec;
7
8#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
10pub enum ConstantTypes {
11 Pi,
13 HalfPi,
15 ThirdPi,
17 QuarterPi,
19 SixthPi,
21 EighthPi,
23 TwoPi,
25 E,
27 C,
29 G,
31 Phi,
33}
34
35pub static CONSTANT_IDENTIFIERS: LazyLock<HashMap<&'static str, ConstantTypes>> =
36 LazyLock::new(|| {
37 HashMap::from([
38 ("#pi", ConstantTypes::Pi),
39 ("#e", ConstantTypes::E),
40 ("#tau", ConstantTypes::TwoPi),
41 ("#c", ConstantTypes::C),
42 ("#G", ConstantTypes::G),
43 ("#phi", ConstantTypes::Phi),
44 ("#halfpi", ConstantTypes::HalfPi),
45 ("#thirdpi", ConstantTypes::ThirdPi),
46 ("#quarterpi", ConstantTypes::QuarterPi),
47 ("#sixthpi", ConstantTypes::SixthPi),
48 ("#eighthpi", ConstantTypes::EighthPi),
49 ("#twopi", ConstantTypes::TwoPi),
50 ])
51 });
52
53#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
55pub enum BucketTypes {
56 Float,
58 String,
60 Constant(ConstantTypes),
62 Undefined,
65}
66
67#[derive(Clone, Eq, PartialEq, Hash, Debug)]
69pub struct Bucket {
70 pub value: Option<String>,
72 pub bucket_type: BucketTypes,
74}
75
76impl Bucket {
77 pub fn new_undefined() -> Self {
79 Self {
80 value: None,
81 bucket_type: BucketTypes::Undefined,
82 }
83 }
84
85 pub fn from_constant(constant_type: ConstantTypes) -> Self {
87 let value = match constant_type {
88 ConstantTypes::Pi => consts::PI,
89 ConstantTypes::HalfPi => consts::FRAC_PI_2,
90 ConstantTypes::ThirdPi => consts::FRAC_PI_3,
91 ConstantTypes::QuarterPi => consts::FRAC_PI_4,
92 ConstantTypes::SixthPi => consts::FRAC_PI_6,
93 ConstantTypes::EighthPi => consts::FRAC_PI_8,
94 ConstantTypes::TwoPi => consts::TAU,
95 ConstantTypes::E => consts::E,
96 ConstantTypes::C => 299_792_458_f64,
97 ConstantTypes::G => 6.67430 * 10_f64.powf(-11_f64),
98 ConstantTypes::Phi => 1.618_033_988_749_895_f64,
99 }
100 .to_string();
101
102 Bucket {
103 value: Some(value),
104 bucket_type: BucketTypes::Constant(constant_type),
105 }
106 }
107
108 pub fn sin(&self) -> Option<Self> {
110 match &self.bucket_type {
111 BucketTypes::Constant(constant_type) => match constant_type {
112 ConstantTypes::E | ConstantTypes::C | ConstantTypes::G | ConstantTypes::Phi => {
113 Some(Self::from(self.value.clone()?.parse::<f64>().ok()?.sin()))
114 }
115 ConstantTypes::Pi | ConstantTypes::TwoPi => Some(Self::from(0)),
116 ConstantTypes::HalfPi => Some(Self::from(1)),
117 ConstantTypes::QuarterPi => Some(Self::from(consts::FRAC_1_SQRT_2)),
118 ConstantTypes::EighthPi => Some(Self::from(consts::FRAC_PI_8.sin())),
119 ConstantTypes::SixthPi => Some(Self::from(0.5)),
120 ConstantTypes::ThirdPi => Some(Self::from(consts::FRAC_PI_3.sin())),
121 },
122 BucketTypes::Float => Some(Self::from(
123 Decimal::from_f64(self.value.clone()?.parse::<f64>().ok()?)?.checked_sin()?,
124 )),
125 BucketTypes::String | BucketTypes::Undefined => None,
126 }
127 }
128
129 pub fn cos(&self) -> Option<Self> {
131 match &self.bucket_type {
132 BucketTypes::Constant(constant_type) => match constant_type {
133 ConstantTypes::E | ConstantTypes::C | ConstantTypes::G | ConstantTypes::Phi => {
134 Some(Self::from(self.value.clone()?.parse::<f64>().ok()?.cos()))
135 }
136 ConstantTypes::Pi => Some(Self::from(-1)),
137 ConstantTypes::TwoPi => Some(Self::from(1)),
138 ConstantTypes::HalfPi => Some(Self::from(0)),
139 ConstantTypes::QuarterPi => Some(Self::from(consts::FRAC_1_SQRT_2)),
140 ConstantTypes::EighthPi => Some(Self::from(consts::FRAC_PI_8.cos())),
141 ConstantTypes::SixthPi => Some(Self::from(consts::FRAC_PI_6.cos())),
142 ConstantTypes::ThirdPi => Some(Self::from(0.5)),
143 },
144 BucketTypes::Float => Some(Self::from(
145 Decimal::from_f64(self.value.clone()?.parse::<f64>().ok()?)?.checked_cos()?,
146 )),
147 BucketTypes::String | BucketTypes::Undefined => None,
148 }
149 }
150
151 pub fn tan(&self) -> Option<Self> {
153 match &self.bucket_type {
154 BucketTypes::Constant(constant_type) => match constant_type {
155 ConstantTypes::E | ConstantTypes::C | ConstantTypes::G | ConstantTypes::Phi => {
156 Some(Self::from(self.value.clone()?.parse::<f64>().ok()?.tan()))
157 }
158 ConstantTypes::Pi | ConstantTypes::TwoPi => Some(Self::from(0)),
159 ConstantTypes::HalfPi => Some(Self::new_undefined()),
160 ConstantTypes::QuarterPi => Some(Self::from(1)),
161 ConstantTypes::EighthPi => Some(Self::from(consts::FRAC_PI_8.tan())),
162 ConstantTypes::SixthPi => Some(Self::from(consts::FRAC_PI_6.tan())),
163 ConstantTypes::ThirdPi => Some(Self::from(consts::FRAC_PI_3.tan())),
164 },
165 BucketTypes::Float => match &self.value {
166 Some(value) => {
167 let float_value = value.parse::<f64>().ok()?;
168 if float_value == (3.0 * consts::PI) / 2.0 {
170 Some(Self::new_undefined())
171 } else {
172 Some(Self::from(
173 Decimal::from_f64(self.value.clone()?.parse::<f64>().ok()?)?
174 .checked_tan()?,
175 ))
176 }
177 }
178 None => None,
179 },
180 BucketTypes::String | BucketTypes::Undefined => None,
181 }
182 }
183
184 pub fn csc(&self) -> Option<Self> {
186 match &self.bucket_type {
187 BucketTypes::Constant(constant_type) => match constant_type {
188 ConstantTypes::E | ConstantTypes::C | ConstantTypes::G | ConstantTypes::Phi => {
191 Some(Self::from(
192 dec!(1.0)
193 / Decimal::from_f64(self.value.clone()?.parse::<f64>().ok()?)?
194 .checked_sin()?,
195 ))
196 }
197 ConstantTypes::Pi | ConstantTypes::TwoPi => Some(Self::new_undefined()),
198 ConstantTypes::HalfPi => Some(Self::from(1)),
199 ConstantTypes::QuarterPi => Some(Self::from(consts::SQRT_2)),
200 ConstantTypes::EighthPi => Some(Self::from(
201 dec!(1.0) / Decimal::from_f64(consts::FRAC_PI_8.sin())?,
202 )),
203 ConstantTypes::SixthPi => Some(Self::from(2)),
204 ConstantTypes::ThirdPi => Some(Self::from(
205 dec!(1.0) / Decimal::from_f64(consts::FRAC_PI_3.sin())?,
206 )),
207 },
208 BucketTypes::Float => match &self.value {
209 Some(value) => {
210 let float_value = value.parse::<f64>().ok()?;
211 if float_value == 0.0 {
212 Some(Self::new_undefined())
213 } else {
214 Some(Self::from(
215 dec!(1.0) / Decimal::from_f64(float_value)?.checked_sin()?,
216 ))
217 }
218 }
219 None => None,
220 },
221 BucketTypes::String | BucketTypes::Undefined => None,
222 }
223 }
224
225 pub fn sec(&self) -> Option<Self> {
227 match &self.bucket_type {
228 BucketTypes::Constant(constant_type) => match constant_type {
229 ConstantTypes::E | ConstantTypes::C | ConstantTypes::G | ConstantTypes::Phi => {
232 Some(Self::from(
233 dec!(1.0)
234 / Decimal::from_f64(self.value.clone()?.parse::<f64>().ok()?)?
235 .checked_cos()?,
236 ))
237 }
238 ConstantTypes::Pi => Some(Self::from(-1)),
239 ConstantTypes::TwoPi => Some(Self::from(1)),
240 ConstantTypes::HalfPi => Some(Self::new_undefined()),
241 ConstantTypes::QuarterPi => Some(Self::from(consts::SQRT_2)),
242 ConstantTypes::EighthPi => Some(Self::from(
243 dec!(1.0) / Decimal::from_f64(consts::FRAC_PI_8.cos())?,
244 )),
245 ConstantTypes::SixthPi => Some(Self::from(
246 dec!(1.0) / Decimal::from_f64(consts::FRAC_PI_6.cos())?,
247 )),
248 ConstantTypes::ThirdPi => Some(Self::from(2)),
249 },
250 BucketTypes::Float => match &self.value {
251 Some(value) => {
252 let float_value = value.parse::<f64>().ok()?;
253
254 if float_value == 0.0 {
256 Some(Self::from(1)) } else if float_value == (3.0 * consts::PI) / 2.0 {
258 Some(Self::new_undefined()) } else {
260 Some(Self::from(
261 dec!(1.0) / Decimal::from_f64(float_value)?.checked_cos()?,
262 ))
263 }
264 }
265 None => None,
266 },
267 BucketTypes::String | BucketTypes::Undefined => None,
268 }
269 }
270
271 pub fn cot(&self) -> Option<Self> {
273 match &self.bucket_type {
274 BucketTypes::Constant(constant_type) => match constant_type {
275 ConstantTypes::E | ConstantTypes::C | ConstantTypes::G | ConstantTypes::Phi => {
278 Some(Self::from(
279 dec!(1.0)
280 / Decimal::from_f64(self.value.clone()?.parse::<f64>().ok()?)?
281 .checked_tan()?,
282 ))
283 }
284 ConstantTypes::Pi | ConstantTypes::TwoPi => Some(Self::new_undefined()),
285 ConstantTypes::HalfPi => Some(Self::from(0)),
286 ConstantTypes::QuarterPi => Some(Self::from(1)),
287 ConstantTypes::EighthPi => Some(Self::from(
288 dec!(1.0) / Decimal::from_f64(consts::FRAC_PI_8.tan())?,
289 )),
290 ConstantTypes::SixthPi => Some(Self::from(
291 dec!(1.0) / Decimal::from_f64(consts::FRAC_PI_6.tan())?,
292 )),
293 ConstantTypes::ThirdPi => Some(Self::from(
294 dec!(1.0) / Decimal::from_f64(consts::FRAC_PI_3.tan())?,
295 )),
296 },
297 BucketTypes::Float => match &self.value {
298 Some(value) => {
299 let float_value = value.parse::<f64>().ok()?;
300 if float_value == 0.0 {
301 Some(Self::new_undefined())
302 } else {
303 Some(Self::from(
304 dec!(1.0) / Decimal::from_f64(float_value)?.checked_tan()?,
305 ))
306 }
307 }
308 None => None,
309 },
310 BucketTypes::String | BucketTypes::Undefined => None,
311 }
312 }
313}
314
315impl Display for Bucket {
317 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
318 f.write_str(&match &self.value {
319 Some(value) => value.to_string(),
320 None => "Undefined".to_owned(),
321 })
322 }
323}
324
325macro_rules! generate_float_impl {
327 ( $($t:ty),* ) => {
328 $( impl From<$t> for Bucket {
329 fn from(value: $t) -> Self {
330 Self {
331 value: Some(value.to_string()),
332 bucket_type: BucketTypes::Float,
333 }
334 }
335 } ) *
336 };
337}
338
339macro_rules! generate_int_impl {
341 ( $($t:ty),* ) => {
342 $( impl From<$t> for Bucket {
343 fn from(value: $t) -> Self {
344 Self {
345 value: Some((value as f64).to_string()),
346 bucket_type: BucketTypes::Float,
347 }
348 }
349 } ) *
350 };
351}
352
353generate_float_impl! {f32, f64}
354generate_int_impl! { u8, u16, u32, u64, i8, i16, i32, i64 }
355
356impl From<Decimal> for Bucket {
357 fn from(value: Decimal) -> Self {
358 Self {
359 value: Some(value.to_string()),
360 bucket_type: BucketTypes::Float,
361 }
362 }
363}
364
365impl From<String> for Bucket {
366 fn from(value: String) -> Self {
367 Self {
368 value: Some(value),
369 bucket_type: BucketTypes::String,
370 }
371 }
372}
373
374impl From<&str> for Bucket {
375 fn from(value: &str) -> Self {
376 Self {
377 value: Some(value.to_owned()),
378 bucket_type: BucketTypes::String,
379 }
380 }
381}