ethanlin01x commented on code in PR #3891:
URL: https://github.com/apache/iggy/pull/3891#discussion_r3854818044


##########
core/common/src/utils/duration.rs:
##########
@@ -226,6 +227,221 @@ impl Visitor<'_> for IggyDurationVisitor {
     }
 }
 
+/// A duration that is guaranteed to be at least one microsecond.
+///
+/// `IggyDuration::from_str` maps `0`, `none`, `disabled` and `unlimited` to 
the same
+/// zero, so all four are rejected here. Serialization emits whole 
microseconds, so a
+/// shorter duration such as `1ns` is rejected as well.
+///
+/// # Example
+///
+/// ```
+/// use iggy_common::{IggyDuration, NonZeroIggyDuration, NonZeroDurationError};
+/// use std::str::FromStr;
+///
+/// let interval = NonZeroIggyDuration::from_str("1s").unwrap();
+/// assert_eq!(1, interval.as_secs());
+/// assert_eq!("1s", format!("{}", interval));
+///
+/// assert_eq!(Err(NonZeroDurationError::Zero), 
NonZeroIggyDuration::from_str("none"));
+/// assert_eq!(
+///     Err(NonZeroDurationError::Zero),
+///     NonZeroIggyDuration::try_from(IggyDuration::from(0_u64)),
+/// );
+/// assert_eq!(
+///     Err(NonZeroDurationError::SubMicrosecond),
+///     NonZeroIggyDuration::from_str("1ns"),
+/// );
+/// ```
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub struct NonZeroIggyDuration {
+    duration: IggyDuration,
+}
+
+/// The reason a value could not become a `NonZeroIggyDuration`.
+#[derive(Debug, Clone, PartialEq)]
+pub enum NonZeroDurationError {
+    /// The value parsed or converted to zero.
+    Zero,
+    /// The value is shorter than the one microsecond resolution of the wire 
format.
+    SubMicrosecond,
+    /// The text is not a duration `humantime` understands.
+    InvalidFormat(humantime::DurationError),
+}
+
+impl NonZeroIggyDuration {
+    pub const ONE_SECOND: NonZeroIggyDuration = NonZeroIggyDuration {
+        duration: IggyDuration::ONE_SECOND,
+    };
+
+    pub fn new(duration: Duration) -> Result<Self, NonZeroDurationError> {
+        IggyDuration::new(duration).try_into()
+    }
+
+    pub fn get(&self) -> IggyDuration {
+        self.duration
+    }
+
+    pub fn get_duration(&self) -> Duration {
+        self.duration.get_duration()
+    }
+
+    pub fn as_human_time_string(&self) -> String {
+        self.duration.as_human_time_string()
+    }
+
+    pub fn as_secs(&self) -> u32 {
+        self.duration.as_secs()
+    }
+
+    pub fn as_secs_f64(&self) -> f64 {
+        self.duration.as_secs_f64()
+    }
+
+    pub fn as_micros(&self) -> u64 {
+        self.duration.as_micros()
+    }
+
+    /// The gap between two non-zero durations is zero when they are equal, so 
the
+    /// result is an `IggyDuration`.
+    pub fn abs_diff(&self, other: NonZeroIggyDuration) -> IggyDuration {
+        self.duration.abs_diff(other.duration)
+    }
+}
+
+impl Display for NonZeroDurationError {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        match self {
+            NonZeroDurationError::Zero => write!(f, "duration must be greater 
than zero"),
+            NonZeroDurationError::SubMicrosecond => {
+                write!(f, "duration must be at least one microsecond")
+            }
+            NonZeroDurationError::InvalidFormat(error) => write!(f, "invalid 
duration: {error}"),
+        }
+    }
+}
+
+impl Error for NonZeroDurationError {
+    fn source(&self) -> Option<&(dyn Error + 'static)> {
+        match self {
+            NonZeroDurationError::Zero | NonZeroDurationError::SubMicrosecond 
=> None,
+            NonZeroDurationError::InvalidFormat(error) => Some(error),
+        }
+    }
+}
+
+impl From<humantime::DurationError> for NonZeroDurationError {
+    fn from(error: humantime::DurationError) -> Self {
+        NonZeroDurationError::InvalidFormat(error)
+    }
+}
+
+impl TryFrom<IggyDuration> for NonZeroIggyDuration {
+    type Error = NonZeroDurationError;
+
+    fn try_from(duration: IggyDuration) -> Result<Self, Self::Error> {
+        if duration.is_zero() {
+            return Err(NonZeroDurationError::Zero);
+        }
+
+        // Serialization emits whole microseconds, so a shorter duration would 
come back as zero.
+        if duration.as_micros() == 0 {

Review Comment:
   Fixed in 
[46f9500](https://github.com/apache/iggy/pull/3891/commits/46f9500f9b16e043bcebbf1eba039d08fa493314)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to