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: u64 = 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: Value = glib::Value::for_value_type::<ClockTime>();
494 let gct: u64 = 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, v_uint64: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: Value = glib::Value::for_value_type::<ClockTime>();
516 let inner: u64 = opt.map(|inner| inner.0).unwrap_or(default:ffi::GST_CLOCK_TIME_NONE);
517 unsafe { glib::gobject_ffi::g_value_set_uint64(value.to_glib_none_mut().0, v_uint64: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: u128 = 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 + 1) / 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: usize = f.precision().unwrap_or(default: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: [u8; 23] = [0u8; MAX_SIZE];
734 let mut cursor: Cursor<&mut [u8]> = io::Cursor::new(&mut buf[..]);
735 write_clocktime(&mut cursor, clocktime:ct, precision).unwrap();
736 let pos: usize = cursor.position() as usize;
737 let buf_str: &str = std::str::from_utf8(&buf[..pos]).unwrap();
738
739 let sign: 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(ct: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(init:ClockTime::ZERO, |a: ClockTime, b: ClockTime| 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}
1817