1use crate::{
2 ATTOS_PER_FS, ATTOS_PER_FS_I128, ATTOS_PER_MS, ATTOS_PER_MS_I128, ATTOS_PER_NS,
3 ATTOS_PER_NS_I128, ATTOS_PER_PS, ATTOS_PER_PS_I128, ATTOS_PER_SEC, ATTOS_PER_SEC_I128,
4 ATTOS_PER_SECF, ATTOS_PER_US, ATTOS_PER_US_I128, Drift, Dt, Real, Scale, Spacetime, floor_f,
5};
6
7impl Dt {
8 #[inline]
9 pub const fn add(self, span: Dt) -> Self {
10 if !span.is_zero() {
11 let (sec, attos) = Dt::add_time(self.sec, self.attos, span.sec, span.attos);
12 Self { sec, attos }
13 } else {
14 self
15 }
16 }
17
18 #[inline]
19 pub const fn sub(self, span: Dt) -> Self {
20 if !span.is_zero() {
21 let (sec, attos) = Dt::sub_time(self.sec, self.attos, span.sec, span.attos);
22 Self { sec, attos }
23 } else {
24 self
25 }
26 }
27
28 pub const fn to_sec_f(&self) -> Real {
31 let Dt { sec, attos: rem } = self.carry_attos();
32
33 if sec < 0 && rem > ATTOS_PER_SEC / 2 {
34 let small = ATTOS_PER_SEC - rem; let small_f = f!(small) / ATTOS_PER_SECF;
39 (f!(sec) + 1.0) - small_f
40 } else {
41 f!(sec) + f!(rem) / ATTOS_PER_SECF
43 }
44 }
45
46 #[inline]
52 pub const fn adjusted_advance(&mut self, elapsed: &Dt, spacetime: &Spacetime) {
53 let dtau = elapsed.add(Drift::from_spacetime(spacetime).time_diff_after(elapsed));
54 *self = self.add(dtau);
55 }
56
57 #[inline]
65 pub const fn adjusted_advance_using_drift(&mut self, elapsed: &Dt, drift: &Drift) {
66 let dtau = elapsed.add(drift.time_diff_after(elapsed));
67 *self = self.add(dtau);
68 }
69
70 #[inline]
72 pub const fn to_diff_raw(&self, other: Self) -> Dt {
73 Self::diff_raw_internal(self.sec, self.attos, other.sec, other.attos)
74 }
75
76 #[inline]
78 pub const fn to_diff_raw_f(&self, other: Self) -> Real {
79 self.to_sec_f() - other.to_sec_f()
80 }
81
82 #[inline]
84 pub const fn add_1sec(&mut self) {
85 self.sec = self.sec.saturating_add(1);
86 }
87
88 #[inline]
90 pub const fn add_1min(&mut self) {
91 self.sec = self.sec.saturating_add(60);
92 }
93
94 #[inline]
96 pub const fn add_1hr(&mut self) {
97 self.sec = self.sec.saturating_add(3600);
98 }
99
100 #[inline]
104 pub const fn add_1ms(&mut self) {
105 Self::add_attos_to(&mut self.sec, &mut self.attos, ATTOS_PER_MS);
106 }
107
108 #[inline]
112 pub const fn add_1us(&mut self) {
113 Self::add_attos_to(&mut self.sec, &mut self.attos, ATTOS_PER_US);
114 }
115
116 #[inline]
120 pub const fn add_1ns(&mut self) {
121 Self::add_attos_to(&mut self.sec, &mut self.attos, ATTOS_PER_NS);
122 }
123
124 #[inline]
126 pub const fn add_sec(&mut self, n: i64) {
127 self.sec = self.sec.saturating_add(n);
128 }
129
130 #[inline]
132 pub const fn add_min(&mut self, n: i64) {
133 self.sec = self.sec.saturating_add(n.saturating_mul(60));
134 }
135
136 #[inline]
138 pub const fn add_hr(&mut self, n: i64) {
139 self.sec = self.sec.saturating_add(n.saturating_mul(3600));
140 }
141
142 #[inline]
146 pub const fn add_ms(&mut self, n: i64) {
147 Self::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_MS);
148 }
149
150 #[inline]
154 pub const fn add_us(&mut self, n: i64) {
155 Self::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_US);
156 }
157
158 #[inline]
162 pub const fn add_ns(&mut self, n: i64) {
163 Self::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_NS);
164 }
165
166 #[inline]
170 pub const fn add_ps(&mut self, n: i64) {
171 Self::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_PS);
172 }
173
174 #[inline]
178 pub const fn add_fs(&mut self, n: i64) {
179 Self::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_FS);
180 }
181
182 #[inline]
186 pub const fn add_attos(&mut self, n: i64) {
187 Self::add_attos_span(&mut self.sec, &mut self.attos, n, 1);
188 }
189
190 #[inline]
192 pub const fn sub_1hr(&mut self) {
193 self.sec = self.sec.saturating_sub(3600);
194 }
195
196 #[inline]
198 pub const fn sub_1min(&mut self) {
199 self.sec = self.sec.saturating_sub(60);
200 }
201
202 #[inline]
204 pub const fn sub_1sec(&mut self) {
205 self.sec = self.sec.saturating_sub(1);
206 }
207
208 #[inline]
212 pub const fn sub_1ms(&mut self) {
213 Self::add_attos_span(&mut self.sec, &mut self.attos, -1, ATTOS_PER_MS);
214 }
215
216 #[inline]
220 pub const fn sub_1us(&mut self) {
221 Self::add_attos_span(&mut self.sec, &mut self.attos, -1, ATTOS_PER_US);
222 }
223
224 #[inline]
228 pub const fn sub_1ns(&mut self) {
229 Self::add_attos_span(&mut self.sec, &mut self.attos, -1, ATTOS_PER_NS);
230 }
231
232 #[inline]
234 pub const fn sub_sec(&mut self, n: i64) {
235 self.sec = self.sec.saturating_sub(n);
236 }
237
238 #[inline]
240 pub const fn sub_min(&mut self, n: i64) {
241 self.sec = self.sec.saturating_sub(n.saturating_mul(60));
242 }
243
244 #[inline]
246 pub const fn sub_hr(&mut self, n: i64) {
247 self.sec = self.sec.saturating_sub(n.saturating_mul(3600));
248 }
249
250 #[inline]
254 pub const fn sub_ms(&mut self, n: i64) {
255 Self::add_attos_span(
256 &mut self.sec,
257 &mut self.attos,
258 n.saturating_neg(),
259 ATTOS_PER_MS,
260 );
261 }
262
263 #[inline]
267 pub const fn sub_us(&mut self, n: i64) {
268 Self::add_attos_span(
269 &mut self.sec,
270 &mut self.attos,
271 n.saturating_neg(),
272 ATTOS_PER_US,
273 );
274 }
275
276 #[inline]
280 pub const fn sub_ns(&mut self, n: i64) {
281 Self::add_attos_span(
282 &mut self.sec,
283 &mut self.attos,
284 n.saturating_neg(),
285 ATTOS_PER_NS,
286 );
287 }
288
289 #[inline]
293 pub const fn sub_ps(&mut self, n: i64) {
294 Self::add_attos_span(
295 &mut self.sec,
296 &mut self.attos,
297 n.saturating_neg(),
298 ATTOS_PER_PS,
299 );
300 }
301
302 #[inline]
306 pub const fn sub_fs(&mut self, n: i64) {
307 Self::add_attos_span(
308 &mut self.sec,
309 &mut self.attos,
310 n.saturating_neg(),
311 ATTOS_PER_FS,
312 );
313 }
314
315 #[inline]
319 pub const fn sub_attos(&mut self, n: i64) {
320 Self::add_attos_span(&mut self.sec, &mut self.attos, n.saturating_neg(), 1);
321 }
322
323 #[inline]
325 pub const fn to_attos(&self) -> i128 {
326 (self.sec as i128) * ATTOS_PER_SEC_I128 + (self.attos as i128)
327 }
328
329 #[inline]
331 pub const fn to_ms(&self) -> i128 {
332 self.to_attos() / (ATTOS_PER_MS as i128)
333 }
334
335 #[inline]
337 pub const fn to_us(&self) -> i128 {
338 self.to_attos() / (ATTOS_PER_US as i128)
339 }
340
341 #[inline]
343 pub const fn to_ns(&self) -> i128 {
344 self.to_attos() / (ATTOS_PER_NS as i128)
345 }
346
347 #[inline]
349 pub const fn to_ps(&self) -> i128 {
350 self.to_attos() / (ATTOS_PER_PS as i128)
351 }
352
353 #[inline]
355 pub const fn to_fs(&self) -> i128 {
356 self.to_attos() / (ATTOS_PER_FS as i128)
357 }
358
359 pub(crate) const fn add_time(sec_a: i64, sub_a: u64, sec_b: i64, sub_b: u64) -> (i64, u64) {
361 let mut sec = sec_a.saturating_add(sec_b);
362 let mut attos = sub_a as i64 + sub_b as i64;
363
364 if attos >= ATTOS_PER_SEC as i64 {
365 if sec < i64::MAX {
366 sec = sec.saturating_add(1);
367 }
368 attos -= ATTOS_PER_SEC as i64;
369 } else if attos < 0 {
370 if sec > i64::MIN {
371 sec = sec.saturating_sub(1);
372 }
373 attos += ATTOS_PER_SEC as i64;
374 }
375
376 let attos = if sec == i64::MAX {
377 ATTOS_PER_SEC - 1
378 } else if sec == i64::MIN {
379 0
380 } else {
381 attos as u64
382 };
383
384 (sec, attos)
385 }
386
387 pub(crate) const fn sub_time(sec_a: i64, sub_a: u64, sec_b: i64, sub_b: u64) -> (i64, u64) {
389 let mut sec = sec_a.saturating_sub(sec_b);
390 let mut attos = sub_a as i64 - sub_b as i64;
391
392 if attos < 0 {
393 if sec > i64::MIN {
394 sec = sec.saturating_sub(1);
395 }
396 attos += ATTOS_PER_SEC as i64;
397 } else if attos >= ATTOS_PER_SEC as i64 {
398 if sec < i64::MAX {
399 sec = sec.saturating_add(1);
400 }
401 attos -= ATTOS_PER_SEC as i64;
402 }
403
404 let attos = if sec == i64::MAX {
405 ATTOS_PER_SEC - 1
406 } else if sec == i64::MIN {
407 0
408 } else {
409 attos as u64
410 };
411
412 (sec, attos)
413 }
414
415 #[inline(always)]
417 pub const fn is_zero(&self) -> bool {
418 self.sec == 0 && self.attos == 0
419 }
420
421 #[inline(always)]
423 pub const fn is_positive(&self) -> bool {
424 self.to_attos() > 0
425 }
426
427 pub const fn mul(self, rhs: i64) -> Self {
431 if rhs == 0 || self.is_zero() {
432 return Self::ZERO;
433 }
434 let total: i128 = self.to_attos().saturating_mul(rhs as i128);
435 Self::from_attos(total, Scale::TAI)
436 }
437
438 pub const fn div(self, rhs: i64) -> Self {
443 if rhs == 0 || self.is_zero() {
444 return Self::ZERO;
445 }
446 let total = self.to_attos();
447 let result = total / (rhs as i128);
448 Self::from_attos(result, Scale::TAI)
449 }
450
451 pub const fn floor(&self, unit: Self) -> Self {
454 if unit.is_zero() {
455 return *self;
456 }
457 let a = self.to_attos();
458 let b = unit.to_attos();
459 let q = safe_div_euc!(a, b, 0i128);
460 let result = q.wrapping_mul(b);
461 Self::from_attos(result, Scale::TAI)
462 }
463
464 pub const fn ceil(&self, unit: Self) -> Self {
467 if unit.is_zero() {
468 return *self;
469 }
470 let a = self.to_attos();
471 let b = unit.to_attos();
472 let neg_a = a.wrapping_neg();
474 let q = safe_div_euc!(neg_a, b, 0i128);
475 let q_ceil = q.wrapping_neg();
476 let result = q_ceil.wrapping_mul(b);
477 Self::from_attos(result, Scale::TAI)
478 }
479
480 pub const fn round(&self, unit: Self) -> Self {
489 if unit.is_zero() {
490 return *self;
491 }
492
493 let a = self.to_attos();
494 let b = unit.to_attos();
495
496 let abs_a = a.wrapping_abs();
497 let abs_b = b.wrapping_abs();
498
499 let q = safe_div_euc!(abs_a, abs_b, 0i128);
500 let r = safe_rem_euc!(abs_a, abs_b, 0i128);
501
502 let half = (abs_b + 1) / 2;
503
504 let q_rounded = if r >= half { q + 1 } else { q };
505
506 let rounded_abs = q_rounded.wrapping_mul(abs_b);
507
508 let result = if a < 0 { -rounded_abs } else { rounded_abs };
509
510 Self::from_attos(result, Scale::TAI)
511 }
512
513 pub const fn abs_div_floor(&self, unit: Self) -> usize {
517 if unit.is_zero() {
518 return 0;
519 }
520 let a = self.to_attos().wrapping_abs();
521 let b = unit.to_attos().wrapping_abs();
522 let q = safe_div_euc!(a, b, 0i128);
523
524 if q > (usize::MAX as i128) {
525 usize::MAX
526 } else {
527 q as usize
528 }
529 }
530
531 pub const fn mul_by_f(&self, rhs: Real) -> Self {
534 if rhs.is_nan() {
535 return Self::ZERO;
536 }
537 if rhs.is_infinite() {
538 if self.is_zero() {
539 return Self::ZERO;
540 }
541 let self_pos = self.sec > 0 || (self.sec == 0 && self.attos != 0);
542 return if (rhs > 0.0) == self_pos {
543 Self::MAX
544 } else {
545 Self::MIN
546 };
547 }
548 if self.is_zero() || rhs == 0.0 {
549 return Self::ZERO;
550 }
551
552 let self_attos = self.to_attos();
553 let max_attos = Self::MAX.to_attos();
554 let min_attos = Self::MIN.to_attos();
555
556 let int_part = if rhs >= (i128::MAX as Real) {
558 i128::MAX
559 } else if rhs <= (i128::MIN as Real) {
560 i128::MIN
561 } else {
562 floor_f(rhs) as i128
563 };
564
565 if int_part == i128::MAX || int_part == i128::MIN {
567 let self_pos = self.sec > 0 || (self.sec == 0 && self.attos != 0);
568 return if (rhs > 0.0) == self_pos {
569 Self::MAX
570 } else {
571 Self::MIN
572 };
573 }
574
575 let frac_part = rhs - f!(int_part); let int_attos = if int_part == 0 {
579 0
580 } else if int_part > 0 {
581 if self_attos > 0 {
582 if int_part > max_attos / self_attos {
583 max_attos
584 } else {
585 self_attos * int_part
586 }
587 } else {
588 let abs_self = self_attos.wrapping_neg();
589 let abs_min = min_attos.wrapping_neg();
590 if int_part > abs_min / abs_self {
591 min_attos
592 } else {
593 self_attos * int_part
594 }
595 }
596 } else {
597 if self_attos > 0 {
599 let abs_int = int_part.wrapping_neg();
600 let abs_min = min_attos.wrapping_neg();
601 if abs_int > abs_min / self_attos {
602 min_attos
603 } else {
604 self_attos * int_part
605 }
606 } else {
607 let abs_self = self_attos.wrapping_neg();
608 let abs_int = int_part.wrapping_neg();
609 if abs_int > max_attos / abs_self {
610 max_attos
611 } else {
612 self_attos * int_part
613 }
614 }
615 };
616
617 const SCALE: i128 = 1_000_000_000_000_000; let frac_scaled = (frac_part * (SCALE as Real)) as i128;
620
621 let frac_attos = if self_attos >= 0 {
622 let high = self_attos / SCALE;
623 let low = self_attos % SCALE;
624 let high_part = high * frac_scaled;
625 let low_part = (low * frac_scaled) / SCALE;
626 high_part + low_part
627 } else {
628 let abs_self = self_attos.wrapping_neg();
629 let high = abs_self / SCALE;
630 let low = abs_self % SCALE;
631 let high_part = high * frac_scaled;
632 let low_part = (low * frac_scaled) / SCALE;
633 let pos = high_part + low_part;
634 pos.wrapping_neg()
635 };
636
637 let total_attos = int_attos.saturating_add(frac_attos);
639 let clamped = if total_attos > max_attos {
640 max_attos
641 } else if total_attos < min_attos {
642 min_attos
643 } else {
644 total_attos
645 };
646
647 Self::from_attos(clamped, Scale::TAI)
648 }
649
650 #[inline]
652 pub const fn div_by_f(&self, rhs: Real) -> Self {
653 if rhs == 0.0 || rhs.is_nan() {
654 return if self.sec >= 0 { Self::MAX } else { Self::MIN };
655 }
656 self.mul_by_f(1.0 / rhs)
657 }
658
659 #[inline]
661 pub const fn div_by_2(&self) -> Self {
662 self.div_by_f(2.0)
663 }
664
665 #[doc(hidden)]
667 pub(crate) const fn add_attos_to(sec: &mut i64, attos: &mut u64, amount: u64) {
668 let total = *attos + amount;
669 let carry_sec = total / ATTOS_PER_SEC;
670 *attos = total % ATTOS_PER_SEC;
671 *sec = sec.saturating_add(carry_sec as i64);
672 }
673
674 #[doc(hidden)]
681 pub(crate) const fn add_attos_span(sec: &mut i64, attos: &mut u64, n: i64, unit: u64) {
682 if n == 0 {
683 return;
684 }
685
686 let mps = ATTOS_PER_SEC;
687
688 if n >= 0 {
689 let amount = (n as u64).saturating_mul(unit);
690 let total = attos.saturating_add(amount);
691
692 let carry = total / mps;
693 let new_frac = total % mps;
694
695 *sec = sec.saturating_add(carry as i64);
696 *attos = new_frac;
697 } else {
698 let amount = n.unsigned_abs().saturating_mul(unit);
699 let borrow_sec = amount / mps;
700 let borrow_frac = amount % mps;
701
702 *sec = sec.saturating_sub(borrow_sec as i64);
703
704 if *attos >= borrow_frac {
705 *attos -= borrow_frac;
706 } else {
707 *attos += mps - borrow_frac;
708 *sec = sec.saturating_sub(1);
709 }
710 }
711
712 if *sec == i64::MAX {
714 *attos = mps - 1;
715 } else if *sec == i64::MIN {
716 *attos = 0;
717 }
718 }
719
720 #[inline]
722 pub const fn to_sec(&mut self) -> i64 {
723 let Dt { sec, .. } = self.carry_attos();
724 sec
725 }
726
727 pub(crate) const fn diff_raw_internal(sec_a: i64, sub_a: u64, sec_b: i64, sub_b: u64) -> Self {
728 if sub_a >= sub_b {
729 Self {
730 sec: sec_a.saturating_sub(sec_b),
731 attos: sub_a - sub_b,
732 }
733 } else {
734 Self {
735 sec: sec_a.saturating_sub(sec_b).saturating_sub(1),
736 attos: sub_a.saturating_add(ATTOS_PER_SEC.saturating_sub(sub_b)),
737 }
738 }
739 }
740
741 #[inline(always)]
743 pub(crate) const fn clamp_i128_to_i64(x: i128) -> i64 {
744 let y = x as i64;
745 if x == y as i128 {
746 y
747 } else if x > 0 {
748 i64::MAX
749 } else {
750 i64::MIN
751 }
752 }
753
754 pub(crate) const fn clamp_u8(value: u8, min: u8, max: u8) -> u8 {
761 if value < min {
762 min
763 } else if value > max {
764 max
765 } else {
766 value
767 }
768 }
769
770 #[inline(always)]
772 pub const fn attos_to_sec_f(attos: u128) -> Real {
773 f!(attos) / ATTOS_PER_SECF
774 }
775
776 #[inline(always)]
778 pub const fn attos_to_sec(attos: i128) -> i128 {
779 attos / ATTOS_PER_SEC_I128
780 }
781
782 #[inline(always)]
784 pub const fn attos_to_ms(attos: i128) -> i128 {
785 attos / ATTOS_PER_MS_I128
786 }
787
788 #[inline(always)]
790 pub const fn attos_to_us(attos: i128) -> i128 {
791 attos / ATTOS_PER_US_I128
792 }
793
794 #[inline(always)]
796 pub const fn attos_to_ns(attos: i128) -> i128 {
797 attos / ATTOS_PER_NS_I128
798 }
799
800 #[inline(always)]
802 pub const fn attos_to_ps(attos: i128) -> i128 {
803 attos / ATTOS_PER_PS_I128
804 }
805
806 #[inline(always)]
808 pub const fn attos_to_fs(attos: i128) -> i128 {
809 attos / ATTOS_PER_FS_I128
810 }
811
812 #[inline]
828 pub const fn div_dt(self, rhs: Self) -> Real {
829 let a = self.to_sec_f();
830 let b = rhs.to_sec_f();
831
832 if b == 0.0 {
833 if a == 0.0 {
834 1.0
835 } else {
836 Real::INFINITY.copysign(a)
837 }
838 } else {
839 a / b
840 }
841 }
842}