1 // Take a look at the license at the top of the repository in the LICENSE file.
2
3 use glib::translate::*;
4 use glib::StaticType;
5 use num_integer::div_rem;
6 use std::io::{self, prelude::*};
7 use std::time::Duration;
8 use std::{cmp, convert, fmt, str};
9
10 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
11 pub struct ClockTime(pub(crate) u64);
12
13 impl ClockTime {
14 pub const SECOND: ClockTime = ClockTime(1_000_000_000);
15 pub const MSECOND: ClockTime = ClockTime(1_000_000);
16 pub const USECOND: ClockTime = ClockTime(1_000);
17 pub const NSECOND: ClockTime = ClockTime(1);
18
hours(self) -> u6419 pub const fn hours(self) -> u64 {
20 self.0 / Self::SECOND.0 / 60 / 60
21 }
22
minutes(self) -> u6423 pub const fn minutes(self) -> u64 {
24 self.0 / Self::SECOND.0 / 60
25 }
26
seconds(self) -> u6427 pub const fn seconds(self) -> u64 {
28 self.0 / Self::SECOND.0
29 }
30
mseconds(self) -> u6431 pub const fn mseconds(self) -> u64 {
32 self.0 / Self::MSECOND.0
33 }
34
useconds(self) -> u6435 pub const fn useconds(self) -> u64 {
36 self.0 / Self::USECOND.0
37 }
38
nseconds(self) -> u6439 pub const fn nseconds(self) -> u64 {
40 self.0
41 }
42
from_seconds(seconds: u64) -> Self43 pub const fn from_seconds(seconds: u64) -> Self {
44 skip_assert_initialized!();
45 ClockTime(seconds * Self::SECOND.0)
46 }
47
from_mseconds(mseconds: u64) -> Self48 pub const fn from_mseconds(mseconds: u64) -> Self {
49 skip_assert_initialized!();
50 ClockTime(mseconds * Self::MSECOND.0)
51 }
52
from_useconds(useconds: u64) -> Self53 pub const fn from_useconds(useconds: u64) -> Self {
54 skip_assert_initialized!();
55 ClockTime(useconds * Self::USECOND.0)
56 }
57
from_nseconds(nseconds: u64) -> Self58 pub const fn from_nseconds(nseconds: u64) -> Self {
59 skip_assert_initialized!();
60 ClockTime(nseconds * Self::NSECOND.0)
61 }
62 }
63
64 macro_rules! option_glib_newtype_from_to {
65 ($type_:ident, $none_value:expr) => {
66 #[doc(hidden)]
67 impl IntoGlib for $type_ {
68 type GlibType = u64;
69
70 fn into_glib(self) -> u64 {
71 self.0
72 }
73 }
74
75 #[doc(hidden)]
76 impl OptionIntoGlib for $type_ {
77 const GLIB_NONE: u64 = $none_value;
78 }
79
80 #[doc(hidden)]
81 impl TryFromGlib<u64> for $type_ {
82 type Error = GlibNoneError;
83 #[inline]
84 unsafe fn try_from_glib(val: u64) -> Result<Self, GlibNoneError> {
85 skip_assert_initialized!();
86 if val == $none_value {
87 return Err(GlibNoneError);
88 }
89
90 Ok($type_(val))
91 }
92 }
93 };
94 }
95
96 option_glib_newtype_from_to!(ClockTime, ffi::GST_CLOCK_TIME_NONE);
97
98 impl glib::value::ValueType for ClockTime {
99 type Type = Self;
100 }
101
102 pub struct ClockTimeValueTypeOrNoneChecker<T>(std::marker::PhantomData<T>);
103
104 unsafe impl<T: StaticType> glib::value::ValueTypeChecker for ClockTimeValueTypeOrNoneChecker<T> {
105 type Error = glib::value::ValueTypeMismatchOrNoneError;
106
check(value: &glib::Value) -> Result<(), Self::Error>107 fn check(value: &glib::Value) -> Result<(), Self::Error> {
108 skip_assert_initialized!();
109 glib::value::GenericValueTypeChecker::<T>::check(value)?;
110
111 let gct = unsafe { glib::gobject_ffi::g_value_get_uint64(value.to_glib_none().0) };
112 if gct == ffi::GST_CLOCK_TIME_NONE {
113 return Err(glib::value::ValueTypeMismatchOrNoneError::UnexpectedNone);
114 }
115
116 Ok(())
117 }
118 }
119
120 unsafe impl<'a> glib::value::FromValue<'a> for ClockTime {
121 type Checker = ClockTimeValueTypeOrNoneChecker<Self>;
122
from_value(value: &glib::Value) -> ClockTime123 unsafe fn from_value(value: &glib::Value) -> ClockTime {
124 skip_assert_initialized!();
125 ClockTime(glib::gobject_ffi::g_value_get_uint64(
126 value.to_glib_none().0,
127 ))
128 }
129 }
130
131 impl glib::value::ToValue for ClockTime {
to_value(&self) -> glib::Value132 fn to_value(&self) -> glib::Value {
133 let mut value = glib::Value::for_value_type::<ClockTime>();
134 let gct = self.into_glib();
135 if gct == ffi::GST_CLOCK_TIME_NONE {
136 crate::gst_warning!(
137 crate::CAT_RUST,
138 "converting a defined `ClockTime` with value `ffi::GST_CLOCK_TIME_NONE` to `Value`, this is probably not what you wanted.",
139 );
140 }
141 unsafe { glib::gobject_ffi::g_value_set_uint64(value.to_glib_none_mut().0, gct) }
142 value
143 }
144
value_type(&self) -> glib::Type145 fn value_type(&self) -> glib::Type {
146 Self::static_type()
147 }
148 }
149
150 impl glib::value::ToValueOptional for ClockTime {
to_value_optional(opt: Option<&Self>) -> glib::Value151 fn to_value_optional(opt: Option<&Self>) -> glib::Value {
152 skip_assert_initialized!();
153 let mut value = glib::Value::for_value_type::<ClockTime>();
154 let inner = opt.map(|inner| inner.0).unwrap_or(ffi::GST_CLOCK_TIME_NONE);
155 unsafe { glib::gobject_ffi::g_value_set_uint64(value.to_glib_none_mut().0, inner) };
156
157 value
158 }
159 }
160
161 #[doc(hidden)]
162 impl glib::StaticType for ClockTime {
static_type() -> glib::Type163 fn static_type() -> glib::Type {
164 <u64 as glib::StaticType>::static_type()
165 }
166 }
167
168 #[derive(Debug)]
169 pub struct DurationError;
170
171 impl fmt::Display for DurationError {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result172 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
173 write!(fmt, "out of range conversion from Duration attempted")
174 }
175 }
176
177 impl std::error::Error for DurationError {}
178
179 impl convert::TryFrom<Duration> for ClockTime {
180 type Error = DurationError;
181
try_from(d: Duration) -> Result<Self, Self::Error>182 fn try_from(d: Duration) -> Result<Self, Self::Error> {
183 skip_assert_initialized!();
184
185 let nanos = d.as_nanos();
186
187 // Note: `std::u64::MAX` is `ClockTime::None`.
188 if nanos >= std::u64::MAX as u128 {
189 return Err(DurationError);
190 }
191
192 Ok(ClockTime::from_nseconds(nanos as u64))
193 }
194 }
195
196 impl convert::From<ClockTime> for Duration {
from(t: ClockTime) -> Self197 fn from(t: ClockTime) -> Self {
198 skip_assert_initialized!();
199
200 Duration::from_nanos(t.nseconds())
201 }
202 }
203
204 macro_rules! impl_common_ops_for_newtype_u64(
205 ($name:ident) => {
206 impl $name {
207 pub const ZERO: Self = Self(0);
208 pub const NONE: Option<Self> = None;
209
210 pub const fn is_zero(self) -> bool {
211 self.0 == Self::ZERO.0
212 }
213
214 #[must_use = "this returns the result of the operation, without modifying the original"]
215 #[inline]
216 // FIXME Can't use `map` in a `const fn` as of rustc 1.53.0-beta.2
217 #[allow(clippy::manual_map)]
218 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
219 match self.0.checked_add(rhs.0) {
220 Some(res) => Some(Self(res)),
221 None => None,
222 }
223 }
224
225 #[must_use = "this returns the result of the operation, without modifying the original"]
226 #[inline]
227 pub const fn saturating_add(self, rhs: Self) -> Self {
228 Self(self.0.saturating_add(rhs.0))
229 }
230
231 #[must_use = "this returns the result of the operation, without modifying the original"]
232 #[inline]
233 pub const fn wrapping_add(self, rhs: Self) -> Self {
234 Self(self.0.wrapping_add(rhs.0))
235 }
236
237 #[must_use = "this returns the result of the operation, without modifying the original"]
238 #[inline]
239 // FIXME Can't use `map` in a `const fn` as of rustc 1.53.0-beta.2
240 #[allow(clippy::manual_map)]
241 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
242 match self.0.checked_sub(rhs.0) {
243 Some(res) => Some(Self(res)),
244 None => None,
245 }
246 }
247
248 #[must_use = "this returns the result of the operation, without modifying the original"]
249 #[inline]
250 pub const fn saturating_sub(self, rhs: Self) -> Self {
251 Self(self.0.saturating_sub(rhs.0))
252 }
253
254 #[must_use = "this returns the result of the operation, without modifying the original"]
255 #[inline]
256 pub const fn wrapping_sub(self, rhs: Self) -> Self {
257 Self(self.0.wrapping_sub(rhs.0))
258 }
259 }
260 };
261 );
262
263 impl_common_ops_for_newtype_u64!(ClockTime);
264
265 /// Tell [`pad_clocktime`] what kind of time we're formatting
266 enum Sign {
267 /// An undefined time (`None`)
268 Undefined,
269
270 /// A non-negative time (zero or greater)
271 NonNegative,
272
273 // For a future ClockTimeDiff formatting
274 #[allow(dead_code)]
275 /// A negative time (below zero)
276 Negative,
277 }
278
279 // Derived from libcore `Formatter::pad_integral` (same APACHE v2 + MIT licenses)
280 //
281 // TODO: Would be useful for formatting ClockTimeDiff
282 // if it was a new type instead of an alias for i64
283 //
284 /// Performs the correct padding for a clock time which has already been
285 /// emitted into a str, as by [`write_clocktime`]. The str should *not*
286 /// contain the sign; that will be added by this method.
pad_clocktime(f: &mut fmt::Formatter<'_>, sign: Sign, buf: &str) -> fmt::Result287 fn pad_clocktime(f: &mut fmt::Formatter<'_>, sign: Sign, buf: &str) -> fmt::Result {
288 skip_assert_initialized!();
289 use self::Sign::*;
290 use std::fmt::{Alignment, Write};
291
292 // Start by determining how we're padding, gathering
293 // settings from the Formatter and the Sign
294
295 // Choose the fill character
296 let sign_aware_zero_pad = f.sign_aware_zero_pad();
297 let fill_char = match sign {
298 Undefined if sign_aware_zero_pad => '-', // Zero-padding an undefined time
299 _ if sign_aware_zero_pad => '0', // Zero-padding a valid time
300 _ => f.fill(), // Otherwise, pad with the user-chosen character
301 };
302
303 // Choose the sign character
304 let sign_plus = f.sign_plus();
305 let sign_char = match sign {
306 Undefined if sign_plus => Some(fill_char), // User requested sign, time is undefined
307 NonNegative if sign_plus => Some('+'), // User requested sign, time is zero or above
308 Negative => Some('-'), // Time is below zero
309 _ => None, // Otherwise, add no sign
310 };
311
312 // Our minimum width is the value's width, plus 1 for the sign if present
313 let width = buf.len() + sign_char.map_or(0, |_| 1);
314
315 // Subtract the minimum width from the requested width to get the padding,
316 // taking care not to allow wrapping due to underflow
317 let padding = f.width().unwrap_or(0).saturating_sub(width);
318
319 // Split the required padding into the three possible parts
320 let align = f.align().unwrap_or(Alignment::Right);
321 let (pre_padding, zero_padding, post_padding) = match align {
322 _ if sign_aware_zero_pad => (0, padding, 0), // Zero-padding: Pad between sign and value
323 Alignment::Left => (0, 0, padding), // Align left: Pad on the right side
324 Alignment::Right => (padding, 0, 0), // Align right: Pad on the left side
325
326 // Align center: Split equally between left and right side
327 // If the required padding is odd, the right side gets one more char
328 Alignment::Center => (padding / 2, 0, (padding + 1) / 2),
329 };
330
331 // And now for the actual writing
332
333 for _ in 0..pre_padding {
334 f.write_char(fill_char)?; // Left padding
335 }
336 if let Some(c) = sign_char {
337 f.write_char(c)?; // ------- Sign character
338 }
339 for _ in 0..zero_padding {
340 f.write_char(fill_char)?; // Padding between sign and value
341 }
342 f.write_str(buf)?; // ---------- Value
343 for _ in 0..post_padding {
344 f.write_char(fill_char)?; // Right padding
345 }
346
347 Ok(())
348 }
349
350 /// Writes an unpadded, signless clocktime string with the given precision
write_clocktime<W: io::Write>( mut writer: W, clocktime: Option<ClockTime>, precision: usize, ) -> io::Result<()>351 fn write_clocktime<W: io::Write>(
352 mut writer: W,
353 clocktime: Option<ClockTime>,
354 precision: usize,
355 ) -> io::Result<()> {
356 skip_assert_initialized!();
357 let precision = cmp::min(9, precision);
358
359 if let Some(ns) = clocktime.map(ClockTime::nseconds) {
360 // Split the time into parts
361 let (s, ns) = div_rem(ns, 1_000_000_000);
362 let (m, s) = div_rem(s, 60);
363 let (h, m) = div_rem(m, 60);
364
365 // Write HH:MM:SS
366 write!(writer, "{}:{:02}:{:02}", h, m, s)?;
367
368 if precision > 0 {
369 // Format the nanoseconds into a stack-allocated string
370 // The value is zero-padded so always 9 digits long
371 let mut buf = [0u8; 9];
372 write!(&mut buf[..], "{:09}", ns).unwrap();
373 let buf_str = str::from_utf8(&buf[..]).unwrap();
374
375 // Write decimal point and a prefix of the nanoseconds for more precision
376 write!(writer, ".{:.p$}", buf_str, p = precision)?;
377 }
378 } else {
379 // Undefined time
380
381 // Write HH:MM:SS, but invalid
382 write!(writer, "--:--:--")?;
383
384 if precision > 0 {
385 // Write decimal point and dashes for more precision
386 write!(writer, ".{:->p$}", "", p = precision)?;
387 }
388 }
389
390 Ok(())
391 }
392
fmt_opt_clock_time(ct: Option<ClockTime>, f: &mut fmt::Formatter) -> fmt::Result393 fn fmt_opt_clock_time(ct: Option<ClockTime>, f: &mut fmt::Formatter) -> fmt::Result {
394 skip_assert_initialized!();
395 let precision = f.precision().unwrap_or(9);
396
397 // What the maximum time (u64::MAX - 1) would format to
398 const MAX_SIZE: usize = "5124095:34:33.709551614".len();
399
400 // Write the unpadded clocktime value into a stack-allocated string
401 let mut buf = [0u8; MAX_SIZE];
402 let mut cursor = io::Cursor::new(&mut buf[..]);
403 write_clocktime(&mut cursor, ct, precision).unwrap();
404 let pos = cursor.position() as usize;
405 let buf_str = str::from_utf8(&buf[..pos]).unwrap();
406
407 let sign = if ct.is_some() {
408 Sign::NonNegative
409 } else {
410 Sign::Undefined
411 };
412
413 pad_clocktime(f, sign, buf_str)
414 }
415
416 impl fmt::Display for ClockTime {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result417 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
418 fmt_opt_clock_time(Some(*self), f)
419 }
420 }
421
422 #[derive(Debug)]
423 pub struct DisplayableOptClockTime(Option<ClockTime>);
424
425 impl fmt::Display for DisplayableOptClockTime {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result426 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
427 fmt_opt_clock_time(self.0, f)
428 }
429 }
430
431 impl crate::utils::Displayable for Option<ClockTime> {
432 type DisplayImpl = DisplayableOptClockTime;
433
display(self) -> DisplayableOptClockTime434 fn display(self) -> DisplayableOptClockTime {
435 DisplayableOptClockTime(self)
436 }
437 }
438
439 impl crate::utils::Displayable for ClockTime {
440 type DisplayImpl = ClockTime;
441
display(self) -> ClockTime442 fn display(self) -> ClockTime {
443 self
444 }
445 }
446
447 #[cfg(test)]
448 mod tests {
449 use super::*;
450
451 #[test]
opt_time_clock()452 fn opt_time_clock() {
453 let ct_1 = ClockTime(1);
454 let opt_ct_none: Option<ClockTime> = None;
455
456 assert_eq!(ct_1.into_glib(), 1);
457 assert_eq!(Some(ct_1).into_glib(), 1);
458 assert_eq!(opt_ct_none.into_glib(), ffi::GST_CLOCK_TIME_NONE);
459
460 let ct_1_from: ClockTime = unsafe { try_from_glib(1u64) }.unwrap();
461 assert_eq!(ct_1_from, ct_1);
462
463 let opt_ct_some: Option<ClockTime> = unsafe { from_glib(1u64) };
464 assert_eq!(opt_ct_some, Some(ct_1));
465
466 let opt_ct_none: Option<ClockTime> = unsafe { from_glib(ffi::GST_CLOCK_TIME_NONE) };
467 assert_eq!(opt_ct_none, None);
468 }
469
470 #[test]
471 #[allow(clippy::eq_op, clippy::op_ref)]
ops()472 fn ops() {
473 let ct_10 = 10 * ClockTime::MSECOND;
474 let ct_20 = 20 * ClockTime::MSECOND;
475 let ct_30 = 30 * ClockTime::MSECOND;
476
477 assert_eq!(ct_10 + ct_20, ct_30);
478 assert_eq!(ct_10 + &ct_20, ct_30);
479 assert_eq!(&ct_10 + &ct_20, ct_30);
480 assert_eq!(ct_30 - ct_20, ct_10);
481 assert_eq!(ct_30 - ct_30, ClockTime::ZERO);
482 assert_eq!(ct_10 * 3, ct_30);
483 assert_eq!(3 * ct_10, ct_30);
484 assert_eq!(3 * &ct_10, ct_30);
485 assert_eq!(ct_30.nseconds(), 30_000_000);
486 }
487
488 #[test]
checked_ops()489 fn checked_ops() {
490 let ct_1 = ClockTime::from_nseconds(1);
491 let ct_2 = ClockTime::from_nseconds(2);
492
493 let ct_max = ClockTime::from_nseconds(std::u64::MAX);
494
495 assert_eq!(ct_1.checked_add(ct_1), Some(ct_2));
496 assert_eq!(ct_1.checked_add(ct_1), Some(ct_2));
497 assert!(ct_max.checked_add(ct_1).is_none());
498
499 assert_eq!(ct_2.checked_sub(ct_1), Some(ct_1));
500 assert_eq!(ct_2.checked_sub(ct_1), Some(ct_1));
501 assert!(ct_1.checked_sub(ct_2).is_none());
502 }
503
504 #[test]
saturating_ops()505 fn saturating_ops() {
506 let ct_1 = ClockTime::from_nseconds(1);
507 let ct_2 = ClockTime::from_nseconds(2);
508 let ct_3 = ClockTime::from_nseconds(3);
509
510 let ct_max = ClockTime::from_nseconds(std::u64::MAX);
511
512 assert_eq!(ct_1.saturating_add(ct_2), ct_3);
513 assert_eq!(ct_1.saturating_add(ct_2), ct_3);
514 assert_eq!(ct_max.saturating_add(ct_1), ct_max);
515
516 assert_eq!(ct_3.saturating_sub(ct_2), ct_1);
517 assert_eq!(ct_3.saturating_sub(ct_2), ct_1);
518 assert!(ct_1.saturating_sub(ct_2).is_zero());
519 }
520
521 #[test]
wrapping_ops()522 fn wrapping_ops() {
523 let ct_1 = ClockTime::NSECOND;
524 let ct_2 = 2 * ClockTime::NSECOND;
525 let ct_3 = 3 * ClockTime::NSECOND;
526
527 let ct_max = ClockTime::from_nseconds(std::u64::MAX);
528
529 assert_eq!(ct_1.wrapping_add(ct_2), ct_3);
530 assert_eq!(ct_1.wrapping_add(ct_2), ct_3);
531 assert_eq!(ct_max.wrapping_add(ct_1), ClockTime::ZERO);
532
533 assert_eq!(ct_3.wrapping_sub(ct_2), ct_1);
534 assert_eq!(ct_3.wrapping_sub(ct_2), ct_1);
535 assert_eq!(ct_1.wrapping_sub(ct_2), ct_max);
536 }
537
538 #[test]
comp()539 fn comp() {
540 let ct_0 = ClockTime::ZERO;
541 let ct_2 = 2 * ClockTime::NSECOND;
542 let ct_3 = 3 * ClockTime::NSECOND;
543 let opt_ct_none: Option<ClockTime> = None;
544
545 assert!(ct_0 < ct_2);
546 assert!(Some(ct_0) < Some(ct_2));
547 assert!(ct_2 < ct_3);
548 assert!(Some(ct_2) < Some(ct_3));
549 assert!(ct_0 < ct_3);
550 assert!(Some(ct_0) < Some(ct_3));
551
552 assert!(ct_3 > ct_2);
553 assert!(Some(ct_3) > Some(ct_2));
554 assert!(ct_2 > ct_0);
555 assert!(Some(ct_2) > Some(ct_0));
556 assert!(ct_3 > ct_0);
557 assert!(Some(ct_3) > Some(ct_0));
558
559 assert!(!(opt_ct_none < None));
560 assert!(!(opt_ct_none > None));
561 // This doesn't work due to the `PartialOrd` impl on `Option<T>`
562 //assert_eq!(Some(ct_0) > opt_ct_none, false);
563 assert!(!(Some(ct_0) < opt_ct_none));
564 }
565
566 #[test]
display()567 fn display() {
568 let none = Option::<ClockTime>::None;
569 let some = Some(45_834_908_569_837 * ClockTime::NSECOND);
570 let lots = ClockTime::from_nseconds(std::u64::MAX - 1);
571
572 // Simple
573
574 assert_eq!(format!("{:.0}", DisplayableOptClockTime(none)), "--:--:--");
575 assert_eq!(
576 format!("{:.3}", DisplayableOptClockTime(none)),
577 "--:--:--.---"
578 );
579 assert_eq!(
580 format!("{}", DisplayableOptClockTime(none)),
581 "--:--:--.---------"
582 );
583
584 assert_eq!(format!("{:.0}", DisplayableOptClockTime(some)), "12:43:54");
585 assert_eq!(
586 format!("{:.3}", DisplayableOptClockTime(some)),
587 "12:43:54.908"
588 );
589 assert_eq!(
590 format!("{}", DisplayableOptClockTime(some)),
591 "12:43:54.908569837"
592 );
593
594 assert_eq!(format!("{:.0}", lots), "5124095:34:33");
595 assert_eq!(format!("{:.3}", lots), "5124095:34:33.709");
596 assert_eq!(format!("{}", lots), "5124095:34:33.709551614");
597
598 // Precision caps at 9
599 assert_eq!(
600 format!("{:.10}", DisplayableOptClockTime(none)),
601 "--:--:--.---------"
602 );
603 assert_eq!(
604 format!("{:.10}", DisplayableOptClockTime(some)),
605 "12:43:54.908569837"
606 );
607 assert_eq!(format!("{:.10}", lots), "5124095:34:33.709551614");
608
609 // Short width
610
611 assert_eq!(format!("{:4.0}", DisplayableOptClockTime(none)), "--:--:--");
612 assert_eq!(
613 format!("{:4.3}", DisplayableOptClockTime(none)),
614 "--:--:--.---"
615 );
616 assert_eq!(
617 format!("{:4}", DisplayableOptClockTime(none)),
618 "--:--:--.---------"
619 );
620
621 assert_eq!(format!("{:4.0}", DisplayableOptClockTime(some)), "12:43:54");
622 assert_eq!(
623 format!("{:4.3}", DisplayableOptClockTime(some)),
624 "12:43:54.908"
625 );
626 assert_eq!(
627 format!("{:4}", DisplayableOptClockTime(some)),
628 "12:43:54.908569837"
629 );
630
631 assert_eq!(format!("{:4.0}", lots), "5124095:34:33");
632 assert_eq!(format!("{:4.3}", lots), "5124095:34:33.709");
633 assert_eq!(format!("{:4}", lots), "5124095:34:33.709551614");
634
635 // Simple padding
636
637 assert_eq!(
638 format!("{:>9.0}", DisplayableOptClockTime(none)),
639 " --:--:--"
640 );
641 assert_eq!(
642 format!("{:<9.0}", DisplayableOptClockTime(none)),
643 "--:--:-- "
644 );
645 assert_eq!(
646 format!("{:^10.0}", DisplayableOptClockTime(none)),
647 " --:--:-- "
648 );
649 assert_eq!(
650 format!("{:>13.3}", DisplayableOptClockTime(none)),
651 " --:--:--.---"
652 );
653 assert_eq!(
654 format!("{:<13.3}", DisplayableOptClockTime(none)),
655 "--:--:--.--- "
656 );
657 assert_eq!(
658 format!("{:^14.3}", DisplayableOptClockTime(none)),
659 " --:--:--.--- "
660 );
661 assert_eq!(
662 format!("{:>19}", DisplayableOptClockTime(none)),
663 " --:--:--.---------"
664 );
665 assert_eq!(
666 format!("{:<19}", DisplayableOptClockTime(none)),
667 "--:--:--.--------- "
668 );
669 assert_eq!(
670 format!("{:^20}", DisplayableOptClockTime(none)),
671 " --:--:--.--------- "
672 );
673
674 assert_eq!(
675 format!("{:>9.0}", DisplayableOptClockTime(some)),
676 " 12:43:54"
677 );
678 assert_eq!(
679 format!("{:<9.0}", DisplayableOptClockTime(some)),
680 "12:43:54 "
681 );
682 assert_eq!(
683 format!("{:^10.0}", DisplayableOptClockTime(some)),
684 " 12:43:54 "
685 );
686 assert_eq!(
687 format!("{:>13.3}", DisplayableOptClockTime(some)),
688 " 12:43:54.908"
689 );
690 assert_eq!(
691 format!("{:<13.3}", DisplayableOptClockTime(some)),
692 "12:43:54.908 "
693 );
694 assert_eq!(
695 format!("{:^14.3}", DisplayableOptClockTime(some)),
696 " 12:43:54.908 "
697 );
698 assert_eq!(
699 format!("{:>19}", DisplayableOptClockTime(some)),
700 " 12:43:54.908569837"
701 );
702 assert_eq!(
703 format!("{:<19}", DisplayableOptClockTime(some)),
704 "12:43:54.908569837 "
705 );
706 assert_eq!(
707 format!("{:^20}", DisplayableOptClockTime(some)),
708 " 12:43:54.908569837 "
709 );
710
711 assert_eq!(format!("{:>14.0}", lots), " 5124095:34:33");
712 assert_eq!(format!("{:<14.0}", lots), "5124095:34:33 ");
713 assert_eq!(format!("{:^15.0}", lots), " 5124095:34:33 ");
714 assert_eq!(format!("{:>18.3}", lots), " 5124095:34:33.709");
715 assert_eq!(format!("{:<18.3}", lots), "5124095:34:33.709 ");
716 assert_eq!(format!("{:^19.3}", lots), " 5124095:34:33.709 ");
717 assert_eq!(format!("{:>24}", lots), " 5124095:34:33.709551614");
718 assert_eq!(format!("{:<24}", lots), "5124095:34:33.709551614 ");
719 assert_eq!(format!("{:^25}", lots), " 5124095:34:33.709551614 ");
720
721 // Padding with sign or zero-extension
722
723 assert_eq!(
724 format!("{:+11.0}", DisplayableOptClockTime(none)),
725 " --:--:--"
726 );
727 assert_eq!(
728 format!("{:011.0}", DisplayableOptClockTime(none)),
729 "-----:--:--"
730 );
731 assert_eq!(
732 format!("{:+011.0}", DisplayableOptClockTime(none)),
733 "-----:--:--"
734 );
735 assert_eq!(
736 format!("{:+15.3}", DisplayableOptClockTime(none)),
737 " --:--:--.---"
738 );
739 assert_eq!(
740 format!("{:015.3}", DisplayableOptClockTime(none)),
741 "-----:--:--.---"
742 );
743 assert_eq!(
744 format!("{:+015.3}", DisplayableOptClockTime(none)),
745 "-----:--:--.---"
746 );
747 assert_eq!(
748 format!("{:+21}", DisplayableOptClockTime(none)),
749 " --:--:--.---------"
750 );
751 assert_eq!(
752 format!("{:021}", DisplayableOptClockTime(none)),
753 "-----:--:--.---------"
754 );
755 assert_eq!(
756 format!("{:+021}", DisplayableOptClockTime(none)),
757 "-----:--:--.---------"
758 );
759
760 assert_eq!(
761 format!("{:+11.0}", DisplayableOptClockTime(some)),
762 " +12:43:54"
763 );
764 assert_eq!(
765 format!("{:011.0}", DisplayableOptClockTime(some)),
766 "00012:43:54"
767 );
768 assert_eq!(
769 format!("{:+011.0}", DisplayableOptClockTime(some)),
770 "+0012:43:54"
771 );
772 assert_eq!(
773 format!("{:+15.3}", DisplayableOptClockTime(some)),
774 " +12:43:54.908"
775 );
776 assert_eq!(
777 format!("{:015.3}", DisplayableOptClockTime(some)),
778 "00012:43:54.908"
779 );
780 assert_eq!(
781 format!("{:+015.3}", DisplayableOptClockTime(some)),
782 "+0012:43:54.908"
783 );
784 assert_eq!(
785 format!("{:+21}", DisplayableOptClockTime(some)),
786 " +12:43:54.908569837"
787 );
788 assert_eq!(
789 format!("{:021}", DisplayableOptClockTime(some)),
790 "00012:43:54.908569837"
791 );
792 assert_eq!(
793 format!("{:+021}", DisplayableOptClockTime(some)),
794 "+0012:43:54.908569837"
795 );
796
797 assert_eq!(format!("{:+16.0}", lots), " +5124095:34:33");
798 assert_eq!(format!("{:016.0}", lots), "0005124095:34:33");
799 assert_eq!(format!("{:+016.0}", lots), "+005124095:34:33");
800 assert_eq!(format!("{:+20.3}", lots), " +5124095:34:33.709");
801 assert_eq!(format!("{:020.3}", lots), "0005124095:34:33.709");
802 assert_eq!(format!("{:+020.3}", lots), "+005124095:34:33.709");
803 assert_eq!(format!("{:+26}", lots), " +5124095:34:33.709551614");
804 assert_eq!(format!("{:026}", lots), "0005124095:34:33.709551614");
805 assert_eq!(format!("{:+026}", lots), "+005124095:34:33.709551614");
806 }
807 }
808