Skip to main content

gstreamer/format/
clock_time.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{
4    fmt,
5    io::{self, prelude::*},
6    sync::LazyLock,
7    time::Duration,
8};
9
10use crate::{ffi, prelude::*};
11use glib::translate::*;
12
13use super::{
14    Format, FormattedValue, FormattedValueError, FormattedValueFullRange, FormattedValueIntrinsic,
15    FormattedValueNoneBuilder, GenericFormattedValue, Signed, SpecificFormattedValue,
16    SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic,
17};
18
19const TRY_FROM_FLOAT_SECS_ERROR_MSG: &str =
20    "can not convert float seconds to ClockTime: value is either negative, too big or NaN";
21
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct TryFromFloatSecsError;
24
25impl fmt::Display for TryFromFloatSecsError {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        f.write_str(TRY_FROM_FLOAT_SECS_ERROR_MSG)
28    }
29}
30
31impl std::error::Error for TryFromFloatSecsError {}
32
33// rustdoc-stripper-ignore-next
34/// A Time quantity
35///
36/// Some functions enforce format specific quantities. This type can be used when
37/// a Duration or an Instant is expected. It comes with functions to perform computations without the
38/// need to retrieve the inner integer.
39///
40/// # Examples
41///
42/// ```rust
43/// # use gstreamer::{prelude::*, ClockTime};
44/// // Regular constructors (can be used in `const` contexts)
45/// const FORTY_TWO_NS: ClockTime = ClockTime::from_nseconds(42);
46/// const TWO_US: ClockTime = ClockTime::from_useconds(2);
47/// let three_ms: ClockTime = ClockTime::from_mseconds(3);
48/// let four_s: ClockTime = ClockTime::from_seconds(4);
49///
50/// // Convenience constructors (not `const`)
51/// let forty_two_ns = 42.nseconds();
52/// let two_us = 2.useconds();
53/// let three_ms = 3.mseconds();
54/// let four_s = 4.seconds();
55///
56/// // All four arithmetic operations
57/// let deadline = (2.mseconds() + 512.useconds()) * 2 / 3;
58///
59/// // Comparisons
60/// if deadline > ClockTime::MSECOND {
61///     println!("Greater");
62/// }
63/// ```
64///
65/// See [the documentation of the `format` module] for more examples.
66///
67/// [the documentation of the `format` module]: ./index.html
68#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
69pub struct ClockTime(u64);
70
71impl ClockTime {
72    #[doc(alias = "GST_SECOND")]
73    pub const SECOND: ClockTime = ClockTime(1_000_000_000);
74    #[doc(alias = "GST_MSECOND")]
75    pub const MSECOND: ClockTime = ClockTime(1_000_000);
76    #[doc(alias = "GST_USECOND")]
77    pub const USECOND: ClockTime = ClockTime(1_000);
78    #[doc(alias = "GST_NSECOND")]
79    pub const NSECOND: ClockTime = ClockTime(1);
80    // checker-ignore-item
81    pub const MAX: ClockTime = ClockTime(ffi::GST_CLOCK_TIME_NONE - 1);
82}
83
84// The following constants are defined at module level because some of them are statics
85
86// rustdoc-stripper-ignore-next
87/// Offset to add to UNIX time to convert to NTP time.
88///
89/// See [`crate::UNIX_TO_NTP_TIME_OFFSET_SECONDS`].
90pub const UNIX_TO_NTP_TIME_OFFSET: ClockTime =
91    ClockTime::from_seconds(crate::UNIX_TO_NTP_TIME_OFFSET_SECONDS);
92
93// rustdoc-stripper-ignore-next
94/// Offset to subtract from NTP time to convert to PTP time.
95///
96/// See [`crate::NTP_TO_PTP_TIME_OFFSET_SECONDS`].
97pub static NTP_TO_PTP_TIME_OFFSET: LazyLock<ClockTime> =
98    LazyLock::new(|| ClockTime::from_seconds(*crate::NTP_TO_PTP_TIME_OFFSET_SECONDS));
99
100// rustdoc-stripper-ignore-next
101/// Number of current leap seconds applicable to UTC compared to TAI
102///
103/// See [`crate::UTC_TO_TAI_LEAP_SECONDS`].
104pub static UTC_TO_TAI_LEAP_SECONDS: LazyLock<ClockTime> =
105    LazyLock::new(|| ClockTime::from_seconds(*crate::UTC_TO_TAI_LEAP_SECONDS));
106
107// rustdoc-stripper-ignore-next
108/// Offset to add to UNIX time to convert to PTP time.
109///
110/// See [`crate::UNIX_TO_PTP_TIME_OFFSET_SECONDS`].
111pub static UNIX_TO_PTP_TIME_OFFSET: LazyLock<ClockTime> =
112    LazyLock::new(|| ClockTime::from_seconds(*crate::UNIX_TO_PTP_TIME_OFFSET_SECONDS));
113
114impl ClockTime {
115    #[inline]
116    pub const fn hours(self) -> u64 {
117        self.0 / Self::SECOND.0 / 60 / 60
118    }
119
120    #[inline]
121    pub const fn minutes(self) -> u64 {
122        self.0 / Self::SECOND.0 / 60
123    }
124
125    #[inline]
126    pub const fn seconds(self) -> u64 {
127        self.0 / Self::SECOND.0
128    }
129
130    #[inline]
131    pub fn seconds_f32(self) -> f32 {
132        self.0 as f32 / Self::SECOND.0 as f32
133    }
134
135    #[inline]
136    pub fn seconds_f64(self) -> f64 {
137        self.0 as f64 / Self::SECOND.0 as f64
138    }
139
140    #[inline]
141    pub const fn mseconds(self) -> u64 {
142        self.0 / Self::MSECOND.0
143    }
144
145    #[inline]
146    pub const fn useconds(self) -> u64 {
147        self.0 / Self::USECOND.0
148    }
149
150    #[inline]
151    pub const fn nseconds(self) -> u64 {
152        self.0
153    }
154
155    // rustdoc-stripper-ignore-next
156    /// Builds a new `ClockTime` which value is the given number of seconds.
157    ///
158    /// # Panics
159    ///
160    /// Panics if the resulting duration in nanoseconds exceeds the `u64` range.
161    #[track_caller]
162    #[inline]
163    pub const fn from_seconds(seconds: u64) -> Self {
164        skip_assert_initialized!();
165        ClockTime(
166            seconds
167                .checked_mul(Self::SECOND.0)
168                .expect("Out of `ClockTime` range"),
169        )
170    }
171
172    // rustdoc-stripper-ignore-next
173    /// Builds a new `ClockTime` which value is the given number of seconds.
174    ///
175    /// Returns an error if seconds is negative, infinite or NaN, or
176    /// the resulting duration in nanoseconds exceeds the `u64` range.
177    #[inline]
178    pub fn try_from_seconds_f32(seconds: f32) -> Result<Self, TryFromFloatSecsError> {
179        skip_assert_initialized!();
180
181        let dur = Duration::try_from_secs_f32(seconds).map_err(|_| TryFromFloatSecsError)?;
182        ClockTime::try_from(dur).map_err(|_| TryFromFloatSecsError)
183    }
184
185    // rustdoc-stripper-ignore-next
186    /// Builds a new `ClockTime` which value is the given number of seconds.
187    ///
188    /// # Panics
189    ///
190    /// Panics if seconds is negative, infinite or NaN, or the resulting duration
191    /// in nanoseconds exceeds the `u64` range.
192    #[track_caller]
193    #[inline]
194    pub fn from_seconds_f32(seconds: f32) -> Self {
195        skip_assert_initialized!();
196
197        Self::try_from_seconds_f32(seconds).expect(TRY_FROM_FLOAT_SECS_ERROR_MSG)
198    }
199
200    // rustdoc-stripper-ignore-next
201    /// Builds a new `ClockTime` which value is the given number of seconds.
202    ///
203    /// Returns an error if seconds is negative, infinite or NaN, or
204    /// the resulting duration in nanoseconds exceeds the `u64` range.
205    #[inline]
206    pub fn try_from_seconds_f64(seconds: f64) -> Result<Self, TryFromFloatSecsError> {
207        skip_assert_initialized!();
208
209        let dur = Duration::try_from_secs_f64(seconds).map_err(|_| TryFromFloatSecsError)?;
210        ClockTime::try_from(dur).map_err(|_| TryFromFloatSecsError)
211    }
212
213    // rustdoc-stripper-ignore-next
214    /// Builds a new `ClockTime` which value is the given number of seconds.
215    ///
216    /// # Panics
217    ///
218    /// Panics if seconds is negative, infinite or NaN, or the resulting duration
219    /// in nanoseconds exceeds the `u64` range.
220    #[track_caller]
221    #[inline]
222    pub fn from_seconds_f64(seconds: f64) -> Self {
223        skip_assert_initialized!();
224
225        Self::try_from_seconds_f64(seconds).expect(TRY_FROM_FLOAT_SECS_ERROR_MSG)
226    }
227
228    // rustdoc-stripper-ignore-next
229    /// Builds a new `ClockTime` which value is the given number of milliseconds.
230    ///
231    /// # Panics
232    ///
233    /// Panics if the resulting duration in nanoseconds exceeds the `u64` range.
234    #[track_caller]
235    #[inline]
236    pub const fn from_mseconds(mseconds: u64) -> Self {
237        skip_assert_initialized!();
238        ClockTime(
239            mseconds
240                .checked_mul(Self::MSECOND.0)
241                .expect("Out of `ClockTime` range"),
242        )
243    }
244
245    // rustdoc-stripper-ignore-next
246    /// Builds a new `ClockTime` which value is the given number of microseconds.
247    ///
248    /// # Panics
249    ///
250    /// Panics if the resulting duration in nanoseconds exceeds the `u64` range.
251    #[track_caller]
252    #[inline]
253    pub const fn from_useconds(useconds: u64) -> Self {
254        skip_assert_initialized!();
255        ClockTime(
256            useconds
257                .checked_mul(Self::USECOND.0)
258                .expect("Out of `ClockTime` range"),
259        )
260    }
261
262    // rustdoc-stripper-ignore-next
263    /// Builds a new `ClockTime` which value is the given number of nanoseconds.
264    ///
265    /// # Panics
266    ///
267    /// Panics if the requested duration equals `GST_CLOCK_TIME_NONE`
268    /// (`u64::MAX`).
269    #[track_caller]
270    #[inline]
271    pub const fn from_nseconds(nseconds: u64) -> Self {
272        skip_assert_initialized!();
273        assert!(
274            nseconds != ffi::GST_CLOCK_TIME_NONE,
275            "Attempt to build a `ClockTime` with value `GST_CLOCK_TIME_NONE`",
276        );
277        ClockTime(nseconds * Self::NSECOND.0)
278    }
279}
280
281impl Signed<ClockTime> {
282    // rustdoc-stripper-ignore-next
283    /// Returns the `self` in nanoseconds.
284    #[inline]
285    pub fn nseconds(self) -> Signed<u64> {
286        match self {
287            Signed::Positive(val) => Signed::Positive(val.nseconds()),
288            Signed::Negative(val) => Signed::Negative(val.nseconds()),
289        }
290    }
291
292    // rustdoc-stripper-ignore-next
293    /// Creates new value from nanoseconds.
294    #[inline]
295    pub fn from_nseconds(val: Signed<u64>) -> Self {
296        skip_assert_initialized!();
297        match val {
298            Signed::Positive(val) => Signed::Positive(ClockTime::from_nseconds(val)),
299            Signed::Negative(val) => Signed::Negative(ClockTime::from_nseconds(val)),
300        }
301    }
302
303    // rustdoc-stripper-ignore-next
304    /// Returns the `self` in microseconds.
305    #[inline]
306    pub fn useconds(self) -> Signed<u64> {
307        match self {
308            Signed::Positive(val) => Signed::Positive(val.useconds()),
309            Signed::Negative(val) => Signed::Negative(val.useconds()),
310        }
311    }
312
313    // rustdoc-stripper-ignore-next
314    /// Creates new value from microseconds.
315    #[inline]
316    pub fn from_useconds(val: Signed<u64>) -> Self {
317        skip_assert_initialized!();
318        match val {
319            Signed::Positive(val) => Signed::Positive(ClockTime::from_useconds(val)),
320            Signed::Negative(val) => Signed::Negative(ClockTime::from_useconds(val)),
321        }
322    }
323
324    // rustdoc-stripper-ignore-next
325    /// Returns the `self` in milliseconds.
326    #[inline]
327    pub fn mseconds(self) -> Signed<u64> {
328        match self {
329            Signed::Positive(val) => Signed::Positive(val.mseconds()),
330            Signed::Negative(val) => Signed::Negative(val.mseconds()),
331        }
332    }
333
334    // rustdoc-stripper-ignore-next
335    /// Creates new value from milliseconds.
336    #[inline]
337    pub fn from_mseconds(val: Signed<u64>) -> Self {
338        skip_assert_initialized!();
339        match val {
340            Signed::Positive(val) => Signed::Positive(ClockTime::from_mseconds(val)),
341            Signed::Negative(val) => Signed::Negative(ClockTime::from_mseconds(val)),
342        }
343    }
344
345    // rustdoc-stripper-ignore-next
346    /// Returns the `self` in seconds.
347    #[inline]
348    pub fn seconds(self) -> Signed<u64> {
349        match self {
350            Signed::Positive(val) => Signed::Positive(val.seconds()),
351            Signed::Negative(val) => Signed::Negative(val.seconds()),
352        }
353    }
354
355    // rustdoc-stripper-ignore-next
356    /// Returns the `self` in f32 seconds.
357    #[inline]
358    pub fn seconds_f32(self) -> f32 {
359        match self {
360            Signed::Positive(val) => val.seconds_f32(),
361            Signed::Negative(val) => -val.seconds_f32(),
362        }
363    }
364
365    // rustdoc-stripper-ignore-next
366    /// Returns the `self` in f64 seconds.
367    #[inline]
368    pub fn seconds_f64(self) -> f64 {
369        match self {
370            Signed::Positive(val) => val.seconds_f64(),
371            Signed::Negative(val) => -val.seconds_f64(),
372        }
373    }
374
375    // rustdoc-stripper-ignore-next
376    /// Creates new value from seconds.
377    #[inline]
378    pub fn from_seconds(val: Signed<u64>) -> Self {
379        skip_assert_initialized!();
380        match val {
381            Signed::Positive(val) => Signed::Positive(ClockTime::from_seconds(val)),
382            Signed::Negative(val) => Signed::Negative(ClockTime::from_seconds(val)),
383        }
384    }
385
386    // rustdoc-stripper-ignore-next
387    /// Builds a new `Signed<ClockTime>` which value is the given number of seconds.
388    ///
389    /// Returns an error if seconds is infinite or NaN, or
390    /// the resulting duration in nanoseconds exceeds the `u64` range.
391    #[inline]
392    pub fn try_from_seconds_f32(seconds: f32) -> Result<Self, TryFromFloatSecsError> {
393        skip_assert_initialized!();
394
395        ClockTime::try_from_seconds_f32(seconds.abs()).map(|ct| {
396            if seconds.is_sign_positive() {
397                Signed::Positive(ct)
398            } else {
399                Signed::Negative(ct)
400            }
401        })
402    }
403
404    // rustdoc-stripper-ignore-next
405    /// Builds a new `Signed<ClockTime>` which value is the given number of seconds.
406    ///
407    /// # Panics
408    ///
409    /// Panics if seconds is infinite or NaN, or the resulting duration
410    /// in nanoseconds exceeds the `u64` range.
411    #[track_caller]
412    #[inline]
413    pub fn from_seconds_f32(seconds: f32) -> Self {
414        skip_assert_initialized!();
415
416        Self::try_from_seconds_f32(seconds).expect(TRY_FROM_FLOAT_SECS_ERROR_MSG)
417    }
418
419    // rustdoc-stripper-ignore-next
420    /// Builds a new `Signed<ClockTime>` which value is the given number of seconds.
421    ///
422    /// Returns an error if seconds is infinite or NaN, or
423    /// the resulting duration in nanoseconds exceeds the `u64` range.
424    #[inline]
425    pub fn try_from_seconds_f64(seconds: f64) -> Result<Self, TryFromFloatSecsError> {
426        skip_assert_initialized!();
427
428        ClockTime::try_from_seconds_f64(seconds.abs()).map(|ct| {
429            if seconds.is_sign_positive() {
430                Signed::Positive(ct)
431            } else {
432                Signed::Negative(ct)
433            }
434        })
435    }
436
437    // rustdoc-stripper-ignore-next
438    /// Builds a new `Signed<ClockTime>` which value is the given number of seconds.
439    ///
440    /// # Panics
441    ///
442    /// Panics if seconds is infinite or NaN, or the resulting duration
443    /// in nanoseconds exceeds the `u64` range.
444    #[track_caller]
445    #[inline]
446    pub fn from_seconds_f64(seconds: f64) -> Self {
447        skip_assert_initialized!();
448
449        Self::try_from_seconds_f64(seconds).expect(TRY_FROM_FLOAT_SECS_ERROR_MSG)
450    }
451}
452
453impl_format_value_traits!(ClockTime, Time, Time, u64);
454option_glib_newtype_from_to!(ClockTime, ffi::GST_CLOCK_TIME_NONE);
455
456// FIXME `functions in traits cannot be const` (rustc 1.64.0)
457// rustdoc-stripper-ignore-next
458/// `ClockTime` formatted value constructor trait.
459pub trait TimeFormatConstructor {
460    // rustdoc-stripper-ignore-next
461    /// Builds a `ClockTime` formatted value from `self` interpreted as nano seconds.
462    fn nseconds(self) -> ClockTime;
463
464    // rustdoc-stripper-ignore-next
465    /// Builds a `ClockTime` formatted value from `self` interpreted as micro seconds.
466    fn useconds(self) -> ClockTime;
467
468    // rustdoc-stripper-ignore-next
469    /// Builds a `ClockTime` formatted value from `self` interpreted as milli seconds.
470    fn mseconds(self) -> ClockTime;
471
472    // rustdoc-stripper-ignore-next
473    /// Builds a `ClockTime` formatted value from `self` interpreted as seconds.
474    fn seconds(self) -> ClockTime;
475
476    // rustdoc-stripper-ignore-next
477    /// Builds a `ClockTime` formatted value from `self` interpreted as minutes.
478    fn minutes(self) -> ClockTime;
479
480    // rustdoc-stripper-ignore-next
481    /// Builds a `ClockTime` formatted value from `self` interpreted as hours.
482    fn hours(self) -> ClockTime;
483}
484
485impl TimeFormatConstructor for u64 {
486    #[track_caller]
487    #[inline]
488    fn nseconds(self) -> ClockTime {
489        ClockTime::from_nseconds(self)
490    }
491
492    #[track_caller]
493    #[inline]
494    fn useconds(self) -> ClockTime {
495        ClockTime::from_useconds(self)
496    }
497
498    #[track_caller]
499    #[inline]
500    fn mseconds(self) -> ClockTime {
501        ClockTime::from_mseconds(self)
502    }
503
504    #[track_caller]
505    #[inline]
506    fn seconds(self) -> ClockTime {
507        ClockTime::from_seconds(self)
508    }
509
510    #[track_caller]
511    #[inline]
512    fn minutes(self) -> ClockTime {
513        ClockTime::from_seconds(self * 60)
514    }
515
516    #[track_caller]
517    #[inline]
518    fn hours(self) -> ClockTime {
519        ClockTime::from_seconds(self * 60 * 60)
520    }
521}
522
523impl glib::value::ValueType for ClockTime {
524    type Type = Self;
525}
526
527pub enum ClockTimeValueTypeOrNoneChecker {}
528
529unsafe impl glib::value::ValueTypeChecker for ClockTimeValueTypeOrNoneChecker {
530    type Error = glib::value::ValueTypeMismatchOrNoneError<glib::value::ValueTypeMismatchError>;
531
532    #[inline]
533    fn check(value: &glib::Value) -> Result<(), Self::Error> {
534        skip_assert_initialized!();
535        glib::value::GenericValueTypeChecker::<ClockTime>::check(value)?;
536
537        let gct = unsafe { glib::gobject_ffi::g_value_get_uint64(value.to_glib_none().0) };
538        if gct == ffi::GST_CLOCK_TIME_NONE {
539            return Err(glib::value::ValueTypeMismatchOrNoneError::UnexpectedNone);
540        }
541
542        Ok(())
543    }
544}
545
546unsafe impl glib::value::FromValue<'_> for ClockTime {
547    type Checker = ClockTimeValueTypeOrNoneChecker;
548
549    #[inline]
550    unsafe fn from_value(value: &glib::Value) -> ClockTime {
551        unsafe {
552            skip_assert_initialized!();
553            ClockTime(glib::gobject_ffi::g_value_get_uint64(
554                value.to_glib_none().0,
555            ))
556        }
557    }
558}
559
560impl glib::value::ToValue for ClockTime {
561    #[inline]
562    fn to_value(&self) -> glib::Value {
563        let mut value = glib::Value::for_value_type::<ClockTime>();
564        let gct = self.into_glib();
565        if gct == ffi::GST_CLOCK_TIME_NONE {
566            crate::warning!(
567                crate::CAT_RUST,
568                "converting a defined `ClockTime` with value `GST_CLOCK_TIME_NONE` to `Value`, this is probably not what you wanted.",
569            );
570        }
571        unsafe { glib::gobject_ffi::g_value_set_uint64(value.to_glib_none_mut().0, gct) }
572        value
573    }
574
575    #[inline]
576    fn value_type(&self) -> glib::Type {
577        Self::static_type()
578    }
579}
580
581impl glib::value::ToValueOptional for ClockTime {
582    #[inline]
583    fn to_value_optional(opt: Option<&Self>) -> glib::Value {
584        skip_assert_initialized!();
585        let mut value = glib::Value::for_value_type::<ClockTime>();
586        let inner = opt.map(|inner| inner.0).unwrap_or(ffi::GST_CLOCK_TIME_NONE);
587        unsafe { glib::gobject_ffi::g_value_set_uint64(value.to_glib_none_mut().0, inner) };
588
589        value
590    }
591}
592
593impl From<ClockTime> for glib::Value {
594    #[inline]
595    fn from(v: ClockTime) -> glib::Value {
596        glib::value::ToValue::to_value(&v)
597    }
598}
599
600#[doc(hidden)]
601impl StaticType for ClockTime {
602    #[inline]
603    fn static_type() -> glib::Type {
604        <u64 as StaticType>::static_type()
605    }
606}
607
608impl HasParamSpec for ClockTime {
609    type ParamSpec = glib::ParamSpecUInt64;
610    type SetValue = Self;
611    type BuilderFn = fn(&str) -> glib::ParamSpecUInt64Builder;
612
613    fn param_spec_builder() -> Self::BuilderFn {
614        Self::ParamSpec::builder
615    }
616}
617
618#[derive(Debug)]
619pub struct DurationError;
620
621impl fmt::Display for DurationError {
622    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
623        write!(fmt, "out of range conversion from Duration attempted")
624    }
625}
626
627impl std::error::Error for DurationError {}
628
629impl TryFrom<Duration> for ClockTime {
630    type Error = DurationError;
631
632    #[inline]
633    fn try_from(d: Duration) -> Result<Self, Self::Error> {
634        skip_assert_initialized!();
635
636        let nanos = d.as_nanos();
637
638        // Note: `u64::MAX` is `ClockTime::NONE`.
639        if nanos >= u64::MAX as u128 {
640            return Err(DurationError);
641        }
642
643        Ok(ClockTime::from_nseconds(nanos as u64))
644    }
645}
646
647impl From<ClockTime> for Duration {
648    #[inline]
649    fn from(t: ClockTime) -> Self {
650        skip_assert_initialized!();
651
652        Duration::from_nanos(t.nseconds())
653    }
654}
655
656impl_common_ops_for_newtype_uint!(ClockTime, u64);
657impl_signed_div_mul!(ClockTime, u64);
658impl_signed_int_into_signed!(ClockTime, u64);
659
660// rustdoc-stripper-ignore-next
661/// Tell [`pad_clocktime`] what kind of time we're formatting
662enum Sign {
663    // rustdoc-stripper-ignore-next
664    /// An undefined time (`None`)
665    Undefined,
666
667    // rustdoc-stripper-ignore-next
668    /// A non-negative time (zero or greater)
669    NonNegative,
670
671    // For a future ClockTimeDiff formatting
672    #[allow(dead_code)]
673    // rustdoc-stripper-ignore-next
674    /// A negative time (below zero)
675    Negative,
676}
677
678// Derived from libcore `Formatter::pad_integral` (same APACHE v2 + MIT licenses)
679//
680// TODO: Would be useful for formatting ClockTimeDiff
681// if it was a new type instead of an alias for i64
682//
683// rustdoc-stripper-ignore-next
684/// Performs the correct padding for a clock time which has already been
685/// emitted into a str, as by [`write_clocktime`]. The str should *not*
686/// contain the sign; that will be added by this method.
687fn pad_clocktime(f: &mut fmt::Formatter<'_>, sign: Sign, buf: &str) -> fmt::Result {
688    skip_assert_initialized!();
689    use std::fmt::{Alignment, Write};
690
691    use self::Sign::*;
692
693    // Start by determining how we're padding, gathering
694    // settings from the Formatter and the Sign
695
696    // Choose the fill character
697    let sign_aware_zero_pad = f.sign_aware_zero_pad();
698    let fill_char = match sign {
699        Undefined if sign_aware_zero_pad => '-', // Zero-padding an undefined time
700        _ if sign_aware_zero_pad => '0',         // Zero-padding a valid time
701        _ => f.fill(),                           // Otherwise, pad with the user-chosen character
702    };
703
704    // Choose the sign character
705    let sign_plus = f.sign_plus();
706    let sign_char = match sign {
707        Undefined if sign_plus => Some(fill_char), // User requested sign, time is undefined
708        NonNegative if sign_plus => Some('+'),     // User requested sign, time is zero or above
709        Negative => Some('-'),                     // Time is below zero
710        _ => None,                                 // Otherwise, add no sign
711    };
712
713    // Our minimum width is the value's width, plus 1 for the sign if present
714    let width = buf.len() + sign_char.map_or(0, |_| 1);
715
716    // Subtract the minimum width from the requested width to get the padding,
717    // taking care not to allow wrapping due to underflow
718    let padding = f.width().unwrap_or(0).saturating_sub(width);
719
720    // Split the required padding into the three possible parts
721    let align = f.align().unwrap_or(Alignment::Right);
722    let (pre_padding, zero_padding, post_padding) = match align {
723        _ if sign_aware_zero_pad => (0, padding, 0), // Zero-padding: Pad between sign and value
724        Alignment::Left => (0, 0, padding),          // Align left: Pad on the right side
725        Alignment::Right => (padding, 0, 0),         // Align right: Pad on the left side
726
727        // Align center: Split equally between left and right side
728        // If the required padding is odd, the right side gets one more char
729        Alignment::Center => (padding / 2, 0, padding.div_ceil(2)),
730    };
731
732    // And now for the actual writing
733
734    for _ in 0..pre_padding {
735        f.write_char(fill_char)?; // Left padding
736    }
737    if let Some(c) = sign_char {
738        f.write_char(c)?; // ------- Sign character
739    }
740    for _ in 0..zero_padding {
741        f.write_char(fill_char)?; // Padding between sign and value
742    }
743    f.write_str(buf)?; // ---------- Value
744    for _ in 0..post_padding {
745        f.write_char(fill_char)?; // Right padding
746    }
747
748    Ok(())
749}
750
751// rustdoc-stripper-ignore-next
752/// Writes an unpadded, signless clocktime string with the given precision
753fn write_clocktime<W: io::Write>(
754    mut writer: W,
755    clocktime: Option<ClockTime>,
756    precision: usize,
757) -> io::Result<()> {
758    skip_assert_initialized!();
759    let precision = std::cmp::min(9, precision);
760
761    if let Some(ns) = clocktime.map(ClockTime::nseconds) {
762        // Split the time into parts
763        let (s, ns) = num_integer::div_rem(ns, 1_000_000_000);
764        let (m, s) = num_integer::div_rem(s, 60);
765        let (h, m) = num_integer::div_rem(m, 60);
766
767        // Write HH:MM:SS
768        write!(writer, "{h}:{m:02}:{s:02}")?;
769
770        if precision > 0 {
771            // Format the nanoseconds into a stack-allocated string
772            // The value is zero-padded so always 9 digits long
773            let mut buf = [0u8; 9];
774            write!(&mut buf[..], "{ns:09}").unwrap();
775            let buf_str = std::str::from_utf8(&buf[..]).unwrap();
776
777            // Write decimal point and a prefix of the nanoseconds for more precision
778            write!(writer, ".{buf_str:.precision$}")?;
779        }
780    } else {
781        // Undefined time
782
783        // Write HH:MM:SS, but invalid
784        write!(writer, "--:--:--")?;
785
786        if precision > 0 {
787            // Write decimal point and dashes for more precision
788            write!(writer, ".{:->p$}", "", p = precision)?;
789        }
790    }
791
792    Ok(())
793}
794
795fn fmt_opt_clock_time(ct: Option<ClockTime>, f: &mut fmt::Formatter) -> fmt::Result {
796    skip_assert_initialized!();
797    let precision = f.precision().unwrap_or(9);
798
799    // What the maximum time (u64::MAX - 1) would format to
800    const MAX_SIZE: usize = "5124095:34:33.709551614".len();
801
802    // Write the unpadded clocktime value into a stack-allocated string
803    let mut buf = [0u8; MAX_SIZE];
804    let mut cursor = io::Cursor::new(&mut buf[..]);
805    write_clocktime(&mut cursor, ct, precision).unwrap();
806    let pos = cursor.position() as usize;
807    let buf_str = std::str::from_utf8(&buf[..pos]).unwrap();
808
809    let sign = if ct.is_some() {
810        Sign::NonNegative
811    } else {
812        Sign::Undefined
813    };
814
815    pad_clocktime(f, sign, buf_str)
816}
817
818impl fmt::Display for ClockTime {
819    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
820        fmt_opt_clock_time(Some(*self), f)
821    }
822}
823
824impl fmt::Debug for ClockTime {
825    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
826        fmt::Display::fmt(self, f)
827    }
828}
829
830pub struct DisplayableOptClockTime(Option<ClockTime>);
831
832impl fmt::Display for DisplayableOptClockTime {
833    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
834        fmt_opt_clock_time(self.0, f)
835    }
836}
837
838impl fmt::Debug for DisplayableOptClockTime {
839    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
840        fmt::Display::fmt(self, f)
841    }
842}
843
844impl crate::utils::Displayable for Option<ClockTime> {
845    type DisplayImpl = DisplayableOptClockTime;
846
847    fn display(self) -> DisplayableOptClockTime {
848        DisplayableOptClockTime(self)
849    }
850}
851
852impl crate::utils::Displayable for ClockTime {
853    type DisplayImpl = ClockTime;
854
855    fn display(self) -> ClockTime {
856        self
857    }
858}
859
860impl std::iter::Sum for ClockTime {
861    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
862        skip_assert_initialized!();
863        iter.fold(ClockTime::ZERO, |a, b| a + b)
864    }
865}
866
867#[cfg(test)]
868mod tests {
869    use opt_ops::prelude::*;
870
871    use super::*;
872    use crate::format::{Signed, UnsignedIntoSigned};
873
874    const CT_1: ClockTime = ClockTime::from_nseconds(1);
875    const CT_2: ClockTime = ClockTime::from_nseconds(2);
876    const CT_3: ClockTime = ClockTime::from_nseconds(3);
877    const CT_10: ClockTime = ClockTime::from_nseconds(10);
878    const CT_20: ClockTime = ClockTime::from_nseconds(20);
879    const CT_30: ClockTime = ClockTime::from_nseconds(30);
880
881    const P_CT_0: Signed<ClockTime> = Signed::Positive(ClockTime::ZERO);
882    const P_CT_NONE: Option<Signed<ClockTime>> = None;
883    const P_CT_1: Signed<ClockTime> = Signed::Positive(ClockTime::from_nseconds(1));
884    const P_CT_2: Signed<ClockTime> = Signed::Positive(ClockTime::from_nseconds(2));
885    const P_CT_3: Signed<ClockTime> = Signed::Positive(ClockTime::from_nseconds(3));
886    const N_CT_1: Signed<ClockTime> = Signed::Negative(ClockTime::from_nseconds(1));
887    const N_CT_2: Signed<ClockTime> = Signed::Negative(ClockTime::from_nseconds(2));
888    const N_CT_3: Signed<ClockTime> = Signed::Negative(ClockTime::from_nseconds(3));
889
890    #[test]
891    fn opt_time_clock() {
892        assert_eq!(CT_1.into_glib(), 1);
893        assert_eq!(Some(CT_1).into_glib(), 1);
894        assert_eq!(ClockTime::NONE.into_glib(), ffi::GST_CLOCK_TIME_NONE);
895
896        let ct_1_from: ClockTime = unsafe { try_from_glib(1u64) }.unwrap();
897        assert_eq!(ct_1_from, CT_1);
898
899        let opt_ct_some: Option<ClockTime> = unsafe { from_glib(1u64) };
900        assert_eq!(opt_ct_some, Some(CT_1));
901
902        let ct_none: Option<ClockTime> = unsafe { from_glib(ffi::GST_CLOCK_TIME_NONE) };
903        assert_eq!(ct_none, None);
904    }
905
906    #[test]
907    #[allow(clippy::eq_op, clippy::op_ref)]
908    fn ops() {
909        assert_eq!(CT_10 + CT_20, CT_30);
910        assert_eq!(CT_30 - CT_20, CT_10);
911        assert_eq!(CT_30 - CT_30, ClockTime::ZERO);
912        assert_eq!(CT_10 * 3, CT_30);
913        assert_eq!(3 * CT_10, CT_30);
914        assert_eq!(CT_20 / 2, CT_10);
915        assert_eq!(CT_20 / CT_2, 10);
916        assert_eq!(CT_30.nseconds(), 30);
917
918        assert_eq!(P_CT_1 + P_CT_2, P_CT_3);
919        assert_eq!(P_CT_3 + N_CT_2, P_CT_1);
920        assert_eq!(P_CT_2 + N_CT_3, N_CT_1);
921        assert_eq!(N_CT_3 + P_CT_1, N_CT_2);
922        assert_eq!(N_CT_2 + P_CT_3, P_CT_1);
923        assert_eq!(N_CT_2 + N_CT_1, N_CT_3);
924
925        assert_eq!(CT_1 + P_CT_2, P_CT_3);
926        assert_eq!(P_CT_1 + CT_2, P_CT_3);
927        assert_eq!(CT_3 + N_CT_1, P_CT_2);
928        assert_eq!(N_CT_1 + CT_2, P_CT_1);
929
930        assert_eq!(P_CT_3 - P_CT_2, P_CT_1);
931        assert_eq!(P_CT_2 - P_CT_3, N_CT_1);
932        assert_eq!(P_CT_2 - N_CT_1, P_CT_3);
933        assert_eq!(N_CT_2 - P_CT_1, N_CT_3);
934        assert_eq!(N_CT_3 - N_CT_1, N_CT_2);
935
936        assert_eq!(CT_3 - P_CT_2, P_CT_1);
937        assert_eq!(P_CT_3 - CT_2, P_CT_1);
938        assert_eq!(N_CT_2 - CT_1, N_CT_3);
939        assert_eq!(CT_2 - N_CT_1, P_CT_3);
940
941        assert_eq!(P_CT_1 * 2i64, P_CT_2);
942        assert_eq!(P_CT_1 * -2i64, N_CT_2);
943        assert_eq!(N_CT_1 * 2i64, N_CT_2);
944        assert_eq!(N_CT_1 * -2i64, P_CT_2);
945
946        assert_eq!(2i64 * P_CT_1, P_CT_2);
947        assert_eq!(-2i64 * P_CT_1, N_CT_2);
948
949        assert_eq!(P_CT_1 * 2u64, P_CT_2);
950        assert_eq!(N_CT_1 * 2u64, N_CT_2);
951
952        assert_eq!(P_CT_2 / 2i64, P_CT_1);
953        assert_eq!(P_CT_2 / -2i64, N_CT_1);
954        assert_eq!(N_CT_2 / 2i64, N_CT_1);
955        assert_eq!(N_CT_2 / -2i64, P_CT_1);
956
957        assert_eq!(P_CT_2 / N_CT_2, Signed::Negative(1));
958
959        assert_eq!(P_CT_2 / 2u64, P_CT_1);
960        assert_eq!(N_CT_2 / 2u64, N_CT_1);
961
962        assert_eq!(P_CT_3 % 2i64, P_CT_1);
963        assert_eq!(P_CT_3 % -2i64, P_CT_1);
964        assert_eq!(N_CT_3 % 2i64, N_CT_1);
965        assert_eq!(N_CT_3 % -2i64, N_CT_1);
966
967        assert_eq!(N_CT_3 % N_CT_2, N_CT_1);
968
969        assert_eq!(P_CT_3 % 2u64, P_CT_1);
970        assert_eq!(N_CT_3 % 2u64, N_CT_1);
971    }
972
973    #[test]
974    fn checked_ops() {
975        assert_eq!(CT_1.checked_add(CT_1), Some(CT_2));
976        assert_eq!(P_CT_1.checked_add(P_CT_2), Some(P_CT_3));
977        assert_eq!(P_CT_3.checked_add(N_CT_2), Some(P_CT_1));
978        assert_eq!(P_CT_2.checked_add(N_CT_3), Some(N_CT_1));
979        assert_eq!(N_CT_3.checked_add(P_CT_1), Some(N_CT_2));
980        assert_eq!(N_CT_2.checked_add(P_CT_3), Some(P_CT_1));
981        assert_eq!(N_CT_2.checked_add(N_CT_1), Some(N_CT_3));
982
983        assert_eq!(CT_1.opt_checked_add(CT_1), Ok(Some(CT_2)));
984        assert_eq!(CT_1.opt_checked_add(Some(CT_1)), Ok(Some(CT_2)));
985        assert_eq!(Some(CT_1).opt_checked_add(Some(CT_1)), Ok(Some(CT_2)));
986        assert_eq!(CT_1.opt_checked_add(ClockTime::NONE), Ok(None));
987        assert_eq!(Some(CT_1).opt_checked_add(ClockTime::NONE), Ok(None));
988
989        assert_eq!(CT_1.opt_checked_add(P_CT_1), Ok(Some(P_CT_2)));
990        assert_eq!(N_CT_3.opt_checked_add(CT_1), Ok(Some(N_CT_2)));
991
992        assert!(ClockTime::MAX.checked_add(CT_1).is_none());
993        assert_eq!(
994            ClockTime::MAX.opt_checked_add(Some(CT_1)),
995            Err(opt_ops::Error::Overflow)
996        );
997
998        assert_eq!(P_CT_1.opt_checked_add(P_CT_1), Ok(Some(P_CT_2)));
999        assert_eq!(P_CT_1.opt_checked_add(Some(N_CT_2)), Ok(Some(N_CT_1)));
1000        assert_eq!(Some(P_CT_1).opt_checked_add(Some(P_CT_1)), Ok(Some(P_CT_2)));
1001        assert_eq!(P_CT_1.opt_checked_add(ClockTime::NONE), Ok(None));
1002        assert_eq!(Some(N_CT_1).opt_checked_add(ClockTime::NONE), Ok(None));
1003
1004        assert_eq!(
1005            ClockTime::MAX.into_positive().opt_checked_add(Some(P_CT_1)),
1006            Err(opt_ops::Error::Overflow)
1007        );
1008
1009        assert_eq!(CT_2.checked_sub(CT_1), Some(CT_1));
1010        assert_eq!(P_CT_3.checked_sub(P_CT_2), Some(P_CT_1));
1011        assert_eq!(P_CT_2.checked_sub(P_CT_3), Some(N_CT_1));
1012        assert_eq!(P_CT_2.checked_sub(N_CT_1), Some(P_CT_3));
1013        assert_eq!(N_CT_2.checked_sub(P_CT_1), Some(N_CT_3));
1014        assert_eq!(N_CT_3.checked_sub(N_CT_1), Some(N_CT_2));
1015        assert_eq!(N_CT_2.checked_sub(N_CT_3), Some(P_CT_1));
1016
1017        assert_eq!(CT_2.opt_checked_sub(CT_1), Ok(Some(CT_1)));
1018        assert_eq!(CT_2.opt_checked_sub(Some(CT_1)), Ok(Some(CT_1)));
1019        assert_eq!(Some(CT_2).opt_checked_sub(CT_1), Ok(Some(CT_1)));
1020        assert_eq!(Some(CT_2).opt_checked_sub(Some(CT_1)), Ok(Some(CT_1)));
1021        assert_eq!(CT_2.opt_checked_sub(ClockTime::NONE), Ok(None));
1022        assert_eq!(Some(CT_2).opt_checked_sub(ClockTime::NONE), Ok(None));
1023
1024        assert_eq!(P_CT_2.opt_checked_sub(CT_1), Ok(Some(P_CT_1)));
1025        assert_eq!(N_CT_2.opt_checked_sub(CT_1), Ok(Some(N_CT_3)));
1026
1027        assert!(CT_1.checked_sub(CT_2).is_none());
1028        assert_eq!(
1029            Some(CT_1).opt_checked_sub(CT_2),
1030            Err(opt_ops::Error::Overflow)
1031        );
1032
1033        assert_eq!(P_CT_2.opt_checked_sub(Some(N_CT_1)), Ok(Some(P_CT_3)));
1034        assert_eq!(Some(N_CT_2).opt_checked_sub(P_CT_1), Ok(Some(N_CT_3)));
1035
1036        assert_eq!(CT_1.checked_mul(2), Some(CT_2));
1037        assert_eq!(Some(CT_1).opt_checked_mul(2), Ok(Some(CT_2)));
1038        assert_eq!(1u64.opt_checked_mul(Some(CT_2)), Ok(Some(CT_2)));
1039        assert_eq!(P_CT_1.checked_mul(2), Some(P_CT_2));
1040        assert_eq!(P_CT_1.checked_mul(-2), Some(N_CT_2));
1041        assert_eq!(N_CT_1.checked_mul(2), Some(N_CT_2));
1042        assert_eq!(N_CT_1.checked_mul(-2), Some(P_CT_2));
1043
1044        assert_eq!(Some(P_CT_1).opt_checked_mul(-2i64), Ok(Some(N_CT_2)));
1045        assert_eq!(N_CT_1.opt_checked_mul(2u64), Ok(Some(N_CT_2)));
1046
1047        assert_eq!((-2i64).opt_checked_mul(Some(P_CT_1)), Ok(Some(N_CT_2)));
1048
1049        assert_eq!(P_CT_1.checked_mul_unsigned(2u64), Some(P_CT_2));
1050        assert_eq!(N_CT_1.checked_mul_unsigned(2u64), Some(N_CT_2));
1051
1052        assert_eq!(CT_3.checked_div(3), Some(CT_1));
1053        assert_eq!(P_CT_3.checked_div(3), Some(P_CT_1));
1054        assert_eq!(P_CT_3.checked_div(-3), Some(N_CT_1));
1055        assert_eq!(N_CT_3.checked_div(3), Some(N_CT_1));
1056        assert_eq!(N_CT_3.checked_div(-3), Some(P_CT_1));
1057
1058        assert_eq!(Some(CT_3).opt_checked_div(CT_3), Ok(Some(1)));
1059
1060        assert_eq!(Some(P_CT_3).opt_checked_div(-3i64), Ok(Some(N_CT_1)));
1061        assert_eq!(N_CT_3.opt_checked_div(3u64), Ok(Some(N_CT_1)));
1062
1063        assert_eq!(P_CT_3.checked_div_unsigned(3u64), Some(P_CT_1));
1064        assert_eq!(N_CT_3.checked_div_unsigned(3u64), Some(N_CT_1));
1065    }
1066
1067    #[test]
1068    fn overflowing_ops() {
1069        assert_eq!(CT_1.overflowing_add(CT_2), (CT_3, false));
1070        assert_eq!(CT_1.opt_overflowing_add(Some(CT_2)), Some((CT_3, false)));
1071        assert_eq!(Some(CT_1).opt_overflowing_add(CT_2), Some((CT_3, false)));
1072        assert_eq!(
1073            Some(CT_1).opt_overflowing_add(Some(CT_2)),
1074            Some((CT_3, false))
1075        );
1076
1077        assert_eq!(ClockTime::NONE.opt_overflowing_add(CT_2), None);
1078        assert_eq!(CT_1.opt_overflowing_add(ClockTime::NONE), None);
1079
1080        assert_eq!(
1081            ClockTime::MAX.overflowing_add(CT_1),
1082            (ClockTime::ZERO, true)
1083        );
1084        assert_eq!(
1085            Some(ClockTime::MAX).opt_overflowing_add(Some(CT_1)),
1086            Some((ClockTime::ZERO, true)),
1087        );
1088
1089        assert_eq!(CT_3.overflowing_sub(CT_2), (CT_1, false));
1090        assert_eq!(CT_3.opt_overflowing_sub(Some(CT_2)), Some((CT_1, false)));
1091        assert_eq!(Some(CT_3).opt_overflowing_sub(CT_2), Some((CT_1, false)));
1092        assert_eq!(
1093            Some(CT_3).opt_overflowing_sub(Some(CT_2)),
1094            Some((CT_1, false))
1095        );
1096        assert_eq!(
1097            Some(CT_3).opt_overflowing_sub(&Some(CT_2)),
1098            Some((CT_1, false))
1099        );
1100        assert_eq!(ClockTime::NONE.opt_overflowing_sub(CT_2), None);
1101        assert_eq!(CT_2.opt_overflowing_sub(ClockTime::NONE), None);
1102
1103        assert_eq!(CT_1.overflowing_sub(CT_2), (ClockTime::MAX, true));
1104        assert_eq!(
1105            Some(CT_1).opt_overflowing_sub(CT_2),
1106            Some((ClockTime::MAX, true))
1107        );
1108    }
1109
1110    #[test]
1111    fn saturating_ops() {
1112        let p_ct_max: Signed<ClockTime> = ClockTime::MAX.into_positive();
1113        let n_ct_max: Signed<ClockTime> = ClockTime::MAX.into_negative();
1114
1115        assert_eq!(CT_1.saturating_add(CT_2), CT_3);
1116        assert_eq!(P_CT_1.saturating_add(P_CT_2), P_CT_3);
1117        assert_eq!(P_CT_2.saturating_add(N_CT_3), N_CT_1);
1118        assert_eq!(P_CT_3.saturating_add(N_CT_2), P_CT_1);
1119        assert_eq!(N_CT_3.saturating_add(P_CT_1), N_CT_2);
1120        assert_eq!(N_CT_2.saturating_add(P_CT_3), P_CT_1);
1121        assert_eq!(N_CT_2.saturating_add(N_CT_1), N_CT_3);
1122
1123        assert_eq!(CT_1.opt_saturating_add(Some(CT_2)), Some(CT_3));
1124        assert_eq!(Some(CT_1).opt_saturating_add(Some(CT_2)), Some(CT_3));
1125        assert_eq!(Some(CT_1).opt_saturating_add(ClockTime::NONE), None);
1126
1127        assert_eq!(P_CT_1.opt_saturating_add(Some(CT_2)), Some(P_CT_3));
1128        assert_eq!(Some(CT_1).opt_saturating_add(P_CT_2), Some(P_CT_3));
1129
1130        assert_eq!(ClockTime::MAX.saturating_add(CT_1), ClockTime::MAX);
1131        assert_eq!(
1132            Some(ClockTime::MAX).opt_saturating_add(Some(CT_1)),
1133            Some(ClockTime::MAX)
1134        );
1135        assert_eq!(p_ct_max.saturating_add(P_CT_1), p_ct_max);
1136
1137        assert_eq!(CT_3.saturating_sub(CT_2), CT_1);
1138        assert_eq!(P_CT_3.saturating_sub(P_CT_2), P_CT_1);
1139        assert_eq!(P_CT_2.saturating_sub(P_CT_3), N_CT_1);
1140        assert_eq!(P_CT_2.saturating_sub(N_CT_1), P_CT_3);
1141        assert_eq!(N_CT_2.saturating_sub(P_CT_1), N_CT_3);
1142        assert_eq!(N_CT_3.saturating_sub(N_CT_1), N_CT_2);
1143        assert_eq!(N_CT_2.saturating_sub(N_CT_3), P_CT_1);
1144
1145        assert_eq!(CT_3.opt_saturating_sub(Some(CT_2)), Some(CT_1));
1146        assert_eq!(Some(CT_3).opt_saturating_sub(Some(CT_2)), Some(CT_1));
1147        assert_eq!(Some(CT_3).opt_saturating_sub(ClockTime::NONE), None);
1148
1149        assert_eq!(P_CT_2.opt_saturating_sub(Some(CT_3)), Some(N_CT_1));
1150        assert_eq!(Some(CT_3).opt_saturating_sub(P_CT_2), Some(P_CT_1));
1151
1152        assert!(CT_1.saturating_sub(CT_2).is_zero());
1153        assert_eq!(P_CT_1.saturating_sub(P_CT_2), N_CT_1);
1154        assert_eq!(
1155            Some(CT_1).opt_saturating_sub(Some(CT_2)),
1156            Some(ClockTime::ZERO)
1157        );
1158
1159        assert_eq!(CT_1.saturating_mul(2), CT_2);
1160        assert_eq!(ClockTime::MAX.saturating_mul(2), ClockTime::MAX);
1161
1162        assert_eq!(P_CT_1.saturating_mul(2), P_CT_2);
1163        assert_eq!(P_CT_1.saturating_mul(-2), N_CT_2);
1164        assert_eq!(N_CT_1.saturating_mul(2), N_CT_2);
1165        assert_eq!(N_CT_1.saturating_mul(-2), P_CT_2);
1166
1167        assert_eq!(Some(N_CT_1).opt_saturating_mul(-2i64), Some(P_CT_2));
1168        assert_eq!((-2i64).opt_saturating_mul(Some(N_CT_1)), Some(P_CT_2));
1169
1170        assert_eq!(P_CT_1.saturating_mul_unsigned(2u64), P_CT_2);
1171        assert_eq!(N_CT_1.saturating_mul_unsigned(2u64), N_CT_2);
1172
1173        assert_eq!(p_ct_max.saturating_mul(2), p_ct_max);
1174        assert_eq!(n_ct_max.saturating_mul(2), n_ct_max);
1175
1176        assert_eq!(Some(2i64).opt_saturating_mul(p_ct_max), Some(p_ct_max));
1177        assert_eq!(2u64.opt_saturating_mul(Some(n_ct_max)), Some(n_ct_max));
1178
1179        assert_eq!(p_ct_max.saturating_mul_unsigned(2u64), p_ct_max);
1180        assert_eq!(n_ct_max.saturating_mul_unsigned(2u64), n_ct_max);
1181    }
1182
1183    #[test]
1184    fn wrapping_ops() {
1185        assert_eq!(CT_1.wrapping_add(CT_2), CT_3);
1186        assert_eq!(CT_1.opt_wrapping_add(CT_2), Some(CT_3));
1187        assert_eq!(Some(CT_1).opt_wrapping_add(CT_2), Some(CT_3));
1188        assert_eq!(Some(CT_1).opt_wrapping_add(Some(CT_2)), Some(CT_3));
1189        assert_eq!(Some(CT_1).opt_wrapping_add(None), None);
1190
1191        assert_eq!(ClockTime::MAX.wrapping_add(CT_1), ClockTime::ZERO);
1192        assert_eq!(
1193            Some(ClockTime::MAX).opt_wrapping_add(Some(CT_1)),
1194            Some(ClockTime::ZERO)
1195        );
1196
1197        assert_eq!(CT_3.wrapping_sub(CT_2), CT_1);
1198        assert_eq!(CT_3.opt_wrapping_sub(CT_2), Some(CT_1));
1199        assert_eq!(Some(CT_3).opt_wrapping_sub(CT_2), Some(CT_1));
1200        assert_eq!(Some(CT_3).opt_wrapping_sub(Some(CT_2)), Some(CT_1));
1201        assert_eq!(Some(CT_3).opt_wrapping_sub(ClockTime::NONE), None);
1202
1203        assert_eq!(CT_1.wrapping_sub(CT_2), ClockTime::MAX);
1204        assert_eq!(
1205            Some(CT_1).opt_wrapping_sub(Some(CT_2)),
1206            Some(ClockTime::MAX)
1207        );
1208    }
1209
1210    #[test]
1211    fn mul_div_ops() {
1212        use muldiv::MulDiv;
1213
1214        assert_eq!(CT_1.mul_div_floor(7, 3), Some(CT_2));
1215
1216        assert_eq!(P_CT_1.mul_div_floor(7u64, 3), Some(P_CT_2));
1217        assert_eq!(P_CT_1.mul_div_floor(-7i64, 3), Some(N_CT_2));
1218        assert_eq!(P_CT_1.mul_div_floor(7i64, -3), Some(N_CT_2));
1219        assert_eq!(P_CT_1.mul_div_floor(-7i64, -3), Some(P_CT_2));
1220
1221        assert_eq!(N_CT_1.mul_div_floor(7u64, 3), Some(N_CT_2));
1222        assert_eq!(N_CT_1.mul_div_floor(-7i64, 3), Some(P_CT_2));
1223        assert_eq!(N_CT_1.mul_div_floor(7i64, -3), Some(P_CT_2));
1224        assert_eq!(N_CT_1.mul_div_floor(-7i64, -3), Some(N_CT_2));
1225
1226        assert_eq!(CT_1.mul_div_round(10, 3), Some(CT_3));
1227        assert_eq!(CT_1.mul_div_round(8, 3), Some(CT_3));
1228
1229        assert_eq!(P_CT_1.mul_div_round(10u64, 3), Some(P_CT_3));
1230        assert_eq!(P_CT_1.mul_div_round(8u64, 3), Some(P_CT_3));
1231        assert_eq!(P_CT_1.mul_div_round(-10i64, 3), Some(N_CT_3));
1232        assert_eq!(P_CT_1.mul_div_round(-8i64, 3), Some(N_CT_3));
1233        assert_eq!(P_CT_1.mul_div_round(10i64, -3), Some(N_CT_3));
1234        assert_eq!(P_CT_1.mul_div_round(-10i64, -3), Some(P_CT_3));
1235
1236        assert_eq!(N_CT_1.mul_div_round(10u64, 3), Some(N_CT_3));
1237        assert_eq!(N_CT_1.mul_div_round(-10i64, 3), Some(P_CT_3));
1238        assert_eq!(N_CT_1.mul_div_round(10i64, -3), Some(P_CT_3));
1239        assert_eq!(N_CT_1.mul_div_round(-10i64, -3), Some(N_CT_3));
1240
1241        assert_eq!(CT_1.mul_div_ceil(7, 3), Some(CT_3));
1242
1243        assert_eq!(P_CT_1.mul_div_ceil(7u64, 3), Some(P_CT_3));
1244        assert_eq!(P_CT_1.mul_div_ceil(-7i64, 3), Some(N_CT_3));
1245        assert_eq!(P_CT_1.mul_div_ceil(7i64, -3), Some(N_CT_3));
1246        assert_eq!(P_CT_1.mul_div_ceil(-7i64, -3), Some(P_CT_3));
1247
1248        assert_eq!(N_CT_1.mul_div_ceil(7u64, 3), Some(N_CT_3));
1249        assert_eq!(N_CT_1.mul_div_ceil(-7i64, 3), Some(P_CT_3));
1250        assert_eq!(N_CT_1.mul_div_ceil(7i64, -3), Some(P_CT_3));
1251        assert_eq!(N_CT_1.mul_div_ceil(-7i64, -3), Some(N_CT_3));
1252    }
1253
1254    #[test]
1255    #[allow(clippy::nonminimal_bool)]
1256    fn comp() {
1257        assert!(ClockTime::ZERO < CT_2);
1258        assert!(Some(ClockTime::ZERO) < Some(CT_2));
1259        assert!(CT_2 < CT_3);
1260        assert!(Some(CT_2) < Some(CT_3));
1261        assert!(ClockTime::ZERO < CT_3);
1262        assert!(Some(ClockTime::ZERO) < Some(CT_3));
1263
1264        assert_eq!(CT_2, CT_2);
1265        assert_ne!(CT_3, CT_2);
1266
1267        assert!(ClockTime::ZERO.into_positive() < P_CT_1);
1268        assert!(ClockTime::ZERO.into_positive() > N_CT_1);
1269        assert!(P_CT_1 < P_CT_2);
1270        assert!(P_CT_1 > N_CT_2);
1271        assert!(N_CT_1 < P_CT_2);
1272        assert!(N_CT_3 < N_CT_2);
1273
1274        assert!(P_CT_1 < CT_2);
1275        assert!(CT_1 < P_CT_2);
1276        assert!(N_CT_2 < CT_1);
1277        assert!(CT_1 > N_CT_2);
1278
1279        assert_eq!(CT_2, P_CT_2);
1280        assert_ne!(N_CT_3, CT_3);
1281
1282        assert_eq!(Some(CT_2).opt_lt(Some(CT_3)), Some(true));
1283        assert_eq!(Some(CT_3).opt_lt(CT_2), Some(false));
1284        assert_eq!(Some(CT_2).opt_le(Some(CT_3)), Some(true));
1285        assert_eq!(Some(CT_3).opt_le(CT_3), Some(true));
1286
1287        assert_eq!(Some(P_CT_2).opt_lt(Some(P_CT_3)), Some(true));
1288        assert_eq!(Some(P_CT_3).opt_lt(P_CT_2), Some(false));
1289        assert_eq!(Some(P_CT_2).opt_le(Some(P_CT_3)), Some(true));
1290        assert_eq!(Some(P_CT_3).opt_le(P_CT_3), Some(true));
1291
1292        assert_eq!(Some(P_CT_0).opt_lt(P_CT_NONE), None);
1293        assert_eq!(P_CT_NONE.opt_lt(P_CT_0), None);
1294
1295        assert_eq!(Some(N_CT_3).opt_lt(Some(N_CT_2)), Some(true));
1296        assert_eq!(Some(N_CT_2).opt_lt(N_CT_3), Some(false));
1297        assert_eq!(Some(N_CT_3).opt_le(Some(N_CT_2)), Some(true));
1298        assert_eq!(Some(N_CT_3).opt_le(N_CT_3), Some(true));
1299
1300        assert_eq!(Some(P_CT_2).opt_lt(N_CT_3), Some(false));
1301        assert_eq!(Some(N_CT_3).opt_lt(Some(P_CT_2)), Some(true));
1302
1303        assert!(CT_3 > CT_2);
1304        assert!(Some(CT_3) > Some(CT_2));
1305        assert!(CT_2 > ClockTime::ZERO);
1306        assert!(Some(CT_2) > Some(ClockTime::ZERO));
1307        assert!(CT_3 > ClockTime::ZERO);
1308        assert!(Some(CT_3) > Some(ClockTime::ZERO));
1309
1310        assert!(!(ClockTime::NONE > None));
1311        // This doesn't work due to the `PartialOrd` impl on `Option<T>`
1312        //assert_eq!(Some(ClockTime::ZERO) > ClockTime::ZERO, false);
1313        assert!(!(Some(ClockTime::ZERO) < ClockTime::NONE));
1314        assert_eq!(Some(CT_3).opt_gt(Some(CT_2)), Some(true));
1315        assert_eq!(Some(CT_3).opt_ge(Some(CT_2)), Some(true));
1316        assert_eq!(Some(CT_3).opt_ge(CT_3), Some(true));
1317
1318        assert_eq!(Some(P_CT_3).opt_gt(Some(P_CT_2)), Some(true));
1319        assert_eq!(Some(P_CT_3).opt_ge(Some(P_CT_2)), Some(true));
1320        assert_eq!(Some(P_CT_3).opt_ge(P_CT_3), Some(true));
1321
1322        assert_eq!(Some(P_CT_0).opt_gt(P_CT_NONE), None);
1323        assert_eq!(P_CT_NONE.opt_gt(P_CT_0), None);
1324
1325        assert_eq!(Some(N_CT_3).opt_gt(Some(N_CT_2)), Some(false));
1326        assert_eq!(Some(N_CT_3).opt_ge(Some(N_CT_2)), Some(false));
1327        assert_eq!(Some(N_CT_3).opt_ge(N_CT_3), Some(true));
1328
1329        assert_eq!(Some(P_CT_2).opt_gt(N_CT_3), Some(true));
1330        assert_eq!(Some(N_CT_3).opt_gt(Some(P_CT_2)), Some(false));
1331
1332        assert!(!(ClockTime::NONE < None));
1333        assert!(!(ClockTime::NONE > None));
1334
1335        // This doesn't work due to the `PartialOrd` impl on `Option<T>`
1336        //assert!(Some(ClockTime::ZERO) > ClockTime::NONE, false);
1337        // Use opt_gt instead.
1338        assert_eq!(Some(ClockTime::ZERO).opt_gt(ClockTime::NONE), None);
1339        assert_eq!(ClockTime::ZERO.opt_gt(ClockTime::NONE), None);
1340        assert_eq!(ClockTime::ZERO.opt_ge(ClockTime::NONE), None);
1341        assert_eq!(ClockTime::NONE.opt_gt(Some(ClockTime::ZERO)), None);
1342        assert_eq!(ClockTime::NONE.opt_gt(ClockTime::ZERO), None);
1343        assert_eq!(ClockTime::NONE.opt_ge(ClockTime::ZERO), None);
1344
1345        assert!(!(Some(ClockTime::ZERO) < ClockTime::NONE));
1346        assert_eq!(Some(ClockTime::ZERO).opt_lt(ClockTime::NONE), None);
1347        assert_eq!(Some(ClockTime::ZERO).opt_le(ClockTime::NONE), None);
1348
1349        assert_eq!(CT_3.opt_min(CT_2), Some(CT_2));
1350        assert_eq!(CT_3.opt_min(Some(CT_2)), Some(CT_2));
1351        assert_eq!(Some(CT_3).opt_min(Some(CT_2)), Some(CT_2));
1352        assert_eq!(ClockTime::NONE.opt_min(Some(CT_2)), None);
1353        assert_eq!(Some(CT_3).opt_min(ClockTime::NONE), None);
1354
1355        assert_eq!(P_CT_3.opt_min(P_CT_2), Some(P_CT_2));
1356        assert_eq!(P_CT_2.opt_min(P_CT_3), Some(P_CT_2));
1357        assert_eq!(N_CT_3.opt_min(N_CT_2), Some(N_CT_3));
1358        assert_eq!(N_CT_2.opt_min(N_CT_3), Some(N_CT_3));
1359        assert_eq!(P_CT_2.opt_min(N_CT_3), Some(N_CT_3));
1360
1361        assert_eq!(CT_3.opt_max(CT_2), Some(CT_3));
1362        assert_eq!(CT_3.opt_max(Some(CT_2)), Some(CT_3));
1363        assert_eq!(Some(CT_3).opt_max(Some(CT_2)), Some(CT_3));
1364        assert_eq!(ClockTime::NONE.opt_max(Some(CT_2)), None);
1365        assert_eq!(Some(CT_3).opt_max(ClockTime::NONE), None);
1366
1367        assert_eq!(P_CT_3.opt_max(P_CT_2), Some(P_CT_3));
1368        assert_eq!(P_CT_2.opt_max(P_CT_3), Some(P_CT_3));
1369        assert_eq!(N_CT_3.opt_max(N_CT_2), Some(N_CT_2));
1370        assert_eq!(N_CT_2.opt_max(N_CT_3), Some(N_CT_2));
1371        assert_eq!(P_CT_2.opt_max(N_CT_3), Some(P_CT_2));
1372    }
1373
1374    #[test]
1375    fn display() {
1376        let none = Option::<ClockTime>::None;
1377        let some = Some(45_834_908_569_837 * ClockTime::NSECOND);
1378        let lots = ClockTime::from_nseconds(u64::MAX - 1);
1379
1380        // Simple
1381
1382        assert_eq!(format!("{:.0}", DisplayableOptClockTime(none)), "--:--:--");
1383        assert_eq!(
1384            format!("{:.3}", DisplayableOptClockTime(none)),
1385            "--:--:--.---"
1386        );
1387        assert_eq!(
1388            format!("{}", DisplayableOptClockTime(none)),
1389            "--:--:--.---------"
1390        );
1391
1392        assert_eq!(format!("{:.0}", DisplayableOptClockTime(some)), "12:43:54");
1393        assert_eq!(
1394            format!("{:.3}", DisplayableOptClockTime(some)),
1395            "12:43:54.908"
1396        );
1397        assert_eq!(
1398            format!("{}", DisplayableOptClockTime(some)),
1399            "12:43:54.908569837"
1400        );
1401
1402        assert_eq!(format!("{lots:.0}"), "5124095:34:33");
1403        assert_eq!(format!("{lots:.3}"), "5124095:34:33.709");
1404        assert_eq!(format!("{lots}"), "5124095:34:33.709551614");
1405
1406        // Precision caps at 9
1407        assert_eq!(
1408            format!("{:.10}", DisplayableOptClockTime(none)),
1409            "--:--:--.---------"
1410        );
1411        assert_eq!(
1412            format!("{:.10}", DisplayableOptClockTime(some)),
1413            "12:43:54.908569837"
1414        );
1415        assert_eq!(format!("{lots:.10}"), "5124095:34:33.709551614");
1416
1417        // Short width
1418
1419        assert_eq!(format!("{:4.0}", DisplayableOptClockTime(none)), "--:--:--");
1420        assert_eq!(
1421            format!("{:4.3}", DisplayableOptClockTime(none)),
1422            "--:--:--.---"
1423        );
1424        assert_eq!(
1425            format!("{:4}", DisplayableOptClockTime(none)),
1426            "--:--:--.---------"
1427        );
1428
1429        assert_eq!(format!("{:4.0}", DisplayableOptClockTime(some)), "12:43:54");
1430        assert_eq!(
1431            format!("{:4.3}", DisplayableOptClockTime(some)),
1432            "12:43:54.908"
1433        );
1434        assert_eq!(
1435            format!("{:4}", DisplayableOptClockTime(some)),
1436            "12:43:54.908569837"
1437        );
1438
1439        assert_eq!(format!("{lots:4.0}"), "5124095:34:33");
1440        assert_eq!(format!("{lots:4.3}"), "5124095:34:33.709");
1441        assert_eq!(format!("{lots:4}"), "5124095:34:33.709551614");
1442
1443        // Simple padding
1444
1445        assert_eq!(
1446            format!("{:>9.0}", DisplayableOptClockTime(none)),
1447            " --:--:--"
1448        );
1449        assert_eq!(
1450            format!("{:<9.0}", DisplayableOptClockTime(none)),
1451            "--:--:-- "
1452        );
1453        assert_eq!(
1454            format!("{:^10.0}", DisplayableOptClockTime(none)),
1455            " --:--:-- "
1456        );
1457        assert_eq!(
1458            format!("{:>13.3}", DisplayableOptClockTime(none)),
1459            " --:--:--.---"
1460        );
1461        assert_eq!(
1462            format!("{:<13.3}", DisplayableOptClockTime(none)),
1463            "--:--:--.--- "
1464        );
1465        assert_eq!(
1466            format!("{:^14.3}", DisplayableOptClockTime(none)),
1467            " --:--:--.--- "
1468        );
1469        assert_eq!(
1470            format!("{:>19}", DisplayableOptClockTime(none)),
1471            " --:--:--.---------"
1472        );
1473        assert_eq!(
1474            format!("{:<19}", DisplayableOptClockTime(none)),
1475            "--:--:--.--------- "
1476        );
1477        assert_eq!(
1478            format!("{:^20}", DisplayableOptClockTime(none)),
1479            " --:--:--.--------- "
1480        );
1481
1482        assert_eq!(
1483            format!("{:>9.0}", DisplayableOptClockTime(some)),
1484            " 12:43:54"
1485        );
1486        assert_eq!(
1487            format!("{:<9.0}", DisplayableOptClockTime(some)),
1488            "12:43:54 "
1489        );
1490        assert_eq!(
1491            format!("{:^10.0}", DisplayableOptClockTime(some)),
1492            " 12:43:54 "
1493        );
1494        assert_eq!(
1495            format!("{:>13.3}", DisplayableOptClockTime(some)),
1496            " 12:43:54.908"
1497        );
1498        assert_eq!(
1499            format!("{:<13.3}", DisplayableOptClockTime(some)),
1500            "12:43:54.908 "
1501        );
1502        assert_eq!(
1503            format!("{:^14.3}", DisplayableOptClockTime(some)),
1504            " 12:43:54.908 "
1505        );
1506        assert_eq!(
1507            format!("{:>19}", DisplayableOptClockTime(some)),
1508            " 12:43:54.908569837"
1509        );
1510        assert_eq!(
1511            format!("{:<19}", DisplayableOptClockTime(some)),
1512            "12:43:54.908569837 "
1513        );
1514        assert_eq!(
1515            format!("{:^20}", DisplayableOptClockTime(some)),
1516            " 12:43:54.908569837 "
1517        );
1518
1519        assert_eq!(format!("{lots:>14.0}"), " 5124095:34:33");
1520        assert_eq!(format!("{lots:<14.0}"), "5124095:34:33 ");
1521        assert_eq!(format!("{lots:^15.0}"), " 5124095:34:33 ");
1522        assert_eq!(format!("{lots:>18.3}"), " 5124095:34:33.709");
1523        assert_eq!(format!("{lots:<18.3}"), "5124095:34:33.709 ");
1524        assert_eq!(format!("{lots:^19.3}"), " 5124095:34:33.709 ");
1525        assert_eq!(format!("{lots:>24}"), " 5124095:34:33.709551614");
1526        assert_eq!(format!("{lots:<24}"), "5124095:34:33.709551614 ");
1527        assert_eq!(format!("{lots:^25}"), " 5124095:34:33.709551614 ");
1528
1529        // Padding with sign or zero-extension
1530
1531        assert_eq!(
1532            format!("{:+11.0}", DisplayableOptClockTime(none)),
1533            "   --:--:--"
1534        );
1535        assert_eq!(
1536            format!("{:011.0}", DisplayableOptClockTime(none)),
1537            "-----:--:--"
1538        );
1539        assert_eq!(
1540            format!("{:+011.0}", DisplayableOptClockTime(none)),
1541            "-----:--:--"
1542        );
1543        assert_eq!(
1544            format!("{:+15.3}", DisplayableOptClockTime(none)),
1545            "   --:--:--.---"
1546        );
1547        assert_eq!(
1548            format!("{:015.3}", DisplayableOptClockTime(none)),
1549            "-----:--:--.---"
1550        );
1551        assert_eq!(
1552            format!("{:+015.3}", DisplayableOptClockTime(none)),
1553            "-----:--:--.---"
1554        );
1555        assert_eq!(
1556            format!("{:+21}", DisplayableOptClockTime(none)),
1557            "   --:--:--.---------"
1558        );
1559        assert_eq!(
1560            format!("{:021}", DisplayableOptClockTime(none)),
1561            "-----:--:--.---------"
1562        );
1563        assert_eq!(
1564            format!("{:+021}", DisplayableOptClockTime(none)),
1565            "-----:--:--.---------"
1566        );
1567
1568        assert_eq!(
1569            format!("{:+11.0}", DisplayableOptClockTime(some)),
1570            "  +12:43:54"
1571        );
1572        assert_eq!(
1573            format!("{:011.0}", DisplayableOptClockTime(some)),
1574            "00012:43:54"
1575        );
1576        assert_eq!(
1577            format!("{:+011.0}", DisplayableOptClockTime(some)),
1578            "+0012:43:54"
1579        );
1580        assert_eq!(
1581            format!("{:+15.3}", DisplayableOptClockTime(some)),
1582            "  +12:43:54.908"
1583        );
1584        assert_eq!(
1585            format!("{:015.3}", DisplayableOptClockTime(some)),
1586            "00012:43:54.908"
1587        );
1588        assert_eq!(
1589            format!("{:+015.3}", DisplayableOptClockTime(some)),
1590            "+0012:43:54.908"
1591        );
1592        assert_eq!(
1593            format!("{:+21}", DisplayableOptClockTime(some)),
1594            "  +12:43:54.908569837"
1595        );
1596        assert_eq!(
1597            format!("{:021}", DisplayableOptClockTime(some)),
1598            "00012:43:54.908569837"
1599        );
1600        assert_eq!(
1601            format!("{:+021}", DisplayableOptClockTime(some)),
1602            "+0012:43:54.908569837"
1603        );
1604
1605        assert_eq!(format!("{lots:+16.0}"), "  +5124095:34:33");
1606        assert_eq!(format!("{lots:016.0}"), "0005124095:34:33");
1607        assert_eq!(format!("{lots:+016.0}"), "+005124095:34:33");
1608        assert_eq!(format!("{lots:+20.3}"), "  +5124095:34:33.709");
1609        assert_eq!(format!("{lots:020.3}"), "0005124095:34:33.709");
1610        assert_eq!(format!("{lots:+020.3}"), "+005124095:34:33.709");
1611        assert_eq!(format!("{lots:+26}"), "  +5124095:34:33.709551614");
1612        assert_eq!(format!("{lots:026}"), "0005124095:34:33.709551614");
1613        assert_eq!(format!("{lots:+026}"), "+005124095:34:33.709551614");
1614    }
1615
1616    #[test]
1617    fn iter_sum() {
1618        let s: ClockTime = vec![ClockTime::from_seconds(1), ClockTime::from_seconds(2)]
1619            .into_iter()
1620            .sum();
1621        assert_eq!(s, ClockTime::from_seconds(3));
1622    }
1623
1624    #[test]
1625    #[should_panic]
1626    fn attempt_to_build_from_clock_time_none() {
1627        let _ = ClockTime::from_nseconds(ffi::GST_CLOCK_TIME_NONE);
1628    }
1629
1630    #[test]
1631    #[should_panic]
1632    fn attempt_to_build_from_u64max() {
1633        let _ = ClockTime::from_nseconds(u64::MAX);
1634    }
1635
1636    #[test]
1637    fn try_into_signed() {
1638        let time = crate::Signed::Positive(ClockTime::from_nseconds(0));
1639        assert_eq!(i64::try_from(time), Ok(0));
1640
1641        let time = crate::Signed::Positive(ClockTime::from_nseconds(123));
1642        assert_eq!(i64::try_from(time), Ok(123));
1643
1644        let time = crate::Signed::Positive(ClockTime::from_nseconds(u64::MAX - 1));
1645        assert!(i64::try_from(time).is_err());
1646
1647        let time = crate::Signed::Positive(ClockTime::from_nseconds(u64::MAX >> 1));
1648        assert_eq!(i64::MAX as i128, (u64::MAX >> 1) as i128);
1649        assert_eq!(i64::try_from(time), Ok(i64::MAX));
1650
1651        let time = crate::Signed::Negative(ClockTime::from_nseconds(0));
1652        assert_eq!(i64::try_from(time), Ok(0));
1653
1654        let time = crate::Signed::Negative(ClockTime::from_nseconds(123));
1655        assert_eq!(i64::try_from(time), Ok(-123));
1656
1657        let time = crate::Signed::Negative(ClockTime::from_nseconds(u64::MAX - 1));
1658        assert!(i64::try_from(time).is_err());
1659
1660        let time = crate::Signed::Negative(ClockTime::from_nseconds(u64::MAX >> 1));
1661        assert_eq!(i64::MIN as i128 + 1, -((u64::MAX >> 1) as i128));
1662        assert_eq!(i64::try_from(time), Ok(i64::MIN + 1));
1663
1664        let time = crate::Signed::Negative(ClockTime::from_nseconds((u64::MAX >> 1) + 1));
1665        assert_eq!(i64::MIN as i128, -(((u64::MAX >> 1) + 1) as i128));
1666        assert_eq!(i64::try_from(time), Ok(i64::MIN));
1667    }
1668
1669    #[test]
1670    fn properties_macro_usage() {
1671        use super::ClockTime;
1672        use glib::{prelude::*, subclass::prelude::*};
1673        use std::cell::Cell;
1674
1675        #[derive(Default, glib::Properties)]
1676        #[properties(wrapper_type = TestObject)]
1677        pub struct TestObjectImp {
1678            #[property(get, set)]
1679            clock_time: Cell<ClockTime>,
1680            #[property(get, set)]
1681            optional_clock_time: Cell<Option<ClockTime>>,
1682        }
1683
1684        #[glib::object_subclass]
1685        impl ObjectSubclass for TestObjectImp {
1686            const NAME: &'static str = "GstTestObject";
1687            type Type = TestObject;
1688        }
1689
1690        impl ObjectImpl for TestObjectImp {
1691            fn properties() -> &'static [glib::ParamSpec] {
1692                Self::derived_properties()
1693            }
1694
1695            fn set_property(&self, id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
1696                self.derived_set_property(id, value, pspec);
1697            }
1698
1699            fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
1700                self.derived_property(id, pspec)
1701            }
1702        }
1703
1704        glib::wrapper! {
1705            pub struct TestObject(ObjectSubclass<TestObjectImp>);
1706        }
1707
1708        let obj: TestObject = glib::Object::new();
1709
1710        assert_eq!(obj.clock_time(), ClockTime::default());
1711        obj.set_clock_time(ClockTime::MAX);
1712        assert_eq!(obj.clock_time(), ClockTime::MAX);
1713
1714        assert_eq!(obj.optional_clock_time(), None);
1715        obj.set_optional_clock_time(ClockTime::MAX);
1716        assert_eq!(obj.optional_clock_time(), Some(ClockTime::MAX));
1717    }
1718
1719    #[test]
1720    fn seconds_float() {
1721        let res = ClockTime::ZERO;
1722        assert_eq!(res.seconds_f32(), 0.0);
1723        assert_eq!(res.seconds_f64(), 0.0);
1724
1725        let res = ClockTime::from_nseconds(2_700_000_000);
1726        assert_eq!(res.seconds_f32(), 2.7);
1727        assert_eq!(res.seconds_f64(), 2.7);
1728
1729        let res = ClockTime::MAX;
1730        assert_eq!(res.seconds_f32(), 18_446_744_073.709_553);
1731        assert_eq!(res.seconds_f64(), 18_446_744_073.709_553);
1732    }
1733
1734    #[test]
1735    fn seconds_float_signed() {
1736        let pos = Signed::Positive(ClockTime::ZERO);
1737        assert_eq!(pos.seconds_f32(), 0.0);
1738        assert_eq!(pos.seconds_f64(), 0.0);
1739        let neg = Signed::Negative(ClockTime::ZERO);
1740        assert_eq!(neg.seconds_f32(), 0.0);
1741        assert_eq!(neg.seconds_f64(), 0.0);
1742
1743        let pos = Signed::Positive(ClockTime::from_nseconds(2_700_000_000));
1744        assert_eq!(pos.seconds_f32(), 2.7);
1745        assert_eq!(pos.seconds_f64(), 2.7);
1746        let neg = Signed::Negative(ClockTime::from_nseconds(2_700_000_000));
1747        assert_eq!(neg.seconds_f32(), -2.7);
1748        assert_eq!(neg.seconds_f64(), -2.7);
1749
1750        let pos = Signed::Positive(ClockTime::MAX);
1751        assert_eq!(pos.seconds_f32(), 18_446_744_073.709_553);
1752        assert_eq!(pos.seconds_f64(), 18_446_744_073.709_553);
1753        let neg = Signed::Negative(ClockTime::MAX);
1754        assert_eq!(neg.seconds_f32(), -18_446_744_073.709_553);
1755        assert_eq!(neg.seconds_f64(), -18_446_744_073.709_553);
1756    }
1757
1758    #[test]
1759    fn try_from_seconds_f32() {
1760        let res = ClockTime::try_from_seconds_f32(0.0);
1761        assert_eq!(res, Ok(ClockTime::ZERO));
1762        let res = ClockTime::try_from_seconds_f32(1e-20);
1763        assert_eq!(res, Ok(ClockTime::ZERO));
1764        let res = ClockTime::try_from_seconds_f32(4.2e-7);
1765        assert_eq!(res, Ok(ClockTime::from_nseconds(420)));
1766        let res = ClockTime::try_from_seconds_f32(2.7);
1767        assert_eq!(res, Ok(ClockTime::from_nseconds(2_700_000_048)));
1768        // subnormal float:
1769        let res = ClockTime::try_from_seconds_f32(f32::from_bits(1));
1770        assert_eq!(res, Ok(ClockTime::ZERO));
1771
1772        // the conversion uses rounding with tie resolution to even
1773        let res = ClockTime::try_from_seconds_f32(0.999e-9);
1774        assert_eq!(res, Ok(ClockTime::from_nseconds(1)));
1775
1776        let res = ClockTime::try_from_seconds_f32(-5.0);
1777        assert!(res.is_err());
1778        let res = ClockTime::try_from_seconds_f32(f32::NAN);
1779        assert!(res.is_err());
1780        let res = ClockTime::try_from_seconds_f32(2e19);
1781        assert!(res.is_err());
1782
1783        // this float represents exactly 976562.5e-9
1784        let val = f32::from_bits(0x3A80_0000);
1785        let res = ClockTime::try_from_seconds_f32(val);
1786        assert_eq!(res, Ok(ClockTime::from_nseconds(976_562)));
1787
1788        // this float represents exactly 2929687.5e-9
1789        let val = f32::from_bits(0x3B40_0000);
1790        let res = ClockTime::try_from_seconds_f32(val);
1791        assert_eq!(res, Ok(ClockTime::from_nseconds(2_929_688)));
1792
1793        // this float represents exactly 1.000_976_562_5
1794        let val = f32::from_bits(0x3F802000);
1795        let res = ClockTime::try_from_seconds_f32(val);
1796        assert_eq!(res, Ok(ClockTime::from_nseconds(1_000_976_562)));
1797
1798        // this float represents exactly 1.002_929_687_5
1799        let val = f32::from_bits(0x3F806000);
1800        let res = ClockTime::try_from_seconds_f32(val);
1801        assert_eq!(res, Ok(ClockTime::from_nseconds(1_002_929_688)));
1802    }
1803
1804    #[test]
1805    fn try_from_seconds_f64() {
1806        let res = ClockTime::try_from_seconds_f64(0.0);
1807        assert_eq!(res, Ok(ClockTime::ZERO));
1808        let res = ClockTime::try_from_seconds_f64(1e-20);
1809        assert_eq!(res, Ok(ClockTime::ZERO));
1810        let res = ClockTime::try_from_seconds_f64(4.2e-7);
1811        assert_eq!(res, Ok(ClockTime::from_nseconds(420)));
1812        let res = ClockTime::try_from_seconds_f64(2.7);
1813        assert_eq!(res, Ok(ClockTime::from_nseconds(2_700_000_000)));
1814        // subnormal float:
1815        let res = ClockTime::try_from_seconds_f64(f64::from_bits(1));
1816        assert_eq!(res, Ok(ClockTime::ZERO));
1817
1818        // the conversion uses rounding with tie resolution to even
1819        let res = ClockTime::try_from_seconds_f64(0.999e-9);
1820        assert_eq!(res, Ok(ClockTime::from_nseconds(1)));
1821        let res = ClockTime::try_from_seconds_f64(0.999_999_999_499);
1822        assert_eq!(res, Ok(ClockTime::from_nseconds(999_999_999)));
1823        let res = ClockTime::try_from_seconds_f64(0.999_999_999_501);
1824        assert_eq!(res, Ok(ClockTime::from_seconds(1)));
1825        let res = ClockTime::try_from_seconds_f64(42.999_999_999_499);
1826        assert_eq!(res, Ok(ClockTime::from_nseconds(42_999_999_999)));
1827        let res = ClockTime::try_from_seconds_f64(42.999_999_999_501);
1828        assert_eq!(res, Ok(ClockTime::from_seconds(43)));
1829
1830        let res = ClockTime::try_from_seconds_f64(-5.0);
1831        assert!(res.is_err());
1832        let res = ClockTime::try_from_seconds_f64(f64::NAN);
1833        assert!(res.is_err());
1834        let res = ClockTime::try_from_seconds_f64(2e19);
1835        assert!(res.is_err());
1836
1837        // this float represents exactly 976562.5e-9
1838        let val = f64::from_bits(0x3F50_0000_0000_0000);
1839        let res = ClockTime::try_from_seconds_f64(val);
1840        assert_eq!(res, Ok(ClockTime::from_nseconds(976_562)));
1841
1842        // this float represents exactly 2929687.5e-9
1843        let val = f64::from_bits(0x3F68_0000_0000_0000);
1844        let res = ClockTime::try_from_seconds_f64(val);
1845        assert_eq!(res, Ok(ClockTime::from_nseconds(2_929_688)));
1846
1847        // this float represents exactly 1.000_976_562_5
1848        let val = f64::from_bits(0x3FF0_0400_0000_0000);
1849        let res = ClockTime::try_from_seconds_f64(val);
1850        assert_eq!(res, Ok(ClockTime::from_nseconds(1_000_976_562)));
1851
1852        // this float represents exactly 1.002_929_687_5
1853        let val = f64::from_bits(0x3FF0_0C00_0000_0000);
1854        let res = ClockTime::try_from_seconds_f64(val);
1855        assert_eq!(res, Ok(ClockTime::from_nseconds(1_002_929_688)));
1856    }
1857
1858    #[test]
1859    fn try_from_seconds_f32_signed() {
1860        let pos = Signed::<ClockTime>::from_seconds_f32(5.0);
1861        assert!(pos.is_positive());
1862
1863        let neg = Signed::<ClockTime>::from_seconds_f32(-5.0);
1864        assert!(neg.is_negative());
1865    }
1866
1867    #[test]
1868    fn try_from_seconds_f64_signed() {
1869        let pos = Signed::<ClockTime>::from_seconds_f64(5.0);
1870        assert!(pos.is_positive());
1871
1872        let neg = Signed::<ClockTime>::from_seconds_f64(-5.0);
1873        assert!(neg.is_negative());
1874    }
1875
1876    #[test]
1877    fn absdiff() {
1878        let t1 = ClockTime::from_seconds(10);
1879        let t2 = ClockTime::from_seconds(4);
1880
1881        let d = ClockTime::from_seconds(6);
1882
1883        assert_eq!(t1.absdiff(t2), d);
1884        assert_eq!(t2.absdiff(t1), d);
1885    }
1886}