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