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> {
127 if !value.is_finite() {
128 return None;
129 }
130 let rem = value % 1.0;
131 let rem = if rem < 0.0 { rem + 1.0 } else { rem };
133 let attoseconds = (rem / crate::f64::consts::SECONDS_PER_ATTOSECOND).round() as i64;
135 Some(Self::from_attoseconds(attoseconds))
136 }
137
138 pub const fn set_milliseconds(mut self, milliseconds: u32) -> Self {
152 debug_assert!(milliseconds < 1000);
153 self.0[0] = milliseconds % 1000;
154 self
155 }
156
157 pub const fn set_microseconds(mut self, microseconds: u32) -> Self {
162 debug_assert!(microseconds < 1000);
163 self.0[1] = microseconds % 1000;
164 self
165 }
166
167 pub const fn set_nanoseconds(mut self, nanoseconds: u32) -> Self {
172 debug_assert!(nanoseconds < 1000);
173 self.0[2] = nanoseconds % 1000;
174 self
175 }
176
177 pub const fn set_picoseconds(mut self, picoseconds: u32) -> Self {
182 debug_assert!(picoseconds < 1000);
183 self.0[3] = picoseconds % 1000;
184 self
185 }
186
187 pub const fn set_femtoseconds(mut self, femtoseconds: u32) -> Self {
192 debug_assert!(femtoseconds < 1000);
193 self.0[4] = femtoseconds % 1000;
194 self
195 }
196
197 pub const fn set_attoseconds(mut self, attoseconds: u32) -> Self {
202 debug_assert!(attoseconds < 1000);
203 self.0[5] = attoseconds % 1000;
204 self
205 }
206
207 pub const fn as_attoseconds(&self) -> i64 {
218 self.0[0] as i64 * FACTORS[0]
219 + self.0[1] as i64 * FACTORS[1]
220 + self.0[2] as i64 * FACTORS[2]
221 + self.0[3] as i64 * FACTORS[3]
222 + self.0[4] as i64 * FACTORS[4]
223 + self.0[5] as i64 * FACTORS[5]
224 }
225
226 pub const fn as_seconds_f64(&self) -> f64 {
237 self.as_attoseconds() as f64 * SECONDS_PER_ATTOSECOND
238 }
239
240 pub const fn milliseconds(&self) -> u32 {
244 self.0[0]
245 }
246
247 pub const fn microseconds(&self) -> u32 {
251 self.0[1]
252 }
253
254 pub const fn nanoseconds(&self) -> u32 {
258 self.0[2]
259 }
260
261 pub const fn picoseconds(&self) -> u32 {
265 self.0[3]
266 }
267
268 pub const fn femtoseconds(&self) -> u32 {
272 self.0[4]
273 }
274
275 pub const fn attoseconds(&self) -> u32 {
279 self.0[5]
280 }
281}
282
283impl Ord for Subsecond {
284 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
285 self.as_attoseconds().cmp(&other.as_attoseconds())
286 }
287}
288
289impl PartialOrd for Subsecond {
290 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
291 Some(self.cmp(other))
292 }
293}
294
295impl PartialEq for Subsecond {
296 fn eq(&self, other: &Self) -> bool {
297 self.as_attoseconds() == other.as_attoseconds()
298 }
299}
300
301impl Eq for Subsecond {}
302
303const DIGITS: usize = 18;
304
305impl Display for Subsecond {
306 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
307 "0.".fmt(f)?;
308 let mut s = self.as_attoseconds().to_string();
309 if s.len() < DIGITS {
310 s = format!("{:0>width$}", s, width = DIGITS);
311 }
312 let p = f.precision().unwrap_or(3).clamp(0, DIGITS);
313 s[0..p].fmt(f)
314 }
315}
316
317#[derive(Debug, Error)]
322#[error("could not parse subsecond from {0}")]
323pub struct SubsecondParseError(String);
324
325impl FromStr for Subsecond {
326 type Err = SubsecondParseError;
327
328 fn from_str(s: &str) -> Result<Self, Self::Err> {
329 let mut this = Self::default();
330
331 if s.is_empty() {
332 return Ok(this);
333 }
334
335 if s.chars().any(|c| !c.is_numeric()) {
336 return Err(SubsecondParseError(s.to_owned()));
337 }
338 let n = s.len();
339 if n > DIGITS {
340 return Err(SubsecondParseError(s.to_owned()));
341 }
342
343 let rem = n % 3;
344 let s = if rem != 0 {
345 let width = n + 3 - rem;
346 format!("{:0<width$}", s)
347 } else {
348 s.to_owned()
349 };
350
351 for i in (0..s.len()).step_by(3) {
352 this.0[i / 3] = s[i..i + 3].parse().unwrap();
353 }
354
355 Ok(this)
356 }
357}
358
359#[cfg(test)]
360mod tests {
361 use super::*;
362
363 #[test]
364 fn test_subsecond() {
365 let s = Subsecond::new()
366 .set_milliseconds(123)
367 .set_microseconds(456)
368 .set_nanoseconds(789)
369 .set_picoseconds(123)
370 .set_femtoseconds(456)
371 .set_attoseconds(789);
372
373 assert_eq!(s.as_attoseconds(), 123456789123456789);
374 assert_eq!(s.as_seconds_f64(), 0.1234567891234568);
375 assert_eq!(s.milliseconds(), 123);
376 assert_eq!(s.microseconds(), 456);
377 assert_eq!(s.nanoseconds(), 789);
378 assert_eq!(s.picoseconds(), 123);
379 assert_eq!(s.femtoseconds(), 456);
380 assert_eq!(s.attoseconds(), 789);
381 }
382
383 #[test]
384 fn test_subsecond_from_attoseconds() {
385 let s = Subsecond::from_attoseconds(123456789123456789);
386
387 assert_eq!(s.as_attoseconds(), 123456789123456789);
388 assert_eq!(s.as_seconds_f64(), 0.1234567891234568);
389 assert_eq!(s.milliseconds(), 123);
390 assert_eq!(s.microseconds(), 456);
391 assert_eq!(s.nanoseconds(), 789);
392 assert_eq!(s.picoseconds(), 123);
393 assert_eq!(s.femtoseconds(), 456);
394 assert_eq!(s.attoseconds(), 789);
395 }
396
397 #[test]
398 fn test_subsecond_display() {
399 let s = Subsecond::new()
400 .set_milliseconds(123)
401 .set_microseconds(456)
402 .set_nanoseconds(789)
403 .set_picoseconds(123)
404 .set_femtoseconds(456)
405 .set_attoseconds(789);
406
407 assert_eq!(format!("{}", s), "0.123");
408 assert_eq!(format!("{:.6}", s), "0.123456");
409 assert_eq!(format!("{:.18}", s), "0.123456789123456789");
410 }
411
412 #[test]
413 fn test_subsecond_parse() {
414 let exp = Subsecond::new().set_milliseconds(123).set_microseconds(400);
415 let act: Subsecond = "1234".parse().unwrap();
416 assert_eq!(act, exp);
417
418 let exp = Subsecond::new()
419 .set_milliseconds(123)
420 .set_microseconds(456)
421 .set_nanoseconds(789)
422 .set_picoseconds(123)
423 .set_femtoseconds(456)
424 .set_attoseconds(789);
425 let act: Subsecond = "123456789123456789".parse().unwrap();
426 assert_eq!(act, exp);
427 }
428
429 #[test]
430 #[should_panic]
431 fn test_subsecond_parse_error() {
432 "123foo".parse::<Subsecond>().unwrap();
433 }
434
435 #[test]
436 fn test_subsecond_from_attoseconds_negative() {
437 let s = Subsecond::from_attoseconds(-1);
439 assert_eq!(s.as_attoseconds(), 999999999999999999);
440 assert_eq!(s.milliseconds(), 999);
441 assert_eq!(s.microseconds(), 999);
442 assert_eq!(s.nanoseconds(), 999);
443 assert_eq!(s.picoseconds(), 999);
444 assert_eq!(s.femtoseconds(), 999);
445 assert_eq!(s.attoseconds(), 999);
446 }
447
448 #[test]
449 fn test_subsecond_from_attoseconds_zero() {
450 let s = Subsecond::from_attoseconds(0);
451 assert_eq!(s.as_attoseconds(), 0);
452 assert_eq!(s, Subsecond::ZERO);
453 }
454
455 #[test]
456 fn test_subsecond_from_attoseconds_max() {
457 let max = ATTOSECONDS_IN_SECOND - 1;
459 let s = Subsecond::from_attoseconds(max);
460 assert_eq!(s.as_attoseconds(), max);
461 assert_eq!(s.milliseconds(), 999);
462 assert_eq!(s.microseconds(), 999);
463 assert_eq!(s.nanoseconds(), 999);
464 assert_eq!(s.picoseconds(), 999);
465 assert_eq!(s.femtoseconds(), 999);
466 assert_eq!(s.attoseconds(), 999);
467 }
468
469 #[test]
470 fn test_subsecond_from_attoseconds_overflow() {
471 let s = Subsecond::from_attoseconds(ATTOSECONDS_IN_SECOND);
473 assert_eq!(s.as_attoseconds(), 0);
474
475 let s = Subsecond::from_attoseconds(ATTOSECONDS_IN_SECOND + 123);
476 assert_eq!(s.as_attoseconds(), 123);
477 }
478
479 #[test]
480 fn test_subsecond_set_methods_max_value() {
481 let s = Subsecond::new().set_milliseconds(999);
483 assert_eq!(s.milliseconds(), 999);
484
485 let s = Subsecond::new().set_microseconds(999);
486 assert_eq!(s.microseconds(), 999);
487
488 let s = Subsecond::new().set_nanoseconds(999);
489 assert_eq!(s.nanoseconds(), 999);
490 }
491
492 #[test]
493 fn test_subsecond_display_edge_cases() {
494 assert_eq!(format!("{}", Subsecond::ZERO), "0.000");
496
497 let s = Subsecond::new().set_milliseconds(123);
499 assert_eq!(format!("{:.0}", s), "");
500
501 assert_eq!(format!("{:.25}", s), "0.123000000000000000");
503 }
504
505 #[test]
506 fn test_subsecond_parse_edge_cases() {
507 let s: Subsecond = "".parse().unwrap();
509 assert_eq!(s, Subsecond::ZERO);
510
511 let s: Subsecond = "1".parse().unwrap();
513 assert_eq!(s.milliseconds(), 100);
514
515 let s: Subsecond = "12".parse().unwrap();
517 assert_eq!(s.milliseconds(), 120);
518
519 let s: Subsecond = "999999999999999999".parse().unwrap();
521 assert_eq!(s.as_attoseconds(), 999999999999999999);
522 }
523
524 #[test]
525 fn test_subsecond_parse_too_long() {
526 let result = "1234567890123456789".parse::<Subsecond>();
528 assert!(result.is_err());
529 }
530
531 #[test]
532 fn test_subsecond_ordering() {
533 let a = Subsecond::from_attoseconds(100);
534 let b = Subsecond::from_attoseconds(200);
535 let c = Subsecond::from_attoseconds(200);
536
537 assert!(a < b);
538 assert!(b > a);
539 assert_eq!(b, c);
540 assert!(b <= c);
541 assert!(b >= c);
542 }
543
544 #[test]
545 fn test_subsecond_equality() {
546 let a = Subsecond::new().set_milliseconds(123);
547 let b = Subsecond::from_attoseconds(123000000000000000);
548
549 assert_eq!(a, b);
550 assert_eq!(a.as_attoseconds(), b.as_attoseconds());
551 }
552}