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