1use crate::{
2 ATTOS_PER_FS, ATTOS_PER_MS, ATTOS_PER_NS, ATTOS_PER_PS, ATTOS_PER_SEC, ATTOS_PER_SEC_I128,
3 ATTOS_PER_SECF, ATTOS_PER_US, Dt, Real, TSpan, floor_f,
4};
5
6impl TSpan {
7 #[inline]
8 pub const fn add(self, rhs: Self) -> Self {
9 let (sec, attos) = Self::add_time(self.sec, self.attos, rhs.sec, rhs.attos);
10 Self { sec, attos }
11 }
12
13 #[inline]
14 pub const fn sub(self, rhs: Self) -> Self {
15 let (sec, attos) = Self::sub_time(self.sec, self.attos, rhs.sec, rhs.attos);
16 Self { sec, attos }
17 }
18
19 pub(crate) const fn add_time(sec_a: i64, sub_a: u64, sec_b: i64, sub_b: u64) -> (i64, u64) {
21 let mut sec = sec_a.saturating_add(sec_b);
22 let mut attos = sub_a as i64 + sub_b as i64;
23
24 if attos >= ATTOS_PER_SEC as i64 {
25 if sec < i64::MAX {
26 sec = sec.saturating_add(1);
27 }
28 attos -= ATTOS_PER_SEC as i64;
29 } else if attos < 0 {
30 if sec > i64::MIN {
31 sec = sec.saturating_sub(1);
32 }
33 attos += ATTOS_PER_SEC as i64;
34 }
35
36 let attos = if sec == i64::MAX {
37 ATTOS_PER_SEC - 1
38 } else if sec == i64::MIN {
39 0
40 } else {
41 attos as u64
42 };
43
44 (sec, attos)
45 }
46
47 pub(crate) const fn sub_time(sec_a: i64, sub_a: u64, sec_b: i64, sub_b: u64) -> (i64, u64) {
49 let mut sec = sec_a.saturating_sub(sec_b);
50 let mut attos = sub_a as i64 - sub_b as i64;
51
52 if attos < 0 {
53 if sec > i64::MIN {
54 sec = sec.saturating_sub(1);
55 }
56 attos += ATTOS_PER_SEC as i64;
57 } else if attos >= ATTOS_PER_SEC as i64 {
58 if sec < i64::MAX {
59 sec = sec.saturating_add(1);
60 }
61 attos -= ATTOS_PER_SEC as i64;
62 }
63
64 let attos = if sec == i64::MAX {
65 ATTOS_PER_SEC - 1
66 } else if sec == i64::MIN {
67 0
68 } else {
69 attos as u64
70 };
71
72 (sec, attos)
73 }
74
75 #[inline]
77 pub const fn is_zero(self) -> bool {
78 self.sec == 0 && self.attos == 0
79 }
80
81 #[inline]
85 pub const fn to_sec_f(self) -> Real {
86 f!(self.sec) + f!(self.attos) / ATTOS_PER_SECF
87 }
88
89 pub const fn mul(self, rhs: i64) -> Self {
93 if rhs == 0 || self.is_zero() {
94 return Self::ZERO;
95 }
96 let total: i128 = self.to_attos().saturating_mul(rhs as i128);
97 Self::from_attos(total)
98 }
99
100 pub const fn div(self, rhs: i64) -> Self {
106 if rhs == 0 || self.is_zero() {
107 return Self::ZERO;
108 }
109 let total = self.to_attos();
110 let result = total.div_euclid(rhs as i128);
111 Self::from_attos(result)
112 }
113
114 pub const fn floor(self, unit: TSpan) -> TSpan {
117 if unit.is_zero() {
118 return self;
119 }
120 let a = self.to_attos();
121 let b = unit.to_attos();
122 let q = a.div_euclid(b);
123 let result = q.wrapping_mul(b);
124 Self::from_attos(result)
125 }
126
127 pub const fn ceil(self, unit: TSpan) -> TSpan {
130 if unit.is_zero() {
131 return self;
132 }
133 let a = self.to_attos();
134 let b = unit.to_attos();
135 let neg_a = a.wrapping_neg();
137 let q = neg_a.div_euclid(b);
138 let q_ceil = q.wrapping_neg();
139 let result = q_ceil.wrapping_mul(b);
140 Self::from_attos(result)
141 }
142
143 pub const fn round(self, unit: TSpan) -> TSpan {
147 if unit.is_zero() {
148 return self;
149 }
150 let a = self.to_attos();
151 let b = unit.to_attos();
152
153 let q = a.div_euclid(b);
154 let r = a.rem_euclid(b);
155
156 let abs_b = b.wrapping_abs();
158 let two = 2i128;
159 let half = (abs_b + 1) / two;
160
161 if r >= half {
162 let one = 1i128;
164 let q_rounded = if a < 0 { q - one } else { q + one };
165 let result = q_rounded.wrapping_mul(b);
166 Self::from_attos(result)
167 } else {
168 let result = q.wrapping_mul(b);
169 Self::from_attos(result)
170 }
171 }
172
173 pub const fn abs_div_floor(self, unit: TSpan) -> usize {
177 if unit.is_zero() {
178 return 0;
179 }
180 let a = self.to_attos().wrapping_abs();
181 let b = unit.to_attos().wrapping_abs();
182 let q = a.div_euclid(b);
183
184 if q > (usize::MAX as i128) {
185 usize::MAX
186 } else {
187 q as usize
188 }
189 }
190
191 pub const fn mul_by_f(self, rhs: Real) -> Self {
194 if rhs.is_nan() {
195 return Self::ZERO;
196 }
197 if rhs.is_infinite() {
198 if self.is_zero() {
199 return Self::ZERO;
200 }
201 let self_pos = self.sec > 0 || (self.sec == 0 && self.attos != 0);
202 return if (rhs > 0.0) == self_pos {
203 Self::MAX
204 } else {
205 Self::MIN
206 };
207 }
208 if self.is_zero() || rhs == 0.0 {
209 return Self::ZERO;
210 }
211
212 let int_part = floor_f(rhs) as i128; let frac_part = rhs - f!(int_part); let int_result = Self::from_attos(self.to_attos().saturating_mul(int_part));
217
218 const SCALE: i128 = 1_000_000_000_000_000; let frac_scaled = (frac_part * (SCALE as Real)) as i128;
221 let frac_product = self.to_attos().saturating_mul(frac_scaled);
222 let frac_attos = frac_product / SCALE;
223 let frac_result = Self::from_attos(frac_attos);
224
225 int_result.add(frac_result)
226 }
227
228 #[inline]
230 pub const fn div_by_f(self, rhs: Real) -> Self {
231 if rhs == 0.0 || rhs.is_nan() {
232 return if self.sec >= 0 { Self::MAX } else { Self::MIN };
233 }
234 self.mul_by_f(1.0 / rhs)
235 }
236
237 #[inline]
239 pub const fn div_by_2(self) -> TSpan {
240 self.div_by_f(2.0)
241 }
242
243 #[inline]
245 pub const fn add_1sec(&mut self) {
246 self.sec = self.sec.saturating_add(1);
247 }
248
249 #[inline]
251 pub const fn add_1min(&mut self) {
252 self.sec = self.sec.saturating_add(60);
253 }
254
255 #[inline]
257 pub const fn add_1hr(&mut self) {
258 self.sec = self.sec.saturating_add(3600);
259 }
260
261 #[inline]
265 pub const fn add_1ms(&mut self) {
266 TSpan::add_attos_to(&mut self.sec, &mut self.attos, ATTOS_PER_MS);
267 }
268
269 #[inline]
273 pub const fn add_1us(&mut self) {
274 TSpan::add_attos_to(&mut self.sec, &mut self.attos, ATTOS_PER_US);
275 }
276
277 #[inline]
281 pub const fn add_1ns(&mut self) {
282 TSpan::add_attos_to(&mut self.sec, &mut self.attos, ATTOS_PER_NS);
283 }
284
285 #[inline]
287 pub const fn add_sec(&mut self, n: i64) {
288 self.sec = self.sec.saturating_add(n);
289 }
290
291 #[inline]
293 pub const fn add_min(&mut self, n: i64) {
294 self.sec = self.sec.saturating_add(n.saturating_mul(60));
295 }
296
297 #[inline]
299 pub const fn add_hr(&mut self, n: i64) {
300 self.sec = self.sec.saturating_add(n.saturating_mul(3600));
301 }
302
303 #[inline]
307 pub const fn add_ms(&mut self, n: i64) {
308 TSpan::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_MS);
309 }
310
311 #[inline]
315 pub const fn add_us(&mut self, n: i64) {
316 TSpan::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_US);
317 }
318
319 #[inline]
323 pub const fn add_ns(&mut self, n: i64) {
324 TSpan::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_NS);
325 }
326
327 #[inline]
331 pub const fn add_ps(&mut self, n: i64) {
332 TSpan::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_PS);
333 }
334
335 #[inline]
339 pub const fn add_fs(&mut self, n: i64) {
340 TSpan::add_attos_span(&mut self.sec, &mut self.attos, n, ATTOS_PER_FS);
341 }
342
343 #[inline]
347 pub const fn add_attos(&mut self, n: i64) {
348 TSpan::add_attos_span(&mut self.sec, &mut self.attos, n, 1);
349 }
350
351 #[inline]
353 pub const fn sub_1hr(&mut self) {
354 self.sec = self.sec.saturating_sub(3600);
355 }
356
357 #[inline]
359 pub const fn sub_1min(&mut self) {
360 self.sec = self.sec.saturating_sub(60);
361 }
362
363 #[inline]
365 pub const fn sub_1sec(&mut self) {
366 self.sec = self.sec.saturating_sub(1);
367 }
368
369 #[inline]
373 pub const fn sub_1ms(&mut self) {
374 TSpan::add_attos_span(&mut self.sec, &mut self.attos, -1, ATTOS_PER_MS);
375 }
376
377 #[inline]
381 pub const fn sub_1us(&mut self) {
382 TSpan::add_attos_span(&mut self.sec, &mut self.attos, -1, ATTOS_PER_US);
383 }
384
385 #[inline]
389 pub const fn sub_1ns(&mut self) {
390 TSpan::add_attos_span(&mut self.sec, &mut self.attos, -1, ATTOS_PER_NS);
391 }
392
393 #[inline]
395 pub const fn sub_sec(&mut self, n: i64) {
396 self.sec = self.sec.saturating_sub(n);
397 }
398
399 #[inline]
401 pub const fn sub_min(&mut self, n: i64) {
402 self.sec = self.sec.saturating_sub(n.saturating_mul(60));
403 }
404
405 #[inline]
407 pub const fn sub_hr(&mut self, n: i64) {
408 self.sec = self.sec.saturating_sub(n.saturating_mul(3600));
409 }
410
411 #[inline]
415 pub const fn sub_ms(&mut self, n: i64) {
416 TSpan::add_attos_span(
417 &mut self.sec,
418 &mut self.attos,
419 n.saturating_neg(),
420 ATTOS_PER_MS,
421 );
422 }
423
424 #[inline]
428 pub const fn sub_us(&mut self, n: i64) {
429 TSpan::add_attos_span(
430 &mut self.sec,
431 &mut self.attos,
432 n.saturating_neg(),
433 ATTOS_PER_US,
434 );
435 }
436
437 #[inline]
441 pub const fn sub_ns(&mut self, n: i64) {
442 TSpan::add_attos_span(
443 &mut self.sec,
444 &mut self.attos,
445 n.saturating_neg(),
446 ATTOS_PER_NS,
447 );
448 }
449
450 #[inline]
454 pub const fn sub_ps(&mut self, n: i64) {
455 TSpan::add_attos_span(
456 &mut self.sec,
457 &mut self.attos,
458 n.saturating_neg(),
459 ATTOS_PER_PS,
460 );
461 }
462
463 #[inline]
467 pub const fn sub_fs(&mut self, n: i64) {
468 TSpan::add_attos_span(
469 &mut self.sec,
470 &mut self.attos,
471 n.saturating_neg(),
472 ATTOS_PER_FS,
473 );
474 }
475
476 #[inline]
480 pub const fn sub_attos(&mut self, n: i64) {
481 TSpan::add_attos_span(&mut self.sec, &mut self.attos, n.saturating_neg(), 1);
482 }
483
484 #[doc(hidden)]
486 pub(crate) const fn add_attos_to(sec: &mut i64, attos: &mut u64, amount: u64) {
487 let total = *attos + amount;
488 let carry_sec = total / ATTOS_PER_SEC;
489 *attos = total % ATTOS_PER_SEC;
490 *sec = sec.saturating_add(carry_sec as i64);
491 }
492
493 #[doc(hidden)]
500 pub(crate) const fn add_attos_span(sec: &mut i64, attos: &mut u64, n: i64, unit: u64) {
501 if n == 0 {
502 return;
503 }
504
505 let mps = ATTOS_PER_SEC;
506
507 if n >= 0 {
508 let amount = (n as u64).saturating_mul(unit);
509 let total = attos.saturating_add(amount);
510
511 let carry = total / mps;
512 let new_frac = total % mps;
513
514 *sec = sec.saturating_add(carry as i64);
515 *attos = new_frac;
516 } else {
517 let amount = n.unsigned_abs().saturating_mul(unit);
518 let borrow_sec = amount / mps;
519 let borrow_frac = amount % mps;
520
521 *sec = sec.saturating_sub(borrow_sec as i64);
522
523 if *attos >= borrow_frac {
524 *attos -= borrow_frac;
525 } else {
526 *attos += mps - borrow_frac;
527 *sec = sec.saturating_sub(1);
528 }
529 }
530
531 if *sec == i64::MAX {
533 *attos = mps - 1;
534 } else if *sec == i64::MIN {
535 *attos = 0;
536 }
537 }
538
539 #[inline]
541 pub const fn to_attos(self) -> i128 {
542 (self.sec as i128) * ATTOS_PER_SEC_I128 + (self.attos as i128)
543 }
544
545 #[inline]
547 pub const fn to_sec(&mut self) -> i64 {
548 self.carry_over();
549 self.sec
550 }
551
552 #[inline]
554 pub const fn to_ms(self) -> i128 {
555 self.to_attos() / (ATTOS_PER_MS as i128)
556 }
557
558 #[inline]
560 pub const fn to_us(self) -> i128 {
561 self.to_attos() / (ATTOS_PER_US as i128)
562 }
563
564 #[inline]
566 pub const fn to_ns(self) -> i128 {
567 self.to_attos() / (ATTOS_PER_NS as i128)
568 }
569
570 #[inline]
572 pub const fn to_ps(self) -> i128 {
573 self.to_attos() / (ATTOS_PER_PS as i128)
574 }
575
576 #[inline]
578 pub const fn to_fs(self) -> i128 {
579 self.to_attos() / (ATTOS_PER_FS as i128)
580 }
581
582 #[inline]
586 pub const fn to_diff(self, rhs: Self) -> Self {
587 Self::diff_raw(self.sec, self.attos, rhs.sec, rhs.attos)
588 }
589
590 #[inline]
592 pub const fn to_diff_tp(self, rhs: Dt) -> Self {
593 Self::diff_raw(self.sec, self.attos, rhs.sec, rhs.attos)
594 }
595
596 #[inline]
597 pub(crate) const fn diff_raw(sec_a: i64, sub_a: u64, sec_b: i64, sub_b: u64) -> Self {
598 if sub_a >= sub_b {
599 Self {
600 sec: sec_a.saturating_sub(sec_b),
601 attos: sub_a - sub_b,
602 }
603 } else {
604 Self {
605 sec: sec_a.saturating_sub(sec_b).saturating_sub(1),
606 attos: sub_a.saturating_add(ATTOS_PER_SEC.saturating_sub(sub_b)),
607 }
608 }
609 }
610}