deep_time/dt/helpers.rs
1use crate::{ATTOS_PER_SEC_I128, ATTOS_PER_SECF, Dt, Real};
2
3impl Dt {
4 /// Clamps an `i128` to the representable range of `i64`.
5 pub const fn to_i64(x: i128) -> i64 {
6 let y = x as i64;
7 if x == y as i128 {
8 y
9 } else if x > 0 {
10 i64::MAX
11 } else {
12 i64::MIN
13 }
14 }
15
16 /// Clamps an `i128` to the representable range of `u64`.
17 pub const fn to_u64(x: i128) -> u64 {
18 if x > u64::MAX as i128 {
19 u64::MAX
20 } else if x < u64::MIN as i128 {
21 u64::MIN
22 } else {
23 x as u64
24 }
25 }
26
27 /// Combines a whole unit count and fractional attoseconds within that unit into total attoseconds.
28 ///
29 /// Computes `whole * unit_attos + frac_attos`. The fractional part is always **added**, even
30 /// when `whole` is negative — the Euclidean / floor split used by
31 /// [`to_ms_floor`](../struct.Dt.html#method.to_ms_floor),
32 /// [`to_ns_floor`](../struct.Dt.html#method.to_ns_floor), and related methods, and by
33 /// constructors such as
34 /// [`from_ms_floor`](../struct.Dt.html#method.from_ms_floor) and
35 /// [`from_ns_floor`](../struct.Dt.html#method.from_ns_floor).
36 ///
37 /// This is **not** the same as pairing with truncating extractors like
38 /// [`to_ms`](../struct.Dt.html#method.to_ms) (signed remainder). Unlike
39 /// [`from_sec_and_frac`](../struct.Dt.html#method.from_sec_and_frac), the fraction is never
40 /// subtracted when `whole` is negative.
41 #[inline(always)]
42 pub const fn unit_and_attos_to_attos(whole: i128, frac_attos: u128, unit_attos: i128) -> i128 {
43 whole
44 .saturating_mul(unit_attos)
45 .saturating_add(frac_attos as i128)
46 }
47
48 /// Converts seconds i128 → total attoseconds i128
49 #[inline(always)]
50 pub const fn sec_to_attos(sec: i128) -> i128 {
51 sec.saturating_mul(ATTOS_PER_SEC_I128)
52 }
53
54 /// Converts total attoseconds → whole seconds as i64
55 #[inline(always)]
56 pub const fn attos_to_sec_i64(attos: i128) -> i64 {
57 Self::to_i64(attos / ATTOS_PER_SEC_I128)
58 }
59
60 /// Clamps `value` to the range `[min, max]`.
61 ///
62 /// This is a `const fn`, so it can be used in const contexts
63 /// (e.g. const generics, statics, const evaluation, etc.).
64 ///
65 /// If `min > max`, the result is equivalent to clamping to `[max, min]`.
66 pub const fn clamp_u8(value: u8, min: u8, max: u8) -> u8 {
67 if value < min {
68 min
69 } else if value > max {
70 max
71 } else {
72 value
73 }
74 }
75
76 /// Clamps `value` to the range `[min, max]`.
77 ///
78 /// This is a `const fn`, so it can be used in const contexts
79 /// (e.g. const generics, statics, const evaluation, etc.).
80 ///
81 /// If `min > max`, the result is equivalent to clamping to `[max, min]`.
82 pub const fn clamp_u64(value: u64, min: u64, max: u64) -> u64 {
83 if value < min {
84 min
85 } else if value > max {
86 max
87 } else {
88 value
89 }
90 }
91
92 /// **Lossy** conversion of u128 attoseconds to → float seconds (s).
93 #[inline(always)]
94 pub const fn attos_to_sec_f(attos: u128) -> Real {
95 f!(attos) / ATTOS_PER_SECF
96 }
97}