libpulse_binding/time/
timeval.rs

1// Copyright 2018 Lyndon Brown
2//
3// This file is part of the PulseAudio Rust language binding.
4//
5// Licensed under the MIT license or the Apache license (version 2.0), at your option. You may not
6// copy, modify, or distribute this file except in compliance with said license. You can find copies
7// of these licenses either in the LICENSE-MIT and LICENSE-APACHE files, or alternatively at
8// <http://opensource.org/licenses/MIT> and <http://www.apache.org/licenses/LICENSE-2.0>
9// respectively.
10//
11// Portions of documentation are copied from the LGPL 2.1+ licensed PulseAudio C headers on a
12// fair-use basis, as discussed in the overall project readme (available in the git repository).
13
14//! Timeval.
15
16use std::cmp::Ordering;
17use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
18use std::time::Duration;
19use super::{UnixTs, MonotonicTs, MicroSeconds, op_err};
20
21#[cfg(not(windows))]
22pub(crate) type TvSecs = libc::time_t;
23#[cfg(not(windows))]
24pub(crate) type TvUsecs = libc::suseconds_t;
25#[cfg(windows)]
26pub(crate) type TvSecs = libc::c_long;
27#[cfg(windows)]
28pub(crate) type TvUsecs = libc::c_long;
29
30/// Wrapper for [`libc::timeval`], attaching various methods and trait implementations.
31#[repr(transparent)]
32#[derive(Copy, Clone)]
33pub struct Timeval(pub libc::timeval); // Warning, this must remain directly transmutable with the inner libc::timeval
34
35impl PartialEq for Timeval {
36    fn eq(&self, other: &Self) -> bool {
37        self.0.tv_sec == other.0.tv_sec && self.0.tv_usec == other.0.tv_usec
38    }
39}
40impl Eq for Timeval {}
41
42impl Ord for Timeval {
43    fn cmp(&self, other: &Self) -> Ordering {
44        match unsafe { capi::pa_timeval_cmp(&self.0, &other.0) } {
45            0 => Ordering::Equal,
46            r if r < 0 => Ordering::Less,
47            _ => Ordering::Greater,
48        }
49    }
50}
51
52impl PartialOrd for Timeval {
53    #[inline]
54    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
55        Some(self.cmp(other))
56    }
57}
58
59impl Timeval {
60    /// Bit to set in `tv_usec` attribute to mark that the `timeval` is in monotonic time.
61    const RTCLOCK_BIT: TvUsecs = 1 << 30;
62
63    /// Creates a new instance, with values provided.
64    #[inline]
65    pub const fn new(sec: TvSecs, usec: TvUsecs) -> Self {
66        Self(libc::timeval { tv_sec: sec, tv_usec: usec })
67    }
68
69    /// Creates a new instance, with value of zero.
70    #[inline]
71    pub const fn new_zero() -> Self {
72        Self::new(0, 0)
73    }
74
75    /// Calculates the difference between the two specified timeval structs.
76    #[inline]
77    pub fn diff(a: &Self, b: &Self) -> MicroSeconds {
78        MicroSeconds(unsafe { capi::pa_timeval_diff(&a.0, &b.0) })
79    }
80
81    /// Gets the time difference between now and self.
82    #[inline]
83    pub fn age(&self) -> MicroSeconds {
84        MicroSeconds(unsafe { capi::pa_timeval_age(&self.0) })
85    }
86
87    /// Sets to the specified (monotonic) value.
88    ///
89    /// The `rtclock` boolean is used for indicating support of the rtclock (monotonic time). If
90    /// `true` then the conversion from `MicroSeconds` to `Timeval` is done, and a special ‘rt’ flag
91    /// bit is set in `Timeval`’s inner `tv_usec` attribute. If `false`, then instead the timestamp
92    /// is converted to a Unix wallclock timestamp.
93    ///
94    /// Asserts that `v` is not `MicroSeconds::INVALID`.
95    pub(crate) fn set_rt(&mut self, v: MicroSeconds, rtclock: bool) -> &mut Self {
96        /* This is a copy of PA’s internal `pa_timeval_rtstore()` function */
97
98        assert_ne!(v, MicroSeconds::INVALID);
99
100        *self = v.into();
101
102        if rtclock {
103            self.0.tv_usec |= Self::RTCLOCK_BIT;
104        }
105        else {
106            self.wallclock_from_rtclock();
107        }
108        self
109    }
110
111    pub(crate) fn wallclock_from_rtclock(&mut self) -> &mut Self {
112        /* This is a copy of PA’s internal `wallclock_from_rtclock()` function */
113
114        let wc_now = (UnixTs::now()).0;
115        let rt_now = Timeval::from((MonotonicTs::now()).0);
116
117        let _ = match rt_now.cmp(self) {
118            Ordering::Less => { wc_now.add(Self::diff(self, &rt_now)) },
119            _              => { wc_now.sub(Self::diff(&rt_now, self)) },
120        };
121
122        *self = wc_now;
123        self
124    }
125
126    /// Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred,
127    /// using the inner integer’s `checked_add()` method.
128    pub fn checked_add(self, other: Self) -> Option<Self> {
129        let self_us = MicroSeconds::from(self);
130        let other_us = MicroSeconds::from(other);
131        self_us.checked_add(other_us).and_then(|i| Some(i.into()))
132    }
133
134    /// Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred,
135    /// using the inner integer’s `checked_add()` method.
136    pub fn checked_add_us(self, rhs: MicroSeconds) -> Option<Self> {
137        let self_us = MicroSeconds::from(self);
138        self_us.checked_add(rhs).and_then(|i| Some(i.into()))
139    }
140
141    /// Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred,
142    /// using the inner integer’s `checked_add()` method.
143    pub fn checked_add_duration(self, rhs: Duration) -> Option<Self> {
144        let self_us = MicroSeconds::from(self);
145        let rhs_us = MicroSeconds::try_from(rhs).ok()?;
146        self_us.checked_add(rhs_us).and_then(|i| Some(i.into()))
147    }
148
149    /// Checked integer subtraction. Computes `self - rhs`, returning `None` if overflow occurred,
150    /// using the inner integer’s `checked_sub()` method.
151    pub fn checked_sub(self, other: Self) -> Option<Self> {
152        let self_us = MicroSeconds::from(self);
153        let other_us = MicroSeconds::from(other);
154        self_us.checked_sub(other_us).and_then(|i| Some(i.into()))
155    }
156
157    /// Checked integer subtraction. Computes `self - rhs`, returning `None` if overflow occurred,
158    /// using the inner integer’s `checked_sub()` method.
159    pub fn checked_sub_us(self, rhs: MicroSeconds) -> Option<Self> {
160        let self_us = MicroSeconds::from(self);
161        self_us.checked_sub(rhs).and_then(|i| Some(i.into()))
162    }
163
164    /// Checked integer subtraction. Computes `self - rhs`, returning `None` if overflow occurred,
165    /// using the inner integer’s `checked_sub()` method.
166    pub fn checked_sub_duration(self, rhs: Duration) -> Option<Self> {
167        let self_us = MicroSeconds::from(self);
168        let rhs_us = MicroSeconds::try_from(rhs).ok()?;
169        self_us.checked_sub(rhs_us).and_then(|i| Some(i.into()))
170    }
171
172    /// Checked integer multiplication. Computes `self * rhs`, returning `None` if overflow
173    /// occurred, using the inner integer’s `checked_mul()` method.
174    pub fn checked_mul(self, rhs: u32) -> Option<Self> {
175        let self_us = MicroSeconds::from(self);
176        self_us.checked_mul(rhs).and_then(|i| Some(i.into()))
177    }
178
179    /// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`, using the
180    /// inner integer’s `checked_div()` method.
181    pub fn checked_div(self, rhs: u32) -> Option<Self> {
182        let self_us = MicroSeconds::from(self);
183        self_us.checked_div(rhs).and_then(|i| Some(i.into()))
184    }
185
186    /// Checked integer remainder. Computes `self % rhs`, returning `None` if `rhs == 0`, using the
187    /// inner integer’s `checked_rem()` method.
188    pub fn checked_rem(self, rhs: u32) -> Option<Self> {
189        let self_us = MicroSeconds::from(self);
190        self_us.checked_rem(rhs).and_then(|i| Some(i.into()))
191    }
192}
193
194impl std::fmt::Debug for Timeval {
195    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
196        write!(f, "timeval {{ tv_sec: {}, tv_usec: {} }}", self.0.tv_sec, self.0.tv_usec)
197    }
198}
199
200impl Add for Timeval {
201    type Output = Self;
202
203    #[track_caller]
204    #[inline]
205    fn add(self, other: Self) -> Self {
206        self.checked_add(other).expect(op_err::ADD)
207    }
208}
209impl AddAssign for Timeval {
210    #[track_caller]
211    #[inline]
212    fn add_assign(&mut self, rhs: Self) {
213        *self = self.add(rhs);
214    }
215}
216
217impl Sub for Timeval {
218    type Output = Self;
219
220    #[track_caller]
221    #[inline]
222    fn sub(self, other: Self) -> Self {
223        self.checked_sub(other).expect(op_err::SUB)
224    }
225}
226impl SubAssign for Timeval {
227    #[track_caller]
228    #[inline]
229    fn sub_assign(&mut self, rhs: Self) {
230        *self = self.sub(rhs);
231    }
232}
233
234////////////////////////////////////////////////////////////////////////////////////////////////////
235// Operations with `MicroSeconds`
236////////////////////////////////////////////////////////////////////////////////////////////////////
237
238impl Add<MicroSeconds> for Timeval {
239    type Output = Self;
240
241    #[track_caller]
242    #[inline]
243    fn add(self, rhs: MicroSeconds) -> Self {
244        self.checked_add_us(rhs).expect(op_err::ADD)
245    }
246}
247impl AddAssign<MicroSeconds> for Timeval {
248    #[track_caller]
249    #[inline]
250    fn add_assign(&mut self, rhs: MicroSeconds) {
251        *self = self.add(rhs);
252    }
253}
254
255impl Sub<MicroSeconds> for Timeval {
256    type Output = Self;
257
258    #[track_caller]
259    #[inline]
260    fn sub(self, rhs: MicroSeconds) -> Self {
261        self.checked_sub_us(rhs).expect(op_err::SUB)
262    }
263}
264impl SubAssign<MicroSeconds> for Timeval {
265    #[track_caller]
266    #[inline]
267    fn sub_assign(&mut self, rhs: MicroSeconds) {
268        *self = self.sub(rhs);
269    }
270}
271
272////////////////////////////////////////////////////////////////////////////////////////////////////
273// Operations with `Duration`
274////////////////////////////////////////////////////////////////////////////////////////////////////
275
276impl Add<Duration> for Timeval {
277    type Output = Self;
278
279    #[track_caller]
280    #[inline]
281    fn add(self, rhs: Duration) -> Self {
282        self.checked_add_duration(rhs).expect(op_err::ADD)
283    }
284}
285impl AddAssign<Duration> for Timeval {
286    #[track_caller]
287    #[inline]
288    fn add_assign(&mut self, rhs: Duration) {
289        *self = self.add(rhs);
290    }
291}
292
293impl Sub<Duration> for Timeval {
294    type Output = Self;
295
296    #[track_caller]
297    #[inline]
298    fn sub(self, rhs: Duration) -> Self {
299        self.checked_sub_duration(rhs).expect(op_err::SUB)
300    }
301}
302impl SubAssign<Duration> for Timeval {
303    #[track_caller]
304    #[inline]
305    fn sub_assign(&mut self, rhs: Duration) {
306        *self = self.sub(rhs);
307    }
308}
309
310////////////////////////////////////////////////////////////////////////////////////////////////////
311// Operations with primitives
312////////////////////////////////////////////////////////////////////////////////////////////////////
313
314impl Mul<u32> for Timeval {
315    type Output = Self;
316
317    #[track_caller]
318    #[inline]
319    fn mul(self, rhs: u32) -> Self {
320        self.checked_mul(rhs).expect(op_err::MUL)
321    }
322}
323impl MulAssign<u32> for Timeval {
324    #[track_caller]
325    #[inline]
326    fn mul_assign(&mut self, rhs: u32) {
327        *self = self.mul(rhs);
328    }
329}
330
331impl Div<u32> for Timeval {
332    type Output = Self;
333
334    #[track_caller]
335    #[inline]
336    fn div(self, rhs: u32) -> Self {
337        self.checked_div(rhs).expect(op_err::DIV)
338    }
339}
340impl DivAssign<u32> for Timeval {
341    #[track_caller]
342    #[inline]
343    fn div_assign(&mut self, rhs: u32) {
344        *self = self.div(rhs);
345    }
346}
347
348impl Rem<u32> for Timeval {
349    type Output = Self;
350
351    #[track_caller]
352    #[inline]
353    fn rem(self, rhs: u32) -> Self {
354        self.checked_rem(rhs).expect(op_err::REM)
355    }
356}
357impl RemAssign<u32> for Timeval {
358    #[track_caller]
359    #[inline]
360    fn rem_assign(&mut self, rhs: u32) {
361        *self = self.rem(rhs);
362    }
363}