1mod units;
2mod ops;
3
4use core::fmt;
5use std::{fmt::Debug, marker::PhantomData, str::FromStr};
6use crate::Number;
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8pub use units::*;
9
10pub trait Unit : PartialEq + Eq + Clone + Copy + Debug {
11 fn name() -> &'static str;
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct UnitNumber<U> {
16 number: Number,
17 unit: PhantomData<U>,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct UnitComplex<U> {
22 re: UnitNumber<U>,
23 im: UnitNumber<U>,
24 unit: PhantomData<U>,
25}
26
27impl<U: Unit> UnitNumber<U> {
28 pub fn new<N: Into<Number>>(number: N) -> Self {
29 Self { number: number.into(), unit: PhantomData }
30 }
31
32 pub fn to_f64(&self) -> f64 {
33 self.number.to_f64()
34 }
35
36 pub fn value(&self) -> Number {
37 self.number
38 }
39
40 pub fn is_nan(self) -> bool {
41 self.number.is_nan()
42 }
43
44 pub fn is_finite(self) -> bool {
45 self.number.is_finite()
46 }
47
48 pub fn powf(self, exp: f64) -> Self {
49 Self::new(self.number.powf(exp))
50 }
51
52 pub fn atan2(self, other: Self) -> Number {
53 self.number.atan2(other.number)
54 }
55}
56
57macro_rules! impl_f64_like_method {
58 ($f:ident) => {
59 pub fn $f(&self) -> Self {
60 Self::new(self.number.$f())
61 }
62 };
63}
64
65impl<U: Unit> UnitNumber<U> {
66 impl_f64_like_method!(abs);
67 impl_f64_like_method!(ceil);
68 impl_f64_like_method!(floor);
69 impl_f64_like_method!(round);
70 impl_f64_like_method!(trunc);
71 impl_f64_like_method!(fract);
72
73 impl_f64_like_method!(sqrt);
74 impl_f64_like_method!(exp);
75 impl_f64_like_method!(ln);
76 impl_f64_like_method!(log10);
77 impl_f64_like_method!(log2);
78 impl_f64_like_method!(recip);
79
80 impl_f64_like_method!(sin);
81 impl_f64_like_method!(cos);
82 impl_f64_like_method!(tan);
83 impl_f64_like_method!(asin);
84 impl_f64_like_method!(acos);
85 impl_f64_like_method!(atan);
86
87 impl_f64_like_method!(sinh);
88 impl_f64_like_method!(cosh);
89 impl_f64_like_method!(tanh);
90
91 impl_f64_like_method!(to_degrees);
92 impl_f64_like_method!(to_radians);
93}
94
95impl<U: Unit> UnitComplex<U> {
96 pub fn new<N1: Into<UnitNumber<U>>, N2: Into<UnitNumber<U>>>(re: N1, im: N2) -> Self {
97 Self { re: re.into(), im: im.into(), unit: PhantomData }
98 }
99
100 pub fn parts(&self) -> (UnitNumber<U>, UnitNumber<U>) {
101 (self.re, self.im)
102 }
103
104 pub fn conjugate(&self) -> Self {
105 Self {
106 re: self.re,
107 im: -self.im,
108 unit: self.unit
109 }
110 }
111
112 pub fn abs(&self) -> UnitNumber<U> {
113 let abs_value = (self.re.number.powf(2.) + self.im.number.powf(2.)).sqrt();
114 UnitNumber::new(abs_value)
115 }
116
117 pub fn arg(&self) -> Number {
118 self.im.atan2(self.re)
119 }
120}
121
122impl<U: Unit> fmt::Display for UnitNumber<U> {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 if let Some(p) = f.precision() {
125 write!(f, "{:.*}{}", p, self.number, U::name())
126 } else {
127 write!(f, "{}{}", self.number, U::name())
128 }
129 }
130}
131
132impl<U: Unit> fmt::Display for UnitComplex<U> {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 if let Some(p) = f.precision() {
135 write!(f, "{:.*} + {:.*}j", p, self.re, p, self.im)
136 } else {
137 write!(f, "{} + {}j", self.re, self.im)
138 }
139 }
140}
141
142impl<U: Unit> FromStr for UnitNumber<U> {
143 type Err = String;
144 fn from_str(s: &str) -> Result<Self, Self::Err> {
145 let s = s.trim();
146 if s.ends_with(U::name()) {
147 let number_len = s.len() - U::name().len();
148 let number_str = &s[..number_len];
149 let number: Number = FromStr::from_str(number_str)?;
150 Ok(Self::new(number))
151 } else {
152 Err(format!("Expect end with '{}'", U::name()))
153 }
154 }
155}
156
157impl<U: Unit> Serialize for UnitNumber<U> {
158 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
159 where
160 S: Serializer,
161 {
162 let s = self.to_string();
163 serializer.serialize_str(&s)
164 }
165}
166
167impl<'de, U: Unit> Deserialize<'de> for UnitNumber<U> {
168 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
169 where
170 D: Deserializer<'de>,
171 {
172 let s = String::deserialize(deserializer)?;
173 Self::from_str(&s).map_err(serde::de::Error::custom)
174 }
175}
176
177impl<U: Unit> From<Number> for UnitNumber<U> {
178 fn from(value: Number) -> Self {
179 Self::new(value)
180 }
181}
182
183macro_rules! impl_from {
184 ($t:ty) => {
185 impl<U: Unit> From<$t> for UnitNumber<U> {
186 fn from(value: $t) -> Self {
187 Self::new(Number::from(value as f64))
188 }
189 }
190 };
191}
192
193impl_from!(f64);
194impl_from!(f32);
195impl_from!(u32);
196impl_from!(i32);