1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::{ |
4 | fmt, |
5 | io::{self, prelude::*}, |
6 | time::Duration, |
7 | }; |
8 | |
9 | use crate::{ffi, prelude::*}; |
10 | use glib::translate::*; |
11 | |
12 | use super::{ |
13 | Format, FormattedValue, FormattedValueError, FormattedValueFullRange, FormattedValueIntrinsic, |
14 | FormattedValueNoneBuilder, GenericFormattedValue, Signed, SpecificFormattedValue, |
15 | SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic, |
16 | }; |
17 | |
18 | const 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)] |
22 | pub struct TryFromFloatSecsError; |
23 | |
24 | impl 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 | |
30 | impl std::error::Error for TryFromFloatSecsError {} |
31 | |
32 | #[derive (PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] |
33 | pub struct ClockTime(u64); |
34 | |
35 | impl 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 | |
213 | impl 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 | |
385 | impl_format_value_traits!(ClockTime, Time, Time, u64); |
386 | option_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. |
391 | pub 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 | |
417 | impl 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 | |
455 | impl glib::value::ValueType for ClockTime { |
456 | type Type = Self; |
457 | } |
458 | |
459 | pub enum ClockTimeValueTypeOrNoneChecker {} |
460 | |
461 | unsafe 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 | |
478 | unsafe 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 | |
490 | impl 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 | |
511 | impl 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 | |
523 | impl 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)] |
531 | impl StaticType for ClockTime { |
532 | #[inline ] |
533 | fn static_type() -> glib::Type { |
534 | <u64 as StaticType>::static_type() |
535 | } |
536 | } |
537 | |
538 | impl 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)] |
549 | pub struct DurationError; |
550 | |
551 | impl 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 | |
557 | impl std::error::Error for DurationError {} |
558 | |
559 | impl 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 | |
577 | impl 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 | |
586 | impl_common_ops_for_newtype_uint!(ClockTime, u64); |
587 | impl_signed_div_mul!(ClockTime, u64); |
588 | impl_signed_int_into_signed!(ClockTime, u64); |
589 | |
590 | // rustdoc-stripper-ignore-next |
591 | /// Tell [`pad_clocktime`] what kind of time we're formatting |
592 | enum 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. |
617 | fn 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 |
683 | fn 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 | |
725 | fn 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 | |
748 | impl 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 | |
754 | impl fmt::Debug for ClockTime { |
755 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
756 | fmt::Display::fmt(self, f) |
757 | } |
758 | } |
759 | |
760 | pub struct DisplayableOptClockTime(Option<ClockTime>); |
761 | |
762 | impl 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 | |
768 | impl fmt::Debug for DisplayableOptClockTime { |
769 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
770 | fmt::Display::fmt(self, f) |
771 | } |
772 | } |
773 | |
774 | impl crate::utils::Displayable for Option<ClockTime> { |
775 | type DisplayImpl = DisplayableOptClockTime; |
776 | |
777 | fn display(self) -> DisplayableOptClockTime { |
778 | DisplayableOptClockTime(self) |
779 | } |
780 | } |
781 | |
782 | impl crate::utils::Displayable for ClockTime { |
783 | type DisplayImpl = ClockTime; |
784 | |
785 | fn display(self) -> ClockTime { |
786 | self |
787 | } |
788 | } |
789 | |
790 | impl 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)] |
798 | mod 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 | |