srt_protocol/packet/
time.rs1use std::{
2 cmp::Ordering,
3 convert::TryInto,
4 fmt,
5 num::Wrapping,
6 ops::{Add, Div, Mul, Neg, Sub},
7 time::{Duration, Instant},
8 u32,
9};
10
11#[derive(Copy, Clone, PartialEq, Eq)]
14pub struct TimeStamp(Wrapping<u32>);
15
16#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
18pub struct TimeSpan(i32);
19
20impl TimeSpan {
21 pub const MAX: TimeSpan = TimeSpan::from_micros(i32::MAX);
22 pub const MIN: TimeSpan = TimeSpan::from_micros(i32::MIN);
23 pub const ZERO: TimeSpan = TimeSpan::from_micros(0);
24
25 pub fn from_interval(begin: Instant, end: Instant) -> Self {
26 if begin <= end {
27 Self::ZERO + (end - begin)
28 } else {
29 Self::ZERO - (begin - end)
30 }
31 }
32
33 pub const fn from_micros(us: i32) -> Self {
34 Self(us)
35 }
36
37 pub const fn from_millis(us: i32) -> Self {
38 Self(us * 1_000)
39 }
40
41 pub const fn as_micros(self) -> i32 {
42 self.0
43 }
44
45 pub const fn abs(self) -> Self {
46 Self(self.0.abs())
47 }
48
49 pub fn as_secs_f64(self) -> f64 {
50 self.0 as f64 / 1e6
51 }
52}
53
54impl TimeStamp {
55 pub const MAX: TimeStamp = TimeStamp::from_micros(u32::MAX);
56 pub const MIN: TimeStamp = TimeStamp::from_micros(u32::MIN);
57
58 pub const fn from_micros(us: u32) -> Self {
59 Self(Wrapping(us))
60 }
61
62 pub const fn as_micros(self) -> u32 {
63 (self.0).0
64 }
65}
66
67impl fmt::Debug for TimeStamp {
68 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
69 let time = (self.0).0;
70 let mins = time / 1_000_000 / 60 % 60;
71 let secs = time / 1_000_000 % 60;
72 let micros = time % 1_000_000;
73 write!(f, "{mins:02}:{secs:02}.{micros:06}")
74 }
75}
76
77impl PartialOrd<TimeStamp> for TimeStamp {
78 fn partial_cmp(&self, other: &TimeStamp) -> Option<Ordering> {
79 Some(self.cmp(other))
80 }
81}
82
83impl Ord for TimeStamp {
84 fn cmp(&self, other: &Self) -> Ordering {
85 (*self - *other).as_micros().cmp(&0)
88 }
89}
90
91impl Add<TimeSpan> for TimeStamp {
92 type Output = TimeStamp;
93
94 fn add(self, rhs: TimeSpan) -> Self::Output {
95 if rhs < TimeSpan::ZERO {
96 TimeStamp(self.0 - Wrapping(rhs.0.unsigned_abs()))
97 } else {
98 TimeStamp(self.0 + Wrapping(rhs.0 as u32))
99 }
100 }
101}
102
103impl Sub<TimeSpan> for TimeStamp {
104 type Output = TimeStamp;
105
106 fn sub(self, rhs: TimeSpan) -> Self::Output {
107 if rhs < TimeSpan::ZERO {
108 TimeStamp(self.0 + Wrapping(rhs.0.unsigned_abs()))
109 } else {
110 TimeStamp(self.0 - Wrapping(rhs.0 as u32))
111 }
112 }
113}
114
115impl Add<Duration> for TimeStamp {
116 type Output = TimeStamp;
117
118 fn add(self, rhs: Duration) -> Self::Output {
119 Self(self.0 + Wrapping(rhs.as_micros() as u32))
120 }
121}
122
123impl Sub<Duration> for TimeStamp {
124 type Output = TimeStamp;
125
126 fn sub(self, rhs: Duration) -> Self::Output {
127 Self(self.0 - Wrapping(rhs.as_micros() as u32))
128 }
129}
130
131impl Sub<TimeStamp> for TimeStamp {
132 type Output = TimeSpan;
133
134 fn sub(self, rhs: TimeStamp) -> TimeSpan {
135 let pos_sub = self.0 - rhs.0;
137 let neg_sub = rhs.0 - self.0;
138 if pos_sub < neg_sub {
139 TimeSpan(pos_sub.0 as i32)
140 } else {
141 -TimeSpan(neg_sub.0 as i32)
142 }
143 }
144}
145
146impl fmt::Debug for TimeSpan {
147 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
148 let sign = if self.0 < 0 { "-" } else { "" };
149 let mins = self.0.abs() / 1_000_000 / 60 % 60;
150 let secs = self.0.abs() / 1_000_000 % 60;
151 let micros = self.0.abs() % 1_000_000;
152 write!(f, "{sign}{mins:02}:{secs:02}.{micros:06}")
153 }
154}
155
156impl From<Duration> for TimeSpan {
157 fn from(duration: Duration) -> TimeSpan {
158 TimeSpan::from_micros(duration.as_micros().try_into().unwrap())
159 }
160}
161
162impl Neg for TimeSpan {
163 type Output = TimeSpan;
164
165 fn neg(self) -> Self::Output {
166 Self(-self.0)
167 }
168}
169
170impl Mul<i32> for TimeSpan {
171 type Output = TimeSpan;
172
173 fn mul(self, rhs: i32) -> Self::Output {
174 Self(self.0 * rhs)
175 }
176}
177
178impl Mul<TimeSpan> for i32 {
179 type Output = TimeSpan;
180
181 fn mul(self, rhs: TimeSpan) -> Self::Output {
182 TimeSpan(self * rhs.0)
183 }
184}
185
186impl Div<i32> for TimeSpan {
187 type Output = TimeSpan;
188
189 fn div(self, rhs: i32) -> Self::Output {
190 Self(self.0 / rhs)
191 }
192}
193
194impl Add<TimeSpan> for TimeSpan {
195 type Output = TimeSpan;
196
197 fn add(self, rhs: TimeSpan) -> Self::Output {
198 Self(self.0 + rhs.0)
199 }
200}
201
202impl Sub<TimeSpan> for TimeSpan {
203 type Output = TimeSpan;
204
205 fn sub(self, rhs: TimeSpan) -> Self::Output {
206 Self(self.0 - rhs.0)
207 }
208}
209
210impl Add<Duration> for TimeSpan {
211 type Output = TimeSpan;
212
213 fn add(self, rhs: Duration) -> Self::Output {
214 Self(self.0 + rhs.as_micros() as i32)
215 }
216}
217
218impl Sub<Duration> for TimeSpan {
219 type Output = TimeSpan;
220
221 fn sub(self, rhs: Duration) -> Self::Output {
222 Self(self.0 - rhs.as_micros() as i32)
223 }
224}
225
226impl Add<TimeSpan> for Duration {
227 type Output = Duration;
228
229 fn add(self, rhs: TimeSpan) -> Self::Output {
230 if rhs > TimeSpan::ZERO {
231 self + Duration::from_micros(rhs.as_micros() as u64)
232 } else {
233 self - Duration::from_micros(u64::from(rhs.as_micros().unsigned_abs()))
234 }
235 }
236}
237
238impl Sub<TimeSpan> for Duration {
239 type Output = Duration;
240
241 fn sub(self, rhs: TimeSpan) -> Self::Output {
242 self.add(-rhs)
243 }
244}
245
246impl Add<TimeSpan> for Instant {
247 type Output = Instant;
248
249 fn add(self, rhs: TimeSpan) -> Self::Output {
250 let micros = rhs.as_micros() as i64;
251 if micros > 0 {
252 self + Duration::from_micros(micros as u64)
253 } else {
254 self.checked_sub(Duration::from_micros(micros.unsigned_abs()))
255 .unwrap()
256 }
257 }
258}
259
260impl Sub<TimeSpan> for Instant {
261 type Output = Instant;
262
263 fn sub(self, rhs: TimeSpan) -> Self::Output {
264 let micros = rhs.as_micros() as i64;
265 if micros > 0 {
266 self + Duration::from_micros(micros as u64)
267 } else {
268 self.checked_sub(Duration::from_micros(micros.unsigned_abs()))
269 .unwrap()
270 }
271 }
272}
273
274#[cfg(test)]
275mod timestamp {
276 use super::*;
277
278 #[test]
279 #[allow(clippy::eq_op)]
280 fn timestamp_operators() {
281 let ts = TimeStamp::from_micros(u32::MAX >> 1);
282 let a = ts + Duration::from_micros(10);
283 let b = ts + Duration::from_micros(11);
284
285 assert_eq!(a - a, TimeSpan::ZERO);
286 assert_eq!(b - a, TimeSpan::from_micros(1));
287 assert_eq!(a - b, TimeSpan::from_micros(-1));
288 assert!(b > a);
289
290 let d = Duration::from_micros(10);
291 assert_eq!(d + TimeSpan::from_micros(1), Duration::from_micros(11));
292 assert_eq!(d + TimeSpan::from_micros(1), d - TimeSpan::from_micros(-1));
293
294 let max = TimeStamp::MIN - TimeSpan::from_micros(1);
295 let min = TimeStamp::MAX + TimeSpan::from_micros(1);
296 assert_eq!(max.as_micros(), u32::MAX);
297 assert_eq!(min.as_micros(), u32::MIN);
298 assert_eq!(max - min, TimeSpan::from_micros(-1));
299 assert_eq!(min - max, TimeSpan::from_micros(1));
300 assert!(max > a);
301 assert!(b < max);
302 assert!(min > max);
305 assert!(max < min);
306 }
307
308 #[test]
309 fn debug_fmt() {
310 assert_eq!("00:00.000001", format!("{:?}", TimeStamp::from_micros(1)));
311 assert_eq!(
312 "01:02.030040",
313 format!("{:?}", TimeStamp::from_micros(62030040))
314 );
315 }
316}