1#![allow(clippy::non_canonical_clone_impl)]
5#![allow(clippy::ignored_unit_patterns)]
6#![allow(clippy::float_cmp)]
7use std::ops::{Deref, DerefMut};
8
9use num_traits::Zero;
10use uom::*;
11
12use serde::{Deserialize, Serialize};
13
14use crate::helper_functions;
15
16pub use self::f64::*;
17
18#[macro_use]
20pub mod mass {
21 use uom::*;
22
23 quantity! {
24 quantity: Mass; "mass";
26 dimension: Q< P1, Z0, Z0>;
28 units {
29 @millidalton: 0.001; "mDa", "millidalton", "millidaltons";
30 @dalton: 1.0; "Da", "dalton", "daltons";
31 @kilodalton: 1_000.0; "kDa", "kilodalton", "kilodaltons";
32 @megadalton: 1_000_000.0; "MDa", "megadalton", "megadaltons";
33 }
34 }
35}
36
37#[macro_use]
39pub mod charge {
40 use uom::*;
41
42 quantity! {
43 quantity: Charge; "charge";
45 dimension: Q< Z0, P1, Z0>;
47 units {
48 @e: 1.0; "e", "atomic_unit_of_charge", "atomic_units_of_charge";
49 }
50 }
51}
52
53#[macro_use]
55pub mod time {
56 use uom::*;
57
58 quantity! {
59 quantity: Time; "time";
61 dimension: Q< Z0, Z0, P1>;
63 units {
64 @ns: 0.000_000_001; "ns", "nanosecond", "nanoseconds";
65 @μs: 0.000_001; "μs", "microsecond", "microseconds";
66 @ms: 0.001; "ms", "millisecond", "milliseconds";
67 @s: 1.0; "s", "second", "seconds";
68 @min: 60.0; "min", "minute", "minutes";
69 @h: 3600.0; "h", "hour", "hours";
70 }
71 }
72}
73
74#[macro_use]
76pub mod mass_over_charge {
77 use uom::*;
78
79 quantity! {
80 quantity: MassOverCharge; "mass_over_charge";
82 dimension: Q< P1, N1, Z0>;
84 units {
85 @thomson: 1.0; "Th", "thomson", "thomson";
86 }
87 }
88}
89
90#[macro_use]
92pub mod ratio {
93 use uom::*;
94
95 quantity! {
96 quantity: Ratio; "ratio";
98 dimension: Q< Z0, Z0, Z0>;
100 units {
101 @fraction: 1.0; "⅟", "fraction", "fraction";
102 @percent: 0.01; "%", "percent", "percent";
103 @promille: 0.01; "‰", "promille", "promille";
104 @ppm: 0.000_001; "ppm", "ppm", "ppm";
105 @ppb: 0.000_000_001; "ppb", "ppb", "ppb";
106 @ppt: 0.000_000_000_001; "ppt", "ppt", "ppt";
107 @ppq: 0.000_000_000_000_001; "ppq", "ppq", "ppq";
108 }
109 }
110}
111
112system! {
113 #[doc(hidden)]
115 quantities: Q {
116 mass: dalton, M;
117 charge: e, C;
118 time: s, T;
119 }
120
121 units: U {
123 mod mass::Mass,
124 mod charge::Charge,
125 mod time::Time,
126 mod mass_over_charge::MassOverCharge,
127 mod ratio::Ratio,
128 }
129}
130
131#[allow(unused_imports)]
133pub mod f64 {
134 mod mks {
135 pub(super) use super::super::*;
136 }
137
138 Q!(self::mks, f64);
139
140 pub use super::charge::e;
141 pub use super::mass::dalton;
142 pub use super::mass_over_charge::thomson;
143 pub use super::ratio::fraction;
144 pub use super::time::s;
145
146 pub fn da(v: f64) -> Mass {
148 Mass::new::<dalton>(v)
149 }
150}
151
152#[allow(unused_imports)]
154pub mod usize {
155 mod mks {
156 pub(super) use super::super::*;
157 }
158
159 Q!(self::mks, usize);
160
161 pub use super::charge::e;
162 pub use super::mass::dalton;
163 pub use super::mass_over_charge::thomson;
164 pub use super::ratio::fraction;
165 pub use super::time::s;
166}
167
168#[allow(unused_imports)]
170pub mod isize {
171 mod mks {
172 pub(super) use super::super::*;
173 }
174
175 Q!(self::mks, isize);
176
177 pub use super::charge::e;
178 pub use super::mass::dalton;
179 pub use super::mass_over_charge::thomson;
180 pub use super::ratio::fraction;
181 pub use super::time::s;
182}
183
184impl usize::Charge {
185 pub fn to_float(self) -> Charge {
187 Charge::new::<e>(self.value as f64)
188 }
189}
190
191impl isize::Charge {
192 pub fn to_float(self) -> Charge {
194 Charge::new::<e>(self.value as f64)
195 }
196}
197
198impl MassOverCharge {
199 pub fn ppm(self, b: Self) -> Ratio {
201 (self - b).abs() / self.abs()
202 }
203
204 pub fn signed_ppm(self, b: Self) -> Ratio {
206 (self - b) / self
207 }
208}
209
210impl Mass {
211 pub fn ppm(self, b: Self) -> Ratio {
213 (self - b).abs() / self.abs()
214 }
215
216 pub fn signed_ppm(self, b: Self) -> Ratio {
218 (self - b) / self
219 }
220}
221
222#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
224pub struct OrderedRatio(Ratio);
225
226impl OrderedRatio {
227 pub fn zero() -> Self {
229 Self(Ratio::zero())
230 }
231
232 #[allow(dead_code)]
234 pub fn into_inner(self) -> Ratio {
235 self.0
236 }
237}
238
239impl Default for OrderedRatio {
240 fn default() -> Self {
241 Self::zero()
242 }
243}
244
245impl From<Ratio> for OrderedRatio {
246 fn from(value: Ratio) -> Self {
247 Self(value)
248 }
249}
250
251impl Deref for OrderedRatio {
252 type Target = Ratio;
253 fn deref(&self) -> &Self::Target {
254 &self.0
255 }
256}
257
258impl DerefMut for OrderedRatio {
259 fn deref_mut(&mut self) -> &mut Self::Target {
260 &mut self.0
261 }
262}
263
264impl Ord for OrderedRatio {
265 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
266 self.0.value.total_cmp(&other.0.value)
267 }
268}
269
270impl PartialOrd for OrderedRatio {
271 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
272 Some(self.cmp(other))
273 }
274}
275
276impl Eq for OrderedRatio {}
277
278impl PartialEq for OrderedRatio {
279 fn eq(&self, other: &Self) -> bool {
280 self.cmp(other).is_eq()
281 }
282}
283
284impl std::hash::Hash for OrderedRatio {
285 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
286 helper_functions::f64_bits(self.0.value).hash(state);
287 }
288}
289
290#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
292pub struct OrderedMass(Mass);
293
294impl OrderedMass {
295 pub fn zero() -> Self {
297 Self(Mass::zero())
298 }
299
300 #[allow(dead_code)]
302 pub fn into_inner(self) -> Mass {
303 self.0
304 }
305}
306
307impl Default for OrderedMass {
308 fn default() -> Self {
309 Self::zero()
310 }
311}
312
313impl From<Mass> for OrderedMass {
314 fn from(value: Mass) -> Self {
315 Self(value)
316 }
317}
318
319impl Deref for OrderedMass {
320 type Target = Mass;
321 fn deref(&self) -> &Self::Target {
322 &self.0
323 }
324}
325
326impl DerefMut for OrderedMass {
327 fn deref_mut(&mut self) -> &mut Self::Target {
328 &mut self.0
329 }
330}
331
332impl Ord for OrderedMass {
333 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
334 self.0.value.total_cmp(&other.0.value)
335 }
336}
337
338impl PartialOrd for OrderedMass {
339 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
340 Some(self.cmp(other))
341 }
342}
343
344impl Eq for OrderedMass {}
345
346impl PartialEq for OrderedMass {
347 fn eq(&self, other: &Self) -> bool {
348 self.cmp(other).is_eq()
349 }
350}
351
352impl std::hash::Hash for OrderedMass {
353 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
354 helper_functions::f64_bits(self.0.value).hash(state);
355 }
356}
357
358#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
360pub struct OrderedMassOverCharge(MassOverCharge);
361
362impl OrderedMassOverCharge {
363 pub fn zero() -> Self {
365 Self(MassOverCharge::zero())
366 }
367
368 #[allow(dead_code)]
370 pub fn into_inner(self) -> MassOverCharge {
371 self.0
372 }
373}
374
375impl Default for OrderedMassOverCharge {
376 fn default() -> Self {
377 Self::zero()
378 }
379}
380
381impl From<MassOverCharge> for OrderedMassOverCharge {
382 fn from(value: MassOverCharge) -> Self {
383 Self(value)
384 }
385}
386
387impl Deref for OrderedMassOverCharge {
388 type Target = MassOverCharge;
389 fn deref(&self) -> &Self::Target {
390 &self.0
391 }
392}
393
394impl DerefMut for OrderedMassOverCharge {
395 fn deref_mut(&mut self) -> &mut Self::Target {
396 &mut self.0
397 }
398}
399
400impl Ord for OrderedMassOverCharge {
401 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
402 self.0.value.total_cmp(&other.0.value)
403 }
404}
405
406impl PartialOrd for OrderedMassOverCharge {
407 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
408 Some(self.cmp(other))
409 }
410}
411
412impl Eq for OrderedMassOverCharge {}
413
414impl PartialEq for OrderedMassOverCharge {
415 fn eq(&self, other: &Self) -> bool {
416 self.cmp(other).is_eq()
417 }
418}
419
420impl std::hash::Hash for OrderedMassOverCharge {
421 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
422 helper_functions::f64_bits(self.0.value).hash(state);
423 }
424}
425
426#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
428pub struct OrderedTime(Time);
429
430impl OrderedTime {
431 pub fn zero() -> Self {
433 Self(Time::zero())
434 }
435
436 #[allow(dead_code)]
438 pub fn into_inner(self) -> Time {
439 self.0
440 }
441}
442
443impl Default for OrderedTime {
444 fn default() -> Self {
445 Self::zero()
446 }
447}
448
449impl From<Time> for OrderedTime {
450 fn from(value: Time) -> Self {
451 Self(value)
452 }
453}
454
455impl Deref for OrderedTime {
456 type Target = Time;
457 fn deref(&self) -> &Self::Target {
458 &self.0
459 }
460}
461
462impl DerefMut for OrderedTime {
463 fn deref_mut(&mut self) -> &mut Self::Target {
464 &mut self.0
465 }
466}
467
468impl Ord for OrderedTime {
469 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
470 self.0.value.total_cmp(&other.0.value)
471 }
472}
473
474impl PartialOrd for OrderedTime {
475 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
476 Some(self.cmp(other))
477 }
478}
479
480impl Eq for OrderedTime {}
481
482impl PartialEq for OrderedTime {
483 fn eq(&self, other: &Self) -> bool {
484 self.cmp(other).is_eq()
485 }
486}
487
488impl std::hash::Hash for OrderedTime {
489 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
490 helper_functions::f64_bits(self.0.value).hash(state);
491 }
492}