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