oxedyne/fe2o3/fe2o3_datime/src/clock/millisecond.rs
3.6 KiB, 21 runs
created by r1870400018:6323, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | //! [Written with AI entirely](https://need2know.ai/entirely-ai/code)\ |
| 2 | //! Anthropic Claude |
| 3 | |
| 4 | use crate::clock::{ |
| 5 | PerSecondRated, |
| 6 | ClockNanoSecond, |
| 7 | }; |
| 8 | |
| 9 | use oxedyne_fe2o3_core::prelude::*; |
| 10 | |
| 11 | use std::fmt; |
| 12 | |
| 13 | /// A millisecond face over ClockNanoSecond: the arithmetic happens in |
| 14 | /// nanoseconds and is converted back on the way out. |
| 15 | /// |
| 16 | /// ```ignore |
| 17 | /// use oxedyne_fe2o3_datime::clock::ClockMilliSecondres!(); |
| 18 | /// |
| 19 | /// let millis = ClockMilliSecond::new(500)?res!(); |
| 20 | /// assert_eq!(millis.of(), 500)res!(); |
| 21 | /// assert_eq!(millis.as_nanos().of(), 500_000_000)res!(); |
| 22 | /// ``` |
| 23 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] |
| 24 | pub struct ClockMilliSecond { |
| 25 | nanos: ClockNanoSecond, |
| 26 | } |
| 27 | |
| 28 | impl ClockMilliSecond { |
| 29 | pub const MAX_VALUE: u32 = 999; |
| 30 | pub const NANOS_PER_MILLI: u32 = 1_000_000; |
| 31 | |
| 32 | pub fn new(millis: u32) -> Outcome<Self> { |
| 33 | if millis > Self::MAX_VALUE { |
| 34 | return Err(err!( |
| 35 | "Millisecond {} is invalid, must be 0-{}", |
| 36 | millis, |
| 37 | Self::MAX_VALUE; |
| 38 | Invalid, Input |
| 39 | )); |
| 40 | } |
| 41 | let nanos = res!(ClockNanoSecond::from_millis(millis)); |
| 42 | Ok(Self { nanos }) |
| 43 | } |
| 44 | |
| 45 | pub(crate) fn new_unchecked(millis: u32) -> Self { |
| 46 | let nanos = ClockNanoSecond::new_unchecked(millis * Self::NANOS_PER_MILLI); |
| 47 | Self { nanos } |
| 48 | } |
| 49 | |
| 50 | pub fn of(&self) -> u32 { |
| 51 | self.nanos.to_millis() |
| 52 | } |
| 53 | |
| 54 | pub fn as_nanos(&self) -> ClockNanoSecond { |
| 55 | self.nanos |
| 56 | } |
| 57 | |
| 58 | /// Truncates the sub-millisecond part. |
| 59 | pub fn from_nanos(nanos: ClockNanoSecond) -> Self { |
| 60 | let millis = nanos.to_millis(); |
| 61 | Self::new_unchecked(millis) |
| 62 | } |
| 63 | |
| 64 | pub fn add_millis(&self, millis: u32) -> (Self, u32) { |
| 65 | let nanos_to_add = millis as u64 * Self::NANOS_PER_MILLI as u64; |
| 66 | let (new_nanos, second_carry) = self.nanos.add_nanos(nanos_to_add); |
| 67 | (Self::from_nanos(new_nanos), second_carry) |
| 68 | } |
| 69 | |
| 70 | pub fn sub_millis(&self, millis: u32) -> (Self, u32) { |
| 71 | let nanos_to_sub = millis as u64 * Self::NANOS_PER_MILLI as u64; |
| 72 | let (new_nanos, second_borrow) = self.nanos.sub_nanos(nanos_to_sub); |
| 73 | (Self::from_nanos(new_nanos), second_borrow) |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | // Validation methods. |
| 78 | impl ClockMilliSecond { |
| 79 | pub fn is_valid(&self) -> bool { |
| 80 | self.of() <= Self::MAX_VALUE |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | impl PerSecondRated for ClockMilliSecond { |
| 85 | fn per_second(&self) -> u64 { |
| 86 | 1_000 |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | impl fmt::Display for ClockMilliSecond { |
| 91 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 92 | write!(f, "{:03}", self.of()) |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | #[cfg(test)] |
| 97 | mod tests { |
| 98 | use super::*; |
| 99 | |
| 100 | #[test] |
| 101 | fn test_millisecond_creation() { |
| 102 | assert!(ClockMilliSecond::new(0).is_ok()); |
| 103 | assert!(ClockMilliSecond::new(500).is_ok()); |
| 104 | assert!(ClockMilliSecond::new(999).is_ok()); |
| 105 | assert!(ClockMilliSecond::new(1000).is_err()); |
| 106 | } |
| 107 | |
| 108 | #[test] |
| 109 | fn test_millisecond_conversions() { |
| 110 | let millis = ClockMilliSecond::new(123).unwrap(); |
| 111 | assert_eq!(millis.of(), 123); |
| 112 | assert_eq!(millis.as_nanos().of(), 123_000_000); |
| 113 | |
| 114 | let nanos = ClockNanoSecond::new(123_456_789).unwrap(); |
| 115 | let millis = ClockMilliSecond::from_nanos(nanos); |
| 116 | assert_eq!(millis.of(), 123); // truncated |
| 117 | } |
| 118 | |
| 119 | #[test] |
| 120 | fn test_millisecond_arithmetic() { |
| 121 | let millis = ClockMilliSecond::new(500).unwrap(); |
| 122 | let (new_millis, carry) = millis.add_millis(300); |
| 123 | assert_eq!(new_millis.of(), 800); |
| 124 | assert_eq!(carry, 0); |
| 125 | |
| 126 | let (new_millis, carry) = millis.add_millis(700); |
| 127 | assert_eq!(new_millis.of(), 200); |
| 128 | assert_eq!(carry, 1); |
| 129 | |
| 130 | let (new_millis, borrow) = millis.sub_millis(200); |
| 131 | assert_eq!(new_millis.of(), 300); |
| 132 | assert_eq!(borrow, 0); |
| 133 | |
| 134 | let (new_millis, borrow) = millis.sub_millis(700); |
| 135 | assert_eq!(new_millis.of(), 800); |
| 136 | assert_eq!(borrow, 1); |
| 137 | } |
| 138 | |
| 139 | #[test] |
| 140 | fn test_per_second_rated() { |
| 141 | let millis = ClockMilliSecond::new(456).unwrap(); |
| 142 | assert_eq!(millis.per_second(), 1_000); |
| 143 | } |
| 144 | } |