1use std::fmt::Display;
39use std::str::FromStr;
40
41use crate::f64::consts::SECONDS_PER_ATTOSECOND;
42use crate::i64::consts::{
43 ATTOSECONDS_IN_FEMTOSECOND, ATTOSECONDS_IN_MICROSECOND, ATTOSECONDS_IN_MILLISECOND,
44 ATTOSECONDS_IN_NANOSECOND, ATTOSECONDS_IN_PICOSECOND, ATTOSECONDS_IN_SECOND,
45};
46use thiserror::Error;
47
48const FACTORS: [i64; 6] = [
49 ATTOSECONDS_IN_MILLISECOND,
50 ATTOSECONDS_IN_MICROSECOND,
51 ATTOSECONDS_IN_NANOSECOND,
52 ATTOSECONDS_IN_PICOSECOND,
53 ATTOSECONDS_IN_FEMTOSECOND,
54 1,
55];
56
57#[derive(Debug, Default, Clone, Copy)]
66#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
67pub struct Subsecond([u32; 6]);
68
69impl Subsecond {
70 pub const ZERO: Self = Self::new();
72
73 pub const fn new() -> Self {
84 Self([0; 6])
85 }
86
87 pub const fn from_attoseconds(attoseconds: i64) -> Self {
108 let attoseconds_normalized = if attoseconds < 0 {
109 ATTOSECONDS_IN_SECOND + attoseconds
110 } else {
111 attoseconds
112 } as i128;
113 let mut this = Self::new();
114 this.0[0] = ((attoseconds_normalized / ATTOSECONDS_IN_MILLISECOND as i128) % 1000) as u32;
115 this.0[1] = ((attoseconds_normalized / ATTOSECONDS_IN_MICROSECOND as i128) % 1000) as u32;
116 this.0[2] = ((attoseconds_normalized / ATTOSECONDS_IN_NANOSECOND as i128) % 1000) as u32;
117 this.0[3] = ((attoseconds_normalized / ATTOSECONDS_IN_PICOSECOND as i128) % 1000) as u32;
118 this.0[4] = ((attoseconds_normalized / ATTOSECONDS_IN_FEMTOSECOND as i128) % 1000) as u32;
119 this.0[5] = (attoseconds_normalized % 1000) as u32;
120 this
121 }
122
123 pub const fn from_f64(value: f64) -> Option<Self> {
124 if !value.is_finite() {
125 return None;
126 }
127 let rem = value % 1.0;
128 let rem = if rem < 0.0 { rem + 1.0 } else { rem };
130 let attoseconds = (rem / crate::f64::consts::SECONDS_PER_ATTOSECOND).round() as i64;
132 Some(Self::from_attoseconds(attoseconds))
133 }
134
135 pub const fn set_milliseconds(mut self, milliseconds: u32) -> Self {
149 debug_assert!(milliseconds < 1000);
150 self.0[0] = milliseconds % 1000;
151 self
152 }
153
154 pub const fn set_microseconds(mut self, microseconds: u32) -> Self {
159 debug_assert!(microseconds < 1000);
160 self.0[1] = microseconds % 1000;
161 self
162 }
163
164 pub const fn set_nanoseconds(mut self, nanoseconds: u32) -> Self {
169 debug_assert!(nanoseconds < 1000);
170 self.0[2] = nanoseconds % 1000;
171 self
172 }
173
174 pub const fn set_picoseconds(mut self, picoseconds: u32) -> Self {
179 debug_assert!(picoseconds < 1000);
180 self.0[3] = picoseconds % 1000;
181 self
182 }
183
184 pub const fn set_femtoseconds(mut self, femtoseconds: u32) -> Self {
189 debug_assert!(femtoseconds < 1000);
190 self.0[4] = femtoseconds % 1000;
191 self
192 }
193
194 pub const fn set_attoseconds(mut self, attoseconds: u32) -> Self {
199 debug_assert!(attoseconds < 1000);
200 self.0[5] = attoseconds % 1000;
201 self
202 }
203
204 pub const fn as_attoseconds(&self) -> i64 {
215 self.0[0] as i64 * FACTORS[0]
216 + self.0[1] as i64 * FACTORS[1]
217 + self.0[2] as i64 * FACTORS[2]
218 + self.0[3] as i64 * FACTORS[3]
219 + self.0[4] as i64 * FACTORS[4]
220 + self.0[5] as i64 * FACTORS[5]
221 }
222
223 pub const fn as_seconds_f64(&self) -> f64 {
234 self.as_attoseconds() as f64 * SECONDS_PER_ATTOSECOND
235 }
236
237 pub const fn milliseconds(&self) -> u32 {
241 self.0[0]
242 }
243
244 pub const fn microseconds(&self) -> u32 {
248 self.0[1]
249 }
250
251 pub const fn nanoseconds(&self) -> u32 {
255 self.0[2]
256 }
257
258 pub const fn picoseconds(&self) -> u32 {
262 self.0[3]
263 }
264
265 pub const fn femtoseconds(&self) -> u32 {
269 self.0[4]
270 }
271
272 pub const fn attoseconds(&self) -> u32 {
276 self.0[5]
277 }
278}
279
280impl Ord for Subsecond {
281 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
282 self.as_attoseconds().cmp(&other.as_attoseconds())
283 }
284}
285
286impl PartialOrd for Subsecond {
287 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
288 Some(self.cmp(other))
289 }
290}
291
292impl PartialEq for Subsecond {
293 fn eq(&self, other: &Self) -> bool {
294 self.as_attoseconds() == other.as_attoseconds()
295 }
296}
297
298impl Eq for Subsecond {}
299
300const DIGITS: usize = 18;
301
302impl Display for Subsecond {
303 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304 "0.".fmt(f)?;
305 let mut s = self.as_attoseconds().to_string();
306 if s.len() < DIGITS {
307 s = format!("{:0>width$}", s, width = DIGITS);
308 }
309 let p = f.precision().unwrap_or(3).clamp(0, DIGITS);
310 s[0..p].fmt(f)
311 }
312}
313
314#[derive(Debug, Error)]
319#[error("could not parse subsecond from {0}")]
320pub struct SubsecondParseError(String);
321
322impl FromStr for Subsecond {
323 type Err = SubsecondParseError;
324
325 fn from_str(s: &str) -> Result<Self, Self::Err> {
326 let mut this = Self::default();
327
328 if s.is_empty() {
329 return Ok(this);
330 }
331
332 if s.chars().any(|c| !c.is_numeric()) {
333 return Err(SubsecondParseError(s.to_owned()));
334 }
335 let n = s.len();
336 if n > DIGITS {
337 return Err(SubsecondParseError(s.to_owned()));
338 }
339
340 let rem = n % 3;
341 let s = if rem != 0 {
342 let width = n + 3 - rem;
343 format!("{:0<width$}", s)
344 } else {
345 s.to_owned()
346 };
347
348 for i in (0..s.len()).step_by(3) {
349 this.0[i / 3] = s[i..i + 3].parse().unwrap();
350 }
351
352 Ok(this)
353 }
354}
355
356#[cfg(test)]
357mod tests {
358 use super::*;
359
360 #[test]
361 fn test_subsecond() {
362 let s = Subsecond::new()
363 .set_milliseconds(123)
364 .set_microseconds(456)
365 .set_nanoseconds(789)
366 .set_picoseconds(123)
367 .set_femtoseconds(456)
368 .set_attoseconds(789);
369
370 assert_eq!(s.as_attoseconds(), 123456789123456789);
371 assert_eq!(s.as_seconds_f64(), 0.1234567891234568);
372 assert_eq!(s.milliseconds(), 123);
373 assert_eq!(s.microseconds(), 456);
374 assert_eq!(s.nanoseconds(), 789);
375 assert_eq!(s.picoseconds(), 123);
376 assert_eq!(s.femtoseconds(), 456);
377 assert_eq!(s.attoseconds(), 789);
378 }
379
380 #[test]
381 fn test_subsecond_from_attoseconds() {
382 let s = Subsecond::from_attoseconds(123456789123456789);
383
384 assert_eq!(s.as_attoseconds(), 123456789123456789);
385 assert_eq!(s.as_seconds_f64(), 0.1234567891234568);
386 assert_eq!(s.milliseconds(), 123);
387 assert_eq!(s.microseconds(), 456);
388 assert_eq!(s.nanoseconds(), 789);
389 assert_eq!(s.picoseconds(), 123);
390 assert_eq!(s.femtoseconds(), 456);
391 assert_eq!(s.attoseconds(), 789);
392 }
393
394 #[test]
395 fn test_subsecond_display() {
396 let s = Subsecond::new()
397 .set_milliseconds(123)
398 .set_microseconds(456)
399 .set_nanoseconds(789)
400 .set_picoseconds(123)
401 .set_femtoseconds(456)
402 .set_attoseconds(789);
403
404 assert_eq!(format!("{}", s), "0.123");
405 assert_eq!(format!("{:.6}", s), "0.123456");
406 assert_eq!(format!("{:.18}", s), "0.123456789123456789");
407 }
408
409 #[test]
410 fn test_subsecond_parse() {
411 let exp = Subsecond::new().set_milliseconds(123).set_microseconds(400);
412 let act: Subsecond = "1234".parse().unwrap();
413 assert_eq!(act, exp);
414
415 let exp = Subsecond::new()
416 .set_milliseconds(123)
417 .set_microseconds(456)
418 .set_nanoseconds(789)
419 .set_picoseconds(123)
420 .set_femtoseconds(456)
421 .set_attoseconds(789);
422 let act: Subsecond = "123456789123456789".parse().unwrap();
423 assert_eq!(act, exp);
424 }
425
426 #[test]
427 #[should_panic]
428 fn test_subsecond_parse_error() {
429 "123foo".parse::<Subsecond>().unwrap();
430 }
431
432 #[test]
433 fn test_subsecond_from_attoseconds_negative() {
434 let s = Subsecond::from_attoseconds(-1);
436 assert_eq!(s.as_attoseconds(), 999999999999999999);
437 assert_eq!(s.milliseconds(), 999);
438 assert_eq!(s.microseconds(), 999);
439 assert_eq!(s.nanoseconds(), 999);
440 assert_eq!(s.picoseconds(), 999);
441 assert_eq!(s.femtoseconds(), 999);
442 assert_eq!(s.attoseconds(), 999);
443 }
444
445 #[test]
446 fn test_subsecond_from_attoseconds_zero() {
447 let s = Subsecond::from_attoseconds(0);
448 assert_eq!(s.as_attoseconds(), 0);
449 assert_eq!(s, Subsecond::ZERO);
450 }
451
452 #[test]
453 fn test_subsecond_from_attoseconds_max() {
454 let max = ATTOSECONDS_IN_SECOND - 1;
456 let s = Subsecond::from_attoseconds(max);
457 assert_eq!(s.as_attoseconds(), max);
458 assert_eq!(s.milliseconds(), 999);
459 assert_eq!(s.microseconds(), 999);
460 assert_eq!(s.nanoseconds(), 999);
461 assert_eq!(s.picoseconds(), 999);
462 assert_eq!(s.femtoseconds(), 999);
463 assert_eq!(s.attoseconds(), 999);
464 }
465
466 #[test]
467 fn test_subsecond_from_attoseconds_overflow() {
468 let s = Subsecond::from_attoseconds(ATTOSECONDS_IN_SECOND);
470 assert_eq!(s.as_attoseconds(), 0);
471
472 let s = Subsecond::from_attoseconds(ATTOSECONDS_IN_SECOND + 123);
473 assert_eq!(s.as_attoseconds(), 123);
474 }
475
476 #[test]
477 fn test_subsecond_set_methods_max_value() {
478 let s = Subsecond::new().set_milliseconds(999);
480 assert_eq!(s.milliseconds(), 999);
481
482 let s = Subsecond::new().set_microseconds(999);
483 assert_eq!(s.microseconds(), 999);
484
485 let s = Subsecond::new().set_nanoseconds(999);
486 assert_eq!(s.nanoseconds(), 999);
487 }
488
489 #[test]
490 fn test_subsecond_display_edge_cases() {
491 assert_eq!(format!("{}", Subsecond::ZERO), "0.000");
493
494 let s = Subsecond::new().set_milliseconds(123);
496 assert_eq!(format!("{:.0}", s), "");
497
498 assert_eq!(format!("{:.25}", s), "0.123000000000000000");
500 }
501
502 #[test]
503 fn test_subsecond_parse_edge_cases() {
504 let s: Subsecond = "".parse().unwrap();
506 assert_eq!(s, Subsecond::ZERO);
507
508 let s: Subsecond = "1".parse().unwrap();
510 assert_eq!(s.milliseconds(), 100);
511
512 let s: Subsecond = "12".parse().unwrap();
514 assert_eq!(s.milliseconds(), 120);
515
516 let s: Subsecond = "999999999999999999".parse().unwrap();
518 assert_eq!(s.as_attoseconds(), 999999999999999999);
519 }
520
521 #[test]
522 fn test_subsecond_parse_too_long() {
523 let result = "1234567890123456789".parse::<Subsecond>();
525 assert!(result.is_err());
526 }
527
528 #[test]
529 fn test_subsecond_ordering() {
530 let a = Subsecond::from_attoseconds(100);
531 let b = Subsecond::from_attoseconds(200);
532 let c = Subsecond::from_attoseconds(200);
533
534 assert!(a < b);
535 assert!(b > a);
536 assert_eq!(b, c);
537 assert!(b <= c);
538 assert!(b >= c);
539 }
540
541 #[test]
542 fn test_subsecond_equality() {
543 let a = Subsecond::new().set_milliseconds(123);
544 let b = Subsecond::from_attoseconds(123000000000000000);
545
546 assert_eq!(a, b);
547 assert_eq!(a.as_attoseconds(), b.as_attoseconds());
548 }
549}